static void load_subblock_array (int doall, FILE *fp_net, char *temp_buf, int num_subblocks, int bnum) { /* Parses one subblock line and, if doall is 1, loads the proper * * arrays. Each subblock line is of the format: * * subblock: <name> <ipin0> <ipin1> .. <ipin[subblock_lut_size-1]> * * <opin> <clockpin> */ int ipin, len, connect_to; char *ptr; ipin = 0; ptr = my_strtok(NULL,TOKENS,fp_net,temp_buf); if (ptr == NULL) { printf("Error in load_subblock_array on line %d of netlist file.\n", linenum); printf("Subblock name is missing.\nAborting.\n\n"); exit (1); } /* Load subblock name if this is the load pass. */ if (doall == 1) { len = strlen (ptr); subblock_inf[bnum][num_subblocks-1].name = my_chunk_malloc ((len+1) * sizeof(char), &ch_subblock_head_ptr, &ch_subblock_bytes_avail, &ch_subblock_next_avail_mem); strcpy (subblock_inf[bnum][num_subblocks-1].name, ptr); } ptr = my_strtok(NULL,TOKENS,fp_net,temp_buf); while (ptr != NULL) { /* For each subblock pin. */ if (doall == 1) { connect_to = get_pin_number (ptr); if (ipin < subblock_lut_size) { /* LUT input. */ subblock_inf[bnum][num_subblocks-1].inputs[ipin] = connect_to; } else if (ipin == subblock_lut_size) { /* LUT output. */ subblock_inf[bnum][num_subblocks-1].output = connect_to; } else if (ipin == subblock_lut_size+1) { /* Clock input. */ subblock_inf[bnum][num_subblocks-1].clock = connect_to; } } ipin++; ptr = my_strtok(NULL,TOKENS,fp_net,temp_buf); } if (ipin != subblock_lut_size + 2) { printf("Error in load_subblock_array at line %d of netlist file.\n", linenum); printf("Subblock had %d pins, expected %d.\n", ipin, subblock_lut_size+2); printf("Aborting.\n\n"); exit (1); } }
void alloc_and_load_edges_and_switches (int inode, int num_edges, t_linked_edge *edge_list_head) { /* Sets up all the edge related information for rr_node inode (num_edges, * * the edges array and the switches array). The edge_list_head points to * * a list of the num_edges edges and switches to put in the arrays. This * * linked list is freed by this routine. This routine also resets the * * rr_edge_done array for the next rr_node (i.e. set it so that no edges * * are marked as having been seen before). */ t_linked_edge *list_ptr, *next_ptr; int i, to_node; rr_node[inode].num_edges = num_edges; rr_node[inode].edges = (int *) my_chunk_malloc (num_edges * sizeof(int), &rr_mem_chunk_list_head, &chunk_bytes_avail, &chunk_next_avail_mem); rr_node[inode].switches = (short *) my_chunk_malloc (num_edges * sizeof(short), &rr_mem_chunk_list_head, &chunk_bytes_avail, &chunk_next_avail_mem); /* Load the edge and switch arrays, deallocate the linked list and reset * * the rr_edge_done flags. */ list_ptr = edge_list_head; i = 0; while (list_ptr != NULL) { to_node = list_ptr->edge; rr_node[inode].edges[i] = to_node; rr_edge_done[to_node] = FALSE; rr_node[inode].switches[i] = list_ptr->iswitch; next_ptr = list_ptr->next; /* Add to free list */ free_linked_edge_soft (list_ptr, &free_edge_list_head); list_ptr = next_ptr; i++; } }
static void alloc_and_load_net_rr_terminals (int **rr_node_indices, int nodes_per_chan) { /* Allocates and loads the net_rr_terminals data structure. For each net * * it stores the rr_node index of the SOURCE of the net and all the SINKs * * of the net. [0..num_nets-1][0..num_pins-1]. Entry [inet][pnum] stores * * the rr index corresponding to the SOURCE (opin) or SINK (ipin) of pnum. */ int inet, ipin, inode, iblk, i, j, iclass; t_rr_type rr_type; net_rr_terminals = (int **) my_malloc (num_nets * sizeof(int *)); for (inet=0;inet<num_nets;inet++) { net_rr_terminals[inet] = (int *) my_chunk_malloc (net[inet].num_pins * sizeof (int), &rr_mem_chunk_list_head, &chunk_bytes_avail, &chunk_next_avail_mem); rr_type = SOURCE; /* First pin only */ for (ipin=0;ipin<net[inet].num_pins;ipin++) { iblk = net[inet].pins[ipin]; i = block[iblk].x; j = block[iblk].y; if (clb[i][j].type == CLB) iclass = net_pin_class[inet][ipin]; else iclass = which_io_block (iblk); inode = get_rr_node_index (i, j, rr_type, iclass, nodes_per_chan, rr_node_indices); net_rr_terminals[inet][ipin] = inode; rr_type = SINK; /* All pins after first are SINKs. */ } } }
static void build_rr_pads (int **rr_node_indices, int Fc_pad, int **pads_to_tracks, int nodes_per_chan, int i, int j, int delayless_switch, t_seg_details *seg_details_x, t_seg_details *seg_details_y) { /* Load up the rr_node structures for the pads at location (i,j). I both * * fill in fields that shouldn't change during the entire routing and * * initialize fields that will change to the proper starting value. * * Empty pad locations have their type set to EMPTY. */ int s_node, p_node, ipad, iloop; int inode, num_edges; t_linked_edge *edge_list_head; /* Each pad contains both a SOURCE + OPIN, and a SINK + IPIN, since each * * pad is bidirectional. The fact that it will only be used as either an * * input or an output makes no difference. */ for (ipad=0;ipad<io_rat;ipad++) { /* For each pad at this (i,j) */ /* Do SOURCE first. */ s_node = get_rr_node_index (i, j, SOURCE, ipad, nodes_per_chan, rr_node_indices); rr_node[s_node].num_edges = 1; p_node = get_rr_node_index (i, j, OPIN, ipad, nodes_per_chan, rr_node_indices); rr_node[s_node].edges = (int *) my_chunk_malloc (sizeof(int), &rr_mem_chunk_list_head, &chunk_bytes_avail, &chunk_next_avail_mem); rr_node[s_node].edges[0] = p_node; rr_node[s_node].switches = (short *) my_chunk_malloc (sizeof(short), &rr_mem_chunk_list_head, &chunk_bytes_avail, &chunk_next_avail_mem); rr_node[s_node].switches[0] = delayless_switch; rr_node_cost_inf[s_node].base_cost = 1.; rr_node[s_node].type = SOURCE; /* Now do OPIN */ edge_list_head = NULL; num_edges = get_pad_opin_connections (pads_to_tracks, ipad, i, j, Fc_pad, seg_details_x, seg_details_y, &edge_list_head, nodes_per_chan, rr_node_indices); alloc_and_load_edges_and_switches (p_node, num_edges, edge_list_head); rr_node_cost_inf[p_node].base_cost = 1.; rr_node[p_node].type = OPIN; /* Code common to both SOURCE and OPIN. */ inode = s_node; for (iloop=1;iloop<=2;iloop++) { /* for both SOURCE or SINK and pin */ rr_node_cost_inf[inode].acc_cost = 0.; rr_node_cost_inf[inode].occ = 0; rr_node_cost_inf[inode].capacity = 1; rr_node[inode].xlow = i; rr_node[inode].xhigh = i; rr_node[inode].ylow = j; rr_node[inode].yhigh = j; rr_node[inode].R = 0.; rr_node[inode].C = 0.; rr_node[inode].ptc_num = ipad; inode = p_node; } /* Now do SINK */ s_node = get_rr_node_index (i, j, SINK, ipad, nodes_per_chan, rr_node_indices); rr_node[s_node].num_edges = 0; rr_node[s_node].edges = NULL; rr_node[s_node].switches = NULL; rr_node_cost_inf[s_node].base_cost = 0.; rr_node[s_node].type = SINK; /* Now do IPIN */ p_node = get_rr_node_index (i, j, IPIN, ipad, nodes_per_chan, rr_node_indices); rr_node[p_node].num_edges = 1; rr_node[p_node].edges = (int *) my_chunk_malloc (sizeof(int), &rr_mem_chunk_list_head, &chunk_bytes_avail, &chunk_next_avail_mem); rr_node[p_node].edges[0] = s_node; rr_node[p_node].switches = (short *) my_chunk_malloc (sizeof(short), &rr_mem_chunk_list_head, &chunk_bytes_avail, &chunk_next_avail_mem); rr_node[p_node].switches[0] = delayless_switch; #ifndef SPEC_CPU2000 rr_node_cost_inf[p_node].base_cost = 0.95; #else rr_node_cost_inf[p_node].base_cost = 1.; /* Avoid roundoff for SPEC */ #endif rr_node[p_node].type = IPIN; /* Code common to both SINK and IPIN. */ inode = s_node; for (iloop=1;iloop<=2;iloop++) { /* for both SOURCE or SINK and pin */ rr_node_cost_inf[inode].acc_cost = 0.; rr_node_cost_inf[inode].occ = 0; rr_node_cost_inf[inode].capacity = 1; rr_node[inode].xlow = i; rr_node[inode].xhigh = i; rr_node[inode].ylow = j; rr_node[inode].yhigh = j; rr_node[inode].R = 0.; rr_node[inode].C = 0.; rr_node[inode].ptc_num = ipad; inode = p_node; } } /* End for each pad. */ }
static void build_rr_clb (int **rr_node_indices, int Fc_output, int *** clb_opin_to_tracks, int nodes_per_chan, int i, int j, int delayless_switch, t_seg_details *seg_details_x, t_seg_details *seg_details_y) { /* Load up the rr_node structures for the clb at location (i,j). I both * * fill in fields that shouldn't change during the entire routing and * * initialize fields that will change to the proper starting value. */ int ipin, iclass, inode, pin_num, to_node, num_edges; t_linked_edge *edge_list_head; /* SOURCES and SINKS first. */ for (iclass=0;iclass<num_class;iclass++) { if (class_inf[iclass].type == DRIVER) { /* SOURCE */ inode = get_rr_node_index (i, j, SOURCE, iclass, nodes_per_chan, rr_node_indices); num_edges = class_inf[iclass].num_pins; rr_node[inode].num_edges = num_edges; rr_node[inode].edges = (int *) my_chunk_malloc (num_edges * sizeof (int), &rr_mem_chunk_list_head, &chunk_bytes_avail, &chunk_next_avail_mem); rr_node[inode].switches = (short *) my_chunk_malloc (num_edges * sizeof (short), &rr_mem_chunk_list_head, &chunk_bytes_avail, &chunk_next_avail_mem); for (ipin=0;ipin<class_inf[iclass].num_pins;ipin++) { pin_num = class_inf[iclass].pinlist[ipin]; to_node = get_rr_node_index (i, j, OPIN, pin_num, nodes_per_chan, rr_node_indices); rr_node[inode].edges[ipin] = to_node; rr_node[inode].switches[ipin] = delayless_switch; } rr_node_cost_inf[inode].capacity = class_inf[iclass].num_pins; rr_node_cost_inf[inode].base_cost = 1.; rr_node[inode].type = SOURCE; } else { /* SINK */ inode = get_rr_node_index (i, j, SINK, iclass, nodes_per_chan, rr_node_indices); /* Note: To allow route throughs through clbs, change the lines below to * * make an edge from the input SINK to the output SOURCE. Do for just the * * special case of INPUTS = class 0 and OUTPUTS = class 1 and see what it * * leads to. If route throughs are allowed, you may want to increase the * * base cost of OPINs and/or SOURCES so they aren't used excessively. */ rr_node[inode].num_edges = 0; rr_node[inode].edges = NULL; rr_node[inode].switches = NULL; rr_node_cost_inf[inode].capacity = class_inf[iclass].num_pins; rr_node_cost_inf[inode].base_cost = 0.; rr_node[inode].type = SINK; } /* Things common to both SOURCEs and SINKs. */ rr_node_cost_inf[inode].acc_cost = 0.; rr_node_cost_inf[inode].occ = 0; rr_node[inode].xlow = i; rr_node[inode].xhigh = i; rr_node[inode].ylow = j; rr_node[inode].yhigh = j; rr_node[inode].R = 0; rr_node[inode].C = 0; rr_node[inode].ptc_num = iclass; } /* Now do the pins. */ for (ipin=0;ipin<pins_per_clb;ipin++) { iclass = clb_pin_class[ipin]; if (class_inf[iclass].type == DRIVER) { /* OPIN */ inode = get_rr_node_index (i, j, OPIN, ipin, nodes_per_chan, rr_node_indices); edge_list_head = NULL; num_edges = get_clb_opin_connections (clb_opin_to_tracks, ipin, i, j, Fc_output, seg_details_x, seg_details_y, &edge_list_head, nodes_per_chan, rr_node_indices); alloc_and_load_edges_and_switches (inode, num_edges, edge_list_head); rr_node_cost_inf[inode].base_cost = 1.; rr_node[inode].type = OPIN; } else { /* IPIN */ inode = get_rr_node_index (i, j, IPIN, ipin, nodes_per_chan, rr_node_indices); rr_node[inode].num_edges = 1; rr_node[inode].edges = (int *) my_chunk_malloc (sizeof(int), &rr_mem_chunk_list_head, &chunk_bytes_avail, &chunk_next_avail_mem); rr_node[inode].switches = (short *) my_chunk_malloc (sizeof(short), &rr_mem_chunk_list_head, &chunk_bytes_avail, &chunk_next_avail_mem); to_node = get_rr_node_index (i, j, SINK, iclass, nodes_per_chan, rr_node_indices); rr_node[inode].edges[0] = to_node; rr_node[inode].switches[0] = delayless_switch; #ifndef SPEC_CPU2000 rr_node_cost_inf[inode].base_cost = 0.95; #else rr_node_cost_inf[inode].base_cost = 1.; /* Avoid roundoff for SPEC */ #endif rr_node[inode].type = IPIN; } /* Things that are common to both OPINs and IPINs. */ rr_node_cost_inf[inode].capacity = 1; rr_node_cost_inf[inode].acc_cost = 0.; rr_node_cost_inf[inode].occ = 0; rr_node[inode].xlow = i; rr_node[inode].xhigh = i; rr_node[inode].ylow = j; rr_node[inode].yhigh = j; rr_node[inode].C = 0; rr_node[inode].R = 0; rr_node[inode].ptc_num = ipin; } }
static void parse_name_and_pinlist (int doall, FILE *fp_net, char *buf) { /* This routine does the first part of the parsing of a block. It is * * called whenever any type of block (.clb, .input or .output) is to * * be parsed. It increments the block count (num_blocks), and checks * * that the block has a name. If doall is 1, this is the loading * * pass and it copies the name to the block data structure. Finally * * it checks that the pinlist: keyword exists. On return, my_strtok * * is set so that the next call will get the first net connected to * * this block. */ char *ptr; int len; /* Get block name. */ ptr = my_strtok(NULL,TOKENS,fp_net,buf); if (ptr == NULL) { printf("Error in parse_name_and_pinlist on line %d of netlist file.\n", linenum); printf(".clb, .input or .output line has no associated name.\n"); exit (1); } if (doall == 1) { /* Second (loading) pass, store block name */ len = strlen (ptr); block[num_blocks-1].name = my_chunk_malloc ((len + 1) * sizeof(char), NULL, &chunk_bytes_avail, &chunk_next_avail_mem); strcpy (block[num_blocks-1].name, ptr); } ptr = my_strtok (NULL,TOKENS,fp_net,buf); if (ptr != NULL) { printf("Error in parse_name_and_pinlist on line %d of netlist file.\n", linenum); printf("Extra characters at end of line.\n"); exit (1); } /* Now get pinlist from the next line. Note that a NULL return value * * from my_gets means EOF, while a NULL return from my_strtok just * * means we had a blank or comment line. */ do { ptr = my_fgets (buf, BUFSIZE, fp_net); if (ptr == NULL) { printf("Error in parse_name_and_pinlist on line %d of netlist file.\n", linenum); printf("Missing pinlist: keyword.\n"); exit (1); } ptr = my_strtok(buf,TOKENS,fp_net,buf); } while (ptr == NULL); if (strcmp (ptr, "pinlist:") != 0) { printf("Error in parse_name_and_pinlist on line %d of netlist file.\n", linenum); printf("Expected pinlist: keyword, got %s.\n",ptr); exit (1); } }
static void init_parse(int doall) { /* Allocates and initializes the data structures needed for the parse. */ int i, j, len, nindex, pin_count; int *tmp_ptr; struct s_hash_iterator hash_iterator; struct s_hash *h_ptr; if (!doall) { /* Initialization before first (counting) pass */ num_nets = 0; hash_table = alloc_hash_table (); #define INITIAL_BLOCK_STORAGE 2000 temp_block_storage = INITIAL_BLOCK_STORAGE; num_subblocks_per_block = my_malloc (INITIAL_BLOCK_STORAGE * sizeof(int)); ch_subblock_bytes_avail = 0; ch_subblock_next_avail_mem = NULL; ch_subblock_head_ptr = NULL; } /* Allocate memory for second (load) pass */ else { net = (struct s_net *) my_malloc (num_nets*sizeof(struct s_net)); block = (struct s_block *) my_malloc (num_blocks* sizeof(struct s_block)); is_global = (boolean *) my_calloc (num_nets, sizeof(boolean)); num_driver = (int *) my_malloc (num_nets * sizeof(int)); temp_num_pins = (int *) my_malloc (num_nets * sizeof(int)); for (i=0;i<num_nets;i++) { num_driver[i] = 0; net[i].num_pins = 0; } /* Allocate block pin connection storage. Some is wasted for io blocks. * * Method used below "chunks" the malloc of a bunch of small things to * * reduce the memory housekeeping overhead of malloc. */ tmp_ptr = (int *) my_malloc (pins_per_clb * num_blocks * sizeof(int)); for (i=0;i<num_blocks;i++) block[i].nets = tmp_ptr + i * pins_per_clb; /* I use my_chunk_malloc for some storage locations below. my_chunk_malloc * * avoids the 12 byte or so overhead incurred by malloc, but since I call it * * with a NULL head_ptr, it will not keep around enough information to ever * * free these data arrays. If you ever have compatibility problems on a * * non-SPARC architecture, just change all the my_chunk_malloc calls to * * my_malloc calls. */ hash_iterator = start_hash_table_iterator (); h_ptr = get_next_hash (hash_table, &hash_iterator); while (h_ptr != NULL) { nindex = h_ptr->index; pin_count = h_ptr->count; net[nindex].blocks = (int *) my_chunk_malloc(pin_count * sizeof(int), NULL, &chunk_bytes_avail, &chunk_next_avail_mem); net[nindex].blk_pin = (int *) my_chunk_malloc (pin_count * sizeof(int), NULL, &chunk_bytes_avail, &chunk_next_avail_mem); /* For avoiding assigning values beyond end of pins array. */ temp_num_pins[nindex] = pin_count; len = strlen (h_ptr->name); net[nindex].name = (char *) my_chunk_malloc ((len + 1) * sizeof(char), NULL, &chunk_bytes_avail, &chunk_next_avail_mem); strcpy (net[nindex].name, h_ptr->name); h_ptr = get_next_hash (hash_table, &hash_iterator); } /* Allocate storage for subblock info. (what's in each logic block) */ num_subblocks_per_block = (int *) my_realloc (num_subblocks_per_block, num_blocks * sizeof (int)); subblock_inf = (t_subblock **) my_malloc (num_blocks * sizeof(t_subblock *)); for (i=0;i<num_blocks;i++) { if (num_subblocks_per_block[i] == 0) subblock_inf[i] = NULL; else { subblock_inf[i] = (t_subblock *) my_chunk_malloc ( num_subblocks_per_block[i] * sizeof (t_subblock), &ch_subblock_head_ptr, &ch_subblock_bytes_avail, &ch_subblock_next_avail_mem); for (j=0;j<num_subblocks_per_block[i];j++) subblock_inf[i][j].inputs = (int *) my_chunk_malloc (subblock_lut_size * sizeof(int), &ch_subblock_head_ptr, &ch_subblock_bytes_avail, &ch_subblock_next_avail_mem); } } } /* Initializations for both passes. */ linenum = 0; num_p_inputs = 0; num_p_outputs = 0; num_clbs = 0; num_blocks = 0; num_globals = 0; }