VPR-6.0
|
00001 #include <math.h> 00002 #include <stdio.h> 00003 #include <assert.h> 00004 #include <time.h> 00005 #include "util.h" 00006 #include "vpr_types.h" 00007 #include "vpr_utils.h" 00008 #include "globals.h" 00009 #include "mst.h" 00010 #include "route_export.h" 00011 #include "route_common.h" 00012 #include "route_tree_timing.h" 00013 #include "route_timing.h" 00014 #include "route_breadth_first.h" 00015 #include "route_directed_search.h" 00016 #include "place_and_route.h" 00017 #include "rr_graph.h" 00018 #include "read_xml_arch_file.h" 00019 00020 /***************** Variables shared only by route modules *******************/ 00021 00022 t_rr_node_route_inf *rr_node_route_inf = NULL; /**< [0..num_rr_nodes-1] */ 00023 00024 struct s_bb *route_bb = NULL; /**< [0..num_nets-1]. Limits area in which each 00025 * net must be routed. */ 00026 00027 00028 /**************** Static variables local to route_common.c ******************/ 00029 00030 static struct s_heap **heap; /**< Indexed from [1..heap_size] */ 00031 static int heap_size; /**< Number of slots in the heap array */ 00032 static int heap_tail; /**< Index of first unused slot in the heap array */ 00033 00034 /** For managing my own list of currently free heap data structures. */ 00035 static struct s_heap *heap_free_head = NULL; 00036 00037 /** For managing my own list of currently free trace data structures. */ 00038 static struct s_trace *trace_free_head = NULL; 00039 00040 #ifdef DEBUG 00041 static int num_trace_allocated = 0; /**< To watch for memory leaks. */ 00042 static int num_heap_allocated = 0; 00043 static int num_linked_f_pointer_allocated = 0; 00044 #endif 00045 00046 static struct s_linked_f_pointer *rr_modified_head = NULL; 00047 static struct s_linked_f_pointer *linked_f_pointer_free_head = NULL; 00048 00049 00050 00051 /* The numbering relation between the channels and clbs is: * 00052 * * 00053 * | IO | chan_ | CLB | chan_ | CLB | * 00054 * |grid[0][2]| y[0][2] | grid[1][2] | y[1][2] | grid[2][2]| * 00055 * +-------- + +------------+ +-----------+ * 00056 * } capacity in * 00057 * No channel chan_x[1][1] chan_x[2][1] } chan_width * 00058 * } _x[1] * 00059 * +---------+ +------------+ +-----------+ * 00060 * | | chan_ | | chan_ | | * 00061 * | IO | y[0][1] | CLB | y[1][1] | CLB | * 00062 * |grid[0][1]| | grid[1][1] | | grid[2][1] | * 00063 * | | | | | | * 00064 * +---------+ +------------+ +-----------+ * 00065 * } capacity in * 00066 * chan_x[1][0] chan_x[2][0] } chan_width * 00067 * } _x[0] * 00068 * +------------+ +-----------+ * 00069 * No | | No | | * 00070 * Channel | IO | Channel | IO | * 00071 * | grid[1][0] | | grid[2][0] | * 00072 * | | | | * 00073 * +------------+ +-----------+ * 00074 * * 00075 * {=======} {=======} * 00076 * Capacity in Capacity in * 00077 * chan_width_y[0] chan_width_y[1] * 00078 * */ 00079 00080 00081 /******************** Subroutines local to route_common.c *******************/ 00082 00083 static void free_trace_data(struct s_trace *tptr); 00084 static void load_route_bb(int bb_factor); 00085 00086 static struct s_trace *alloc_trace_data(void); 00087 static void add_to_heap(struct s_heap *hptr); 00088 static struct s_heap *alloc_heap_data(void); 00089 static struct s_linked_f_pointer *alloc_linked_f_pointer(void); 00090 00091 static t_ivec **alloc_and_load_clb_opins_used_locally(); 00092 static void adjust_one_rr_occ_and_pcost(int inode, 00093 int add_or_sub, 00094 float pres_fac); 00095 00096 00097 00098 /************************** Subroutine definitions ***************************/ 00099 00100 /** This routing frees any routing currently held in best routing, 00101 * then copies over the current routing (held in trace_head), and 00102 * finally sets trace_head and trace_tail to all NULLs so that the 00103 * connection to the saved routing is broken. This is necessary so 00104 * that the next iteration of the router does not free the saved 00105 * routing elements. Also saves any data about locally used clb_opins, 00106 * since this is also part of the routing. 00107 */ 00108 void 00109 save_routing(struct s_trace **best_routing, 00110 t_ivec ** clb_opins_used_locally, 00111 t_ivec ** saved_clb_opins_used_locally) 00112 { 00113 00114 int inet, iblk, iclass, ipin, num_local_opins; 00115 struct s_trace *tptr, *tempptr; 00116 t_type_ptr type; 00117 00118 for(inet = 0; inet < num_nets; inet++) 00119 { 00120 00121 /* Free any previously saved routing. It is no longer best. */ 00122 tptr = best_routing[inet]; 00123 while(tptr != NULL) 00124 { 00125 tempptr = tptr->next; 00126 free_trace_data(tptr); 00127 tptr = tempptr; 00128 } 00129 00130 /* Save a pointer to the current routing in best_routing. */ 00131 best_routing[inet] = trace_head[inet]; 00132 00133 /* Set the current (working) routing to NULL so the current trace * 00134 * elements won't be reused by the memory allocator. */ 00135 00136 trace_head[inet] = NULL; 00137 trace_tail[inet] = NULL; 00138 } 00139 00140 /* Save which OPINs are locally used. */ 00141 00142 for(iblk = 0; iblk < num_blocks; iblk++) 00143 { 00144 type = block[iblk].type; 00145 for(iclass = 0; iclass < type->num_class; iclass++) 00146 { 00147 num_local_opins = 00148 clb_opins_used_locally[iblk][iclass].nelem; 00149 for(ipin = 0; ipin < num_local_opins; ipin++) 00150 { 00151 saved_clb_opins_used_locally[iblk][iclass]. 00152 list[ipin] = 00153 clb_opins_used_locally[iblk][iclass]. 00154 list[ipin]; 00155 } 00156 } 00157 } 00158 } 00159 00160 /** Deallocates any current routing in trace_head, and replaces it with 00161 * the routing in best_routing. Best_routing is set to NULL to show that 00162 * it no longer points to a valid routing. NOTE: trace_tail is not 00163 * restored -- it is set to all NULLs since it is only used in 00164 * update_traceback. If you need trace_tail restored, modify this 00165 * routine. Also restores the locally used opin data. 00166 */ 00167 void 00168 restore_routing(struct s_trace **best_routing, 00169 t_ivec ** clb_opins_used_locally, 00170 t_ivec ** saved_clb_opins_used_locally) 00171 { 00172 00173 int inet, iblk, ipin, iclass, num_local_opins; 00174 t_type_ptr type; 00175 00176 for(inet = 0; inet < num_nets; inet++) 00177 { 00178 00179 /* Free any current routing. */ 00180 free_traceback(inet); 00181 00182 /* Set the current routing to the saved one. */ 00183 trace_head[inet] = best_routing[inet]; 00184 best_routing[inet] = NULL; /* No stored routing. */ 00185 } 00186 00187 /* Save which OPINs are locally used. */ 00188 00189 for(iblk = 0; iblk < num_blocks; iblk++) 00190 { 00191 type = block[iblk].type; 00192 for(iclass = 0; iclass < type->num_class; iclass++) 00193 { 00194 num_local_opins = 00195 clb_opins_used_locally[iblk][iclass].nelem; 00196 for(ipin = 0; ipin < num_local_opins; ipin++) 00197 { 00198 clb_opins_used_locally[iblk][iclass].list[ipin] = 00199 saved_clb_opins_used_locally[iblk][iclass]. 00200 list[ipin]; 00201 } 00202 } 00203 00204 } 00205 } 00206 00207 /** This routine finds a "magic cookie" for the routing and prints it. 00208 * Use this number as a routing serial number to ensure that programming 00209 * changes do not break the router. 00210 */ 00211 void 00212 get_serial_num(void) 00213 { 00214 00215 int inet, serial_num, inode; 00216 struct s_trace *tptr; 00217 00218 serial_num = 0; 00219 00220 for(inet = 0; inet < num_nets; inet++) 00221 { 00222 00223 /* Global nets will have null trace_heads (never routed) so they * 00224 * are not included in the serial number calculation. */ 00225 00226 tptr = trace_head[inet]; 00227 while(tptr != NULL) 00228 { 00229 inode = tptr->index; 00230 serial_num += 00231 (inet + 1) * (rr_node[inode].xlow * (nx + 1) - 00232 rr_node[inode].yhigh); 00233 00234 serial_num -= rr_node[inode].ptc_num * (inet + 1) * 10; 00235 00236 serial_num -= rr_node[inode].type * (inet + 1) * 100; 00237 serial_num %= 2000000000; /* Prevent overflow */ 00238 tptr = tptr->next; 00239 } 00240 } 00241 printf("Serial number (magic cookie) for the routing is: %d\n", 00242 serial_num); 00243 } 00244 00245 /** Attempts a routing via an iterated maze router algorithm. Width_fac 00246 * specifies the relative width of the channels, while the members of 00247 * router_opts determine the value of the costs assigned to routing 00248 * resource node, etc. det_routing_arch describes the detailed routing 00249 * architecture (connection and switch boxes) of the FPGA; it is used 00250 * only if a DETAILED routing has been selected. 00251 */ 00252 boolean 00253 try_route(int width_fac, 00254 struct s_router_opts router_opts, 00255 struct s_det_routing_arch det_routing_arch, 00256 t_segment_inf * segment_inf, 00257 t_timing_inf timing_inf, 00258 float **net_slack, 00259 float **net_delay, 00260 t_chan_width_dist chan_width_dist, 00261 t_ivec ** clb_opins_used_locally, 00262 t_mst_edge ** mst, 00263 boolean * Fc_clipped) 00264 { 00265 00266 int tmp; 00267 clock_t begin, end; 00268 boolean success; 00269 t_graph_type graph_type; 00270 00271 if(router_opts.route_type == GLOBAL) { 00272 graph_type = GRAPH_GLOBAL; 00273 } else { 00274 graph_type = (det_routing_arch.directionality == 00275 BI_DIRECTIONAL ? GRAPH_BIDIR : GRAPH_UNIDIR); 00276 } 00277 00278 /* Set the channel widths */ 00279 00280 init_chan(width_fac, chan_width_dist); 00281 00282 /* Free any old routing graph, if one exists. */ 00283 00284 free_rr_graph(); 00285 00286 begin = clock(); 00287 00288 00289 /* Set up the routing resource graph defined by this FPGA architecture. */ 00290 00291 build_rr_graph(graph_type, 00292 num_types, type_descriptors, nx, ny, grid, 00293 chan_width_x[0], NULL, 00294 det_routing_arch.switch_block_type, det_routing_arch.Fs, 00295 det_routing_arch.num_segment, det_routing_arch.num_switch, segment_inf, 00296 det_routing_arch.global_route_switch, 00297 det_routing_arch.delayless_switch, timing_inf, 00298 det_routing_arch.wire_to_ipin_switch, 00299 router_opts.base_cost_type, &tmp); 00300 00301 end = clock(); 00302 #ifdef CLOCKS_PER_SEC 00303 printf("build rr_graph took %g seconds\n", (float)(end - begin) / CLOCKS_PER_SEC); 00304 #else 00305 printf("build rr_graph took %g seconds\n", (float)(end - begin) / CLK_PER_SEC); 00306 #endif 00307 00308 00309 /* Allocate and load some additional rr_graph information needed only by * 00310 * the router. */ 00311 00312 alloc_and_load_rr_node_route_structs(); 00313 00314 init_route_structs(router_opts.bb_factor); 00315 00316 if(router_opts.router_algorithm == BREADTH_FIRST) 00317 { 00318 printf("Confirming Router Algorithm: BREADTH_FIRST.\n"); 00319 success = 00320 try_breadth_first_route(router_opts, clb_opins_used_locally, 00321 width_fac); 00322 } 00323 else if(router_opts.router_algorithm == TIMING_DRIVEN) 00324 { /* TIMING_DRIVEN route */ 00325 printf("Confirming Router Algorithm: TIMING_DRIVEN.\n"); 00326 assert(router_opts.route_type != GLOBAL); 00327 success = 00328 try_timing_driven_route(router_opts, net_slack, net_delay, 00329 clb_opins_used_locally); 00330 } 00331 else 00332 { /* Directed Search Routability Driven */ 00333 printf("Confirming Router Algorithm: DIRECTED_SEARCH.\n"); 00334 success = 00335 try_directed_search_route(router_opts, clb_opins_used_locally, 00336 width_fac, mst); 00337 } 00338 00339 free_rr_node_route_structs(); 00340 00341 return (success); 00342 } 00343 00344 /** This routine checks to see if this is a resource-feasible routing. 00345 * That is, are all rr_node capacity limitations respected? It assumes 00346 * that the occupancy arrays are up to date when it is called. 00347 */ 00348 boolean 00349 feasible_routing(void) 00350 { 00351 00352 int inode; 00353 00354 for(inode = 0; inode < num_rr_nodes; inode++) { 00355 if(rr_node[inode].occ > rr_node[inode].capacity) { 00356 return (FALSE); 00357 } 00358 } 00359 00360 return (TRUE); 00361 } 00362 00363 /** This routine updates the occupancy and pres_cost of the rr_nodes that are 00364 * affected by the portion of the routing of one net that starts at 00365 * route_segment_start. If route_segment_start is trace_head[inet], the 00366 * cost of all the nodes in the routing of net inet are updated. If 00367 * add_or_sub is -1 the net (or net portion) is ripped up, if it is 1 the 00368 * net is added to the routing. The size of pres_fac determines how severly 00369 * oversubscribed rr_nodes are penalized. 00370 */ 00371 void 00372 pathfinder_update_one_cost(struct s_trace *route_segment_start, 00373 int add_or_sub, 00374 float pres_fac) 00375 { 00376 00377 struct s_trace *tptr; 00378 int inode, occ, capacity; 00379 00380 tptr = route_segment_start; 00381 if(tptr == NULL) /* No routing yet. */ 00382 return; 00383 00384 for(;;) 00385 { 00386 inode = tptr->index; 00387 00388 occ = rr_node[inode].occ + add_or_sub; 00389 capacity = rr_node[inode].capacity; 00390 00391 rr_node[inode].occ = occ; 00392 00393 /* pres_cost is Pn in the Pathfinder paper. I set my pres_cost according to * 00394 * the overuse that would result from having ONE MORE net use this routing * 00395 * node. */ 00396 00397 if(occ < capacity) 00398 { 00399 rr_node_route_inf[inode].pres_cost = 1.; 00400 } 00401 else 00402 { 00403 rr_node_route_inf[inode].pres_cost = 00404 1. + (occ + 1 - capacity) * pres_fac; 00405 } 00406 00407 if(rr_node[inode].type == SINK) 00408 { 00409 tptr = tptr->next; /* Skip next segment. */ 00410 if(tptr == NULL) 00411 break; 00412 } 00413 00414 tptr = tptr->next; 00415 00416 } /* End while loop -- did an entire traceback. */ 00417 } 00418 00419 /** This routine recomputes the pres_cost and acc_cost of each routing 00420 * resource for the pathfinder algorithm after all nets have been routed. 00421 * It updates the accumulated cost to by adding in the number of extra 00422 * signals sharing a resource right now (i.e. after each complete iteration) 00423 * times acc_fac. It also updates pres_cost, since pres_fac may have 00424 * changed. THIS ROUTINE ASSUMES THE OCCUPANCY VALUES IN RR_NODE ARE UP TO 00425 * DATE. 00426 */ 00427 void 00428 pathfinder_update_cost(float pres_fac, 00429 float acc_fac) 00430 { 00431 00432 int inode, occ, capacity; 00433 00434 for(inode = 0; inode < num_rr_nodes; inode++) 00435 { 00436 occ = rr_node[inode].occ; 00437 capacity = rr_node[inode].capacity; 00438 00439 if(occ > capacity) 00440 { 00441 rr_node_route_inf[inode].acc_cost += 00442 (occ - capacity) * acc_fac; 00443 rr_node_route_inf[inode].pres_cost = 00444 1. + (occ + 1 - capacity) * pres_fac; 00445 } 00446 00447 /* If occ == capacity, we don't need to increase acc_cost, but a change * 00448 * in pres_fac could have made it necessary to recompute the cost anyway. */ 00449 00450 else if(occ == capacity) 00451 { 00452 rr_node_route_inf[inode].pres_cost = 1. + pres_fac; 00453 } 00454 } 00455 } 00456 00457 /** Call this before you route any nets. It frees any old traceback and 00458 * sets the list of rr_nodes touched to empty. 00459 */ 00460 void 00461 init_route_structs(int bb_factor) 00462 { 00463 00464 int i; 00465 00466 for(i = 0; i < num_nets; i++) 00467 free_traceback(i); 00468 00469 load_route_bb(bb_factor); 00470 00471 /* Check that things that should have been emptied after the last routing * 00472 * really were. */ 00473 00474 if(rr_modified_head != NULL) 00475 { 00476 printf 00477 ("Error in init_route_structs. List of modified rr nodes is \n" 00478 "not empty.\n"); 00479 exit(1); 00480 } 00481 00482 if(heap_tail != 1) 00483 { 00484 printf("Error in init_route_structs. Heap is not empty.\n"); 00485 exit(1); 00486 } 00487 } 00488 00489 /** This routine adds the most recently finished wire segment to the 00490 * traceback linked list. The first connection starts with the net SOURCE 00491 * and begins at the structure pointed to by trace_head[inet]. Each 00492 * connection ends with a SINK. After each SINK, the next connection 00493 * begins (if the net has more than 2 pins). The first element after the 00494 * SINK gives the routing node on a previous piece of the routing, which is 00495 * the link from the existing net to this new piece of the net. 00496 * In each traceback I start at the end of a path and trace back through 00497 * its predecessors to the beginning. I have stored information on the 00498 * predecesser of each node to make traceback easy -- this sacrificies some 00499 * memory for easier code maintenance. This routine returns a pointer to 00500 * the first "new" node in the traceback (node not previously in trace). 00501 */ 00502 struct s_trace * 00503 update_traceback(struct s_heap *hptr, 00504 int inet) 00505 { 00506 00507 struct s_trace *tptr, *prevptr, *temptail, *ret_ptr; 00508 int inode; 00509 short iedge; 00510 00511 #ifdef DEBUG 00512 t_rr_type rr_type; 00513 #endif 00514 00515 inode = hptr->index; 00516 00517 #ifdef DEBUG 00518 rr_type = rr_node[inode].type; 00519 if(rr_type != SINK) 00520 { 00521 printf("Error in update_traceback. Expected type = SINK (%d).\n", 00522 SINK); 00523 printf("Got type = %d while tracing back net %d.\n", rr_type, 00524 inet); 00525 exit(1); 00526 } 00527 #endif 00528 00529 tptr = alloc_trace_data(); /* SINK on the end of the connection */ 00530 tptr->index = inode; 00531 tptr->iswitch = OPEN; 00532 tptr->next = NULL; 00533 temptail = tptr; /* This will become the new tail at the end */ 00534 /* of the routine. */ 00535 00536 /* Now do it's predecessor. */ 00537 00538 inode = hptr->u.prev_node; 00539 iedge = hptr->prev_edge; 00540 00541 while(inode != NO_PREVIOUS) 00542 { 00543 prevptr = alloc_trace_data(); 00544 prevptr->index = inode; 00545 prevptr->iswitch = rr_node[inode].switches[iedge]; 00546 prevptr->next = tptr; 00547 tptr = prevptr; 00548 00549 iedge = rr_node_route_inf[inode].prev_edge; 00550 inode = rr_node_route_inf[inode].prev_node; 00551 } 00552 00553 if(trace_tail[inet] != NULL) 00554 { 00555 trace_tail[inet]->next = tptr; /* Traceback ends with tptr */ 00556 ret_ptr = tptr->next; /* First new segment. */ 00557 } 00558 else 00559 { /* This was the first "chunk" of the net's routing */ 00560 trace_head[inet] = tptr; 00561 ret_ptr = tptr; /* Whole traceback is new. */ 00562 } 00563 00564 trace_tail[inet] = temptail; 00565 return (ret_ptr); 00566 } 00567 00568 /** The routine sets the path_cost to HUGE_FLOAT for all channel segments 00569 * touched by previous routing phases. 00570 */ 00571 void 00572 reset_path_costs(void) 00573 { 00574 00575 struct s_linked_f_pointer *mod_ptr; 00576 00577 #ifdef DEBUG 00578 int num_mod_ptrs; 00579 #endif 00580 00581 /* The traversal method below is slightly painful to make it faster. */ 00582 00583 if(rr_modified_head != NULL) 00584 { 00585 mod_ptr = rr_modified_head; 00586 00587 #ifdef DEBUG 00588 num_mod_ptrs = 1; 00589 #endif 00590 00591 while(mod_ptr->next != NULL) 00592 { 00593 *(mod_ptr->fptr) = HUGE_FLOAT; 00594 mod_ptr = mod_ptr->next; 00595 #ifdef DEBUG 00596 num_mod_ptrs++; 00597 #endif 00598 } 00599 *(mod_ptr->fptr) = HUGE_FLOAT; /* Do last one. */ 00600 00601 /* Reset the modified list and put all the elements back in the free * 00602 * list. */ 00603 00604 mod_ptr->next = linked_f_pointer_free_head; 00605 linked_f_pointer_free_head = rr_modified_head; 00606 rr_modified_head = NULL; 00607 00608 #ifdef DEBUG 00609 num_linked_f_pointer_allocated -= num_mod_ptrs; 00610 #endif 00611 } 00612 } 00613 00614 00615 /** Returns the *congestion* cost of using this rr_node. */ 00616 float 00617 get_rr_cong_cost(int inode) 00618 { 00619 short cost_index; 00620 float cost; 00621 00622 cost_index = rr_node[inode].cost_index; 00623 cost = rr_indexed_data[cost_index].base_cost * 00624 rr_node_route_inf[inode].acc_cost * 00625 rr_node_route_inf[inode].pres_cost; 00626 return (cost); 00627 } 00628 00629 /** Mark all the SINKs of this net as targets by setting their target flags 00630 * to the number of times the net must connect to each SINK. Note that 00631 * this number can occassionally be greater than 1 -- think of connecting 00632 * the same net to two inputs of an and-gate (and-gate inputs are logically 00633 * equivalent, so both will connect to the same SINK). 00634 */ 00635 void 00636 mark_ends(int inet) 00637 { 00638 00639 int ipin, inode; 00640 00641 for(ipin = 1; ipin <= clb_net[inet].num_sinks; ipin++) 00642 { 00643 inode = net_rr_terminals[inet][ipin]; 00644 rr_node_route_inf[inode].target_flag++; 00645 } 00646 } 00647 00648 /** Puts an rr_node on the heap, if the new cost given is lower than the 00649 * current path_cost to this channel segment. The index of its predecessor 00650 * is stored to make traceback easy. The index of the edge used to get 00651 * from its predecessor to it is also stored to make timing analysis, etc. 00652 * easy. The backward_path_cost and R_upstream values are used only by the 00653 * timing-driven router -- the breadth-first router ignores them. 00654 */ 00655 void 00656 node_to_heap(int inode, 00657 float cost, 00658 int prev_node, 00659 int prev_edge, 00660 float backward_path_cost, 00661 float R_upstream) 00662 { 00663 00664 struct s_heap *hptr; 00665 00666 if(cost >= rr_node_route_inf[inode].path_cost) 00667 return; 00668 00669 hptr = alloc_heap_data(); 00670 hptr->index = inode; 00671 hptr->cost = cost; 00672 hptr->u.prev_node = prev_node; 00673 hptr->prev_edge = prev_edge; 00674 hptr->backward_path_cost = backward_path_cost; 00675 hptr->R_upstream = R_upstream; 00676 add_to_heap(hptr); 00677 } 00678 00679 /** Puts the entire traceback (old routing) for this net on the free list 00680 * and sets the trace_head pointers etc. for the net to NULL. 00681 */ 00682 void 00683 free_traceback(int inet) 00684 { 00685 00686 struct s_trace *tptr, *tempptr; 00687 00688 tptr = trace_head[inet]; 00689 00690 while(tptr != NULL) 00691 { 00692 tempptr = tptr->next; 00693 free_trace_data(tptr); 00694 tptr = tempptr; 00695 } 00696 00697 trace_head[inet] = NULL; 00698 trace_tail[inet] = NULL; 00699 } 00700 00701 00702 /** Allocates the data structures needed for routing. */ 00703 t_ivec ** 00704 alloc_route_structs() 00705 { 00706 t_ivec **clb_opins_used_locally; 00707 00708 alloc_route_static_structs(); 00709 clb_opins_used_locally = 00710 alloc_and_load_clb_opins_used_locally(); 00711 00712 return (clb_opins_used_locally); 00713 } 00714 00715 void alloc_route_static_structs() { 00716 trace_head = (struct s_trace **)my_calloc(num_nets, 00717 sizeof(struct s_trace *)); 00718 trace_tail = (struct s_trace **)my_malloc(num_nets * 00719 sizeof(struct s_trace *)); 00720 00721 heap_size = nx * ny; 00722 heap = (struct s_heap **)my_malloc(heap_size * sizeof(struct s_heap *)); 00723 heap--; /* heap stores from [1..heap_size] */ 00724 heap_tail = 1; 00725 00726 route_bb = (struct s_bb *)my_malloc(num_nets * sizeof(struct s_bb)); 00727 } 00728 00729 /** Allocates data structures into which the key routing data can be saved, 00730 * allowing the routing to be recovered later (e.g. after a another routing 00731 * is attempted). 00732 */ 00733 struct s_trace ** 00734 alloc_saved_routing(t_ivec ** clb_opins_used_locally, 00735 t_ivec *** saved_clb_opins_used_locally_ptr) 00736 { 00737 00738 struct s_trace **best_routing; 00739 t_ivec **saved_clb_opins_used_locally; 00740 int iblk, iclass, num_local_opins; 00741 t_type_ptr type; 00742 00743 best_routing = (struct s_trace **)my_calloc(num_nets, 00744 sizeof(struct s_trace *)); 00745 00746 saved_clb_opins_used_locally = 00747 (t_ivec **) my_malloc(num_blocks * sizeof(t_ivec *)); 00748 00749 for(iblk = 0; iblk < num_blocks; iblk++) 00750 { 00751 type = block[iblk].type; 00752 saved_clb_opins_used_locally[iblk] = 00753 (t_ivec *) my_malloc(type->num_class * sizeof(t_ivec)); 00754 for(iclass = 0; iclass < type->num_class; iclass++) 00755 { 00756 num_local_opins = 00757 clb_opins_used_locally[iblk][iclass].nelem; 00758 saved_clb_opins_used_locally[iblk][iclass].nelem = 00759 num_local_opins; 00760 00761 if(num_local_opins == 0) 00762 { 00763 saved_clb_opins_used_locally[iblk][iclass].list = 00764 NULL; 00765 } 00766 else 00767 { 00768 saved_clb_opins_used_locally[iblk][iclass].list = 00769 (int *)my_malloc(num_local_opins * 00770 sizeof(int)); 00771 } 00772 } 00773 } 00774 00775 *saved_clb_opins_used_locally_ptr = saved_clb_opins_used_locally; 00776 return (best_routing); 00777 } 00778 00779 /* TODO: probably now this whole function can be removed, must check correctness of routing so I will leave everything as is 00780 until I can golden check the routing before I do this massive code rewrite and performance optimizations */ 00781 /** Allocates and loads the data needed to make the router reserve some CLB 00782 * output pins for connections made locally within a CLB (if the netlist 00783 * specifies that this is necessary). 00784 */ 00785 static t_ivec ** 00786 alloc_and_load_clb_opins_used_locally() 00787 { 00788 00789 t_ivec **clb_opins_used_locally; 00790 int iblk, clb_pin, iclass, num_local_opins; 00791 int class_low, class_high; 00792 t_type_ptr type; 00793 00794 clb_opins_used_locally = 00795 (t_ivec **) my_malloc(num_blocks * sizeof(t_ivec *)); 00796 00797 for(iblk = 0; iblk < num_blocks; iblk++) 00798 { 00799 type = block[iblk].type; 00800 get_class_range_for_block(iblk, &class_low, &class_high); 00801 clb_opins_used_locally[iblk] = 00802 (t_ivec *) my_malloc(type->num_class * sizeof(t_ivec)); 00803 for(iclass = 0; iclass < type->num_class; iclass++) 00804 clb_opins_used_locally[iblk][iclass].nelem = 0; 00805 00806 for(clb_pin = 0; clb_pin < type->num_pins; clb_pin++) 00807 { 00808 /* Subblock output used only locally, but must connect to a CLB OPIN? */ 00809 if(block[iblk].nets[clb_pin] != OPEN 00810 && clb_net[block[iblk].nets[clb_pin]].num_sinks == 0) 00811 { 00812 iclass = type->pin_class[clb_pin]; 00813 /* Check to make sure class is in same range as that assigned to block */ 00814 assert(iclass >= class_low 00815 && iclass <= class_high); 00816 clb_opins_used_locally[iblk][iclass].nelem++; 00817 } 00818 } 00819 00820 for(iclass = 0; iclass < type->num_class; iclass++) 00821 { 00822 num_local_opins = 00823 clb_opins_used_locally[iblk][iclass].nelem; 00824 00825 if(num_local_opins == 0) 00826 clb_opins_used_locally[iblk][iclass].list = NULL; 00827 else 00828 clb_opins_used_locally[iblk][iclass].list = 00829 (int *)my_malloc(num_local_opins * sizeof(int)); 00830 } 00831 } 00832 00833 return (clb_opins_used_locally); 00834 } 00835 00836 /** the trace lists are only freed after use by the timing-driven placer. 00837 * Do not free them after use by the router, since stats, and draw 00838 * routines use the trace values 00839 */ 00840 void 00841 free_trace_structs(void) 00842 { 00843 int i; 00844 00845 for(i = 0; i < num_nets; i++) 00846 free_traceback(i); 00847 00848 free(trace_head); 00849 free(trace_tail); 00850 trace_head = NULL; 00851 trace_tail = NULL; 00852 } 00853 00854 /** Frees the temporary storage needed only during the routing. The 00855 * final routing result is not freed. 00856 */ 00857 void 00858 free_route_structs(t_ivec ** clb_opins_used_locally) 00859 { 00860 00861 int i; 00862 00863 free(heap + 1); 00864 free(route_bb); 00865 00866 heap = NULL; /* Defensive coding: crash hard if I use these. */ 00867 route_bb = NULL; 00868 00869 if(clb_opins_used_locally != NULL) { 00870 for(i = 0; i < num_blocks; i++) 00871 { 00872 free_ivec_vector(clb_opins_used_locally[i], 0, 00873 block[i].type->num_class - 1); 00874 } 00875 free(clb_opins_used_locally); 00876 } 00877 00878 /* NB: Should use my chunk_malloc for tptr, hptr, and mod_ptr structures. * 00879 * I could free everything except the tptrs at the end then. */ 00880 00881 } 00882 00883 00884 /** Frees the data structures needed to save a routing. */ 00885 void 00886 free_saved_routing(struct s_trace **best_routing, 00887 t_ivec ** saved_clb_opins_used_locally) 00888 { 00889 int i; 00890 00891 free(best_routing); 00892 for(i = 0; i < num_blocks; i++) 00893 { 00894 free_ivec_vector(saved_clb_opins_used_locally[i], 0, 00895 block[i].type->num_class - 1); 00896 } 00897 free(saved_clb_opins_used_locally); 00898 } 00899 00900 /** Allocates some extra information about each rr_node that is used only 00901 * during routing. 00902 */ 00903 void 00904 alloc_and_load_rr_node_route_structs(void) 00905 { 00906 00907 int inode; 00908 00909 if(rr_node_route_inf != NULL) 00910 { 00911 printf("Error in alloc_and_load_rr_node_route_structs: \n" 00912 "old rr_node_route_inf array exists.\n"); 00913 exit(1); 00914 } 00915 00916 rr_node_route_inf = my_malloc(num_rr_nodes * sizeof(t_rr_node_route_inf)); 00917 00918 for(inode = 0; inode < num_rr_nodes; inode++) 00919 { 00920 rr_node_route_inf[inode].prev_node = NO_PREVIOUS; 00921 rr_node_route_inf[inode].prev_edge = NO_PREVIOUS; 00922 rr_node_route_inf[inode].pres_cost = 1.; 00923 rr_node_route_inf[inode].acc_cost = 1.; 00924 rr_node_route_inf[inode].path_cost = HUGE_FLOAT; 00925 rr_node_route_inf[inode].target_flag = 0; 00926 } 00927 } 00928 00929 /** Allocates some extra information about each rr_node that is used only 00930 * during routing. 00931 */ 00932 void 00933 reset_rr_node_route_structs(void) 00934 { 00935 int inode; 00936 00937 assert(rr_node_route_inf != NULL); 00938 00939 for(inode = 0; inode < num_rr_nodes; inode++) 00940 { 00941 rr_node_route_inf[inode].prev_node = NO_PREVIOUS; 00942 rr_node_route_inf[inode].prev_edge = NO_PREVIOUS; 00943 rr_node_route_inf[inode].pres_cost = 1.; 00944 rr_node_route_inf[inode].acc_cost = 1.; 00945 rr_node_route_inf[inode].path_cost = HUGE_FLOAT; 00946 rr_node_route_inf[inode].target_flag = 0; 00947 } 00948 } 00949 00950 /** Frees the extra information about each rr_node that is needed only 00951 * during routing. 00952 */ 00953 void 00954 free_rr_node_route_structs(void) 00955 { 00956 00957 free(rr_node_route_inf); 00958 rr_node_route_inf = NULL; /* Mark as free */ 00959 } 00960 00961 /* RESEARCH TODO: Bounding box heuristic needs to be redone for heterogeneous blocks */ 00962 /** This routine loads the bounding box arrays used to limit the space 00963 * searched by the maze router when routing each net. The search is 00964 * limited to channels contained with the net bounding box expanded 00965 * by bb_factor channels on each side. For example, if bb_factor is 00966 * 0, the maze router must route each net within its bounding box. 00967 * If bb_factor = nx, the maze router will search every channel in 00968 * the FPGA if necessary. The bounding boxes returned by this routine 00969 * are different from the ones used by the placer in that they are 00970 * clipped to lie within (0,0) and (nx+1,ny+1) rather than (1,1) and 00971 * (nx,ny). 00972 */ 00973 static void 00974 load_route_bb(int bb_factor) 00975 { 00976 00977 int k, xmax, ymax, xmin, ymin, x, y, inet; 00978 00979 for(inet = 0; inet < num_nets; inet++) 00980 { 00981 x = block[clb_net[inet].node_block[0]].x; 00982 y = block[clb_net[inet].node_block[0]].y + block[clb_net[inet].node_block[0]].type->pin_height[clb_net[inet].node_block_pin[0]]; 00983 00984 xmin = x; 00985 ymin = y; 00986 xmax = x; 00987 ymax = y; 00988 00989 for(k = 1; k <= clb_net[inet].num_sinks; k++) 00990 { 00991 x = block[clb_net[inet].node_block[k]].x; 00992 y = block[clb_net[inet].node_block[k]].y + block[clb_net[inet].node_block[k]].type->pin_height[clb_net[inet].node_block_pin[k]]; 00993 00994 if(x < xmin) 00995 { 00996 xmin = x; 00997 } 00998 else if(x > xmax) 00999 { 01000 xmax = x; 01001 } 01002 01003 if(y < ymin) 01004 { 01005 ymin = y; 01006 } 01007 else if(y > ymax) 01008 { 01009 ymax = y; 01010 } 01011 } 01012 01013 /* Want the channels on all 4 sides to be usuable, even if bb_factor = 0. */ 01014 01015 xmin -= 1; 01016 ymin -= 1; 01017 01018 /* Expand the net bounding box by bb_factor, then clip to the physical * 01019 * chip area. */ 01020 01021 route_bb[inet].xmin = max(xmin - bb_factor, 0); 01022 route_bb[inet].xmax = min(xmax + bb_factor, nx + 1); 01023 route_bb[inet].ymin = max(ymin - bb_factor, 0); 01024 route_bb[inet].ymax = min(ymax + bb_factor, ny + 1); 01025 } 01026 } 01027 01028 /** This routine adds the floating point pointer (fptr) into a 01029 * linked list that indicates all the pathcosts that have been 01030 * modified thus far. 01031 */ 01032 void 01033 add_to_mod_list(float *fptr) 01034 { 01035 01036 struct s_linked_f_pointer *mod_ptr; 01037 01038 mod_ptr = alloc_linked_f_pointer(); 01039 01040 /* Add this element to the start of the modified list. */ 01041 01042 mod_ptr->next = rr_modified_head; 01043 mod_ptr->fptr = fptr; 01044 rr_modified_head = mod_ptr; 01045 } 01046 01047 01048 /** Adds an item to the heap, expanding the heap if necessary. */ 01049 static void 01050 add_to_heap(struct s_heap *hptr) 01051 { 01052 int ito, ifrom; 01053 struct s_heap *temp_ptr; 01054 01055 if(heap_tail > heap_size) 01056 { /* Heap is full */ 01057 heap_size *= 2; 01058 heap = my_realloc((void *)(heap + 1), heap_size * 01059 sizeof(struct s_heap *)); 01060 heap--; /* heap goes from [1..heap_size] */ 01061 } 01062 01063 heap[heap_tail] = hptr; 01064 ifrom = heap_tail; 01065 ito = ifrom / 2; 01066 heap_tail++; 01067 01068 while((ito >= 1) && (heap[ifrom]->cost < heap[ito]->cost)) 01069 { 01070 temp_ptr = heap[ito]; 01071 heap[ito] = heap[ifrom]; 01072 heap[ifrom] = temp_ptr; 01073 ifrom = ito; 01074 ito = ifrom / 2; 01075 } 01076 } 01077 01078 /** WMF: peeking accessor :) */ 01079 boolean 01080 is_empty_heap(void) 01081 { 01082 return (heap_tail == 1); 01083 } 01084 01085 /** Returns a pointer to the smallest element on the heap, or NULL if the 01086 * heap is empty. Invalid (index == OPEN) entries on the heap are never 01087 * returned -- they are just skipped over. 01088 */ 01089 struct s_heap * 01090 get_heap_head(void) 01091 { 01092 01093 int ito, ifrom; 01094 struct s_heap *heap_head, *temp_ptr; 01095 01096 do 01097 { 01098 if(heap_tail == 1) 01099 { /* Empty heap. */ 01100 printf("Empty heap occurred in get_heap_head.\n"); 01101 printf 01102 ("Some blocks are impossible to connect in this architecture.\n"); 01103 return (NULL); 01104 } 01105 01106 heap_head = heap[1]; /* Smallest element. */ 01107 01108 /* Now fix up the heap */ 01109 01110 heap_tail--; 01111 heap[1] = heap[heap_tail]; 01112 ifrom = 1; 01113 ito = 2 * ifrom; 01114 01115 while(ito < heap_tail) 01116 { 01117 if(heap[ito + 1]->cost < heap[ito]->cost) 01118 ito++; 01119 if(heap[ito]->cost > heap[ifrom]->cost) 01120 break; 01121 temp_ptr = heap[ito]; 01122 heap[ito] = heap[ifrom]; 01123 heap[ifrom] = temp_ptr; 01124 ifrom = ito; 01125 ito = 2 * ifrom; 01126 } 01127 01128 } 01129 while(heap_head->index == OPEN); /* Get another one if invalid entry. */ 01130 01131 return (heap_head); 01132 } 01133 01134 01135 void 01136 empty_heap(void) 01137 { 01138 01139 int i; 01140 01141 for(i = 1; i < heap_tail; i++) 01142 free_heap_data(heap[i]); 01143 01144 heap_tail = 1; 01145 } 01146 01147 #define NCHUNK 200 /**< # of various structs malloced at a time. */ 01148 01149 01150 static struct s_heap * 01151 alloc_heap_data(void) 01152 { 01153 01154 int i; 01155 struct s_heap *temp_ptr; 01156 01157 if(heap_free_head == NULL) 01158 { /* No elements on the free list */ 01159 heap_free_head = (struct s_heap *)my_malloc(NCHUNK * 01160 sizeof(struct 01161 s_heap)); 01162 01163 /* If I want to free this memory, I have to store the original pointer * 01164 * somewhere. Not worthwhile right now -- if you need more memory * 01165 * for post-routing stages, look into it. */ 01166 01167 for(i = 0; i < NCHUNK - 1; i++) 01168 (heap_free_head + i)->u.next = heap_free_head + i + 1; 01169 (heap_free_head + NCHUNK - 1)->u.next = NULL; 01170 } 01171 01172 temp_ptr = heap_free_head; 01173 heap_free_head = heap_free_head->u.next; 01174 #ifdef DEBUG 01175 num_heap_allocated++; 01176 #endif 01177 return (temp_ptr); 01178 } 01179 01180 01181 void 01182 free_heap_data(struct s_heap *hptr) 01183 { 01184 01185 hptr->u.next = heap_free_head; 01186 heap_free_head = hptr; 01187 #ifdef DEBUG 01188 num_heap_allocated--; 01189 #endif 01190 } 01191 01192 /** Marks all the heap entries consisting of sink_node, where it was reached 01193 * via ipin_node, as invalid (OPEN). Used only by the breadth_first router 01194 * and even then only in rare circumstances. 01195 */ 01196 void 01197 invalidate_heap_entries(int sink_node, 01198 int ipin_node) 01199 { 01200 int i; 01201 01202 for(i = 1; i < heap_tail; i++) 01203 { 01204 if(heap[i]->index == sink_node 01205 && heap[i]->u.prev_node == ipin_node) 01206 heap[i]->index = OPEN; /* Invalid. */ 01207 } 01208 } 01209 01210 01211 static struct s_trace * 01212 alloc_trace_data(void) 01213 { 01214 01215 int i; 01216 struct s_trace *temp_ptr; 01217 01218 if(trace_free_head == NULL) 01219 { /* No elements on the free list */ 01220 trace_free_head = (struct s_trace *)my_malloc(NCHUNK * 01221 sizeof(struct 01222 s_trace)); 01223 01224 /* If I want to free this memory, I have to store the original pointer * 01225 * somewhere. Not worthwhile right now -- if you need more memory * 01226 * for post-routing stages, look into it. */ 01227 01228 for(i = 0; i < NCHUNK - 1; i++) 01229 (trace_free_head + i)->next = trace_free_head + i + 1; 01230 (trace_free_head + NCHUNK - 1)->next = NULL; 01231 } 01232 temp_ptr = trace_free_head; 01233 trace_free_head = trace_free_head->next; 01234 #ifdef DEBUG 01235 num_trace_allocated++; 01236 #endif 01237 return (temp_ptr); 01238 } 01239 01240 01241 /** Puts the traceback structure pointed to by tptr on the free list. */ 01242 static void 01243 free_trace_data(struct s_trace *tptr) 01244 { 01245 tptr->next = trace_free_head; 01246 trace_free_head = tptr; 01247 #ifdef DEBUG 01248 num_trace_allocated--; 01249 #endif 01250 } 01251 01252 /** This routine returns a linked list element with a float pointer as 01253 * the node data. 01254 */ 01255 static struct s_linked_f_pointer * 01256 alloc_linked_f_pointer(void) 01257 { 01258 01259 int i; 01260 struct s_linked_f_pointer *temp_ptr; 01261 01262 if(linked_f_pointer_free_head == NULL) 01263 { 01264 /* No elements on the free list */ 01265 linked_f_pointer_free_head = (struct s_linked_f_pointer *) 01266 my_malloc(NCHUNK * sizeof(struct s_linked_f_pointer)); 01267 01268 /* If I want to free this memory, I have to store the original pointer * 01269 * somewhere. Not worthwhile right now -- if you need more memory * 01270 * for post-routing stages, look into it. */ 01271 01272 for(i = 0; i < NCHUNK - 1; i++) 01273 { 01274 (linked_f_pointer_free_head + i)->next = 01275 linked_f_pointer_free_head + i + 1; 01276 } 01277 (linked_f_pointer_free_head + NCHUNK - 1)->next = NULL; 01278 } 01279 01280 temp_ptr = linked_f_pointer_free_head; 01281 linked_f_pointer_free_head = linked_f_pointer_free_head->next; 01282 01283 #ifdef DEBUG 01284 num_linked_f_pointer_allocated++; 01285 #endif 01286 01287 return (temp_ptr); 01288 } 01289 01290 01291 /** Prints out the routing to file route_file. */ 01292 void 01293 print_route(char *route_file) 01294 { 01295 int inet, inode, ipin, bnum, ilow, jlow, node_block_pin, iclass; 01296 t_rr_type rr_type; 01297 struct s_trace *tptr; 01298 char *name_type[] = 01299 { "SOURCE", "SINK", "IPIN", "OPIN", "CHANX", "CHANY", "INTRA_CLUSTER_EDGE" }; 01300 FILE *fp; 01301 01302 fp = fopen(route_file, "w"); 01303 01304 fprintf(fp, "Array size: %d x %d logic blocks.\n", nx, ny); 01305 fprintf(fp, "\nRouting:"); 01306 for(inet = 0; inet < num_nets; inet++) 01307 { 01308 if(clb_net[inet].is_global == FALSE) 01309 { 01310 if(clb_net[inet].num_sinks == FALSE) 01311 { 01312 fprintf(fp, "\n\nNet %d (%s)\n\n", inet, clb_net[inet].name); 01313 fprintf(fp, "\n\n Used in local cluster only, reserved one CLB pin\n\n"); 01314 } else { 01315 fprintf(fp, "\n\nNet %d (%s)\n\n", inet, clb_net[inet].name); 01316 tptr = trace_head[inet]; 01317 01318 while(tptr != NULL) 01319 { 01320 inode = tptr->index; 01321 rr_type = rr_node[inode].type; 01322 ilow = rr_node[inode].xlow; 01323 jlow = rr_node[inode].ylow; 01324 01325 fprintf(fp, "%6s (%d,%d) ", name_type[rr_type], 01326 ilow, jlow); 01327 01328 if((ilow != rr_node[inode].xhigh) || (jlow != 01329 rr_node 01330 [inode]. 01331 yhigh)) 01332 fprintf(fp, "to (%d,%d) ", 01333 rr_node[inode].xhigh, 01334 rr_node[inode].yhigh); 01335 01336 switch (rr_type) 01337 { 01338 01339 case IPIN: 01340 case OPIN: 01341 if(grid[ilow][jlow].type == IO_TYPE) 01342 { 01343 fprintf(fp, " Pad: "); 01344 } 01345 else 01346 { /* IO Pad. */ 01347 fprintf(fp, " Pin: "); 01348 } 01349 break; 01350 01351 case CHANX: 01352 case CHANY: 01353 fprintf(fp, " Track: "); 01354 break; 01355 01356 case SOURCE: 01357 case SINK: 01358 if(grid[ilow][jlow].type == IO_TYPE) 01359 { 01360 fprintf(fp, " Pad: "); 01361 } 01362 else 01363 { /* IO Pad. */ 01364 fprintf(fp, " Class: "); 01365 } 01366 break; 01367 01368 default: 01369 printf 01370 ("Error in print_route: Unexpected traceback element " 01371 "type: %d (%s).\n", rr_type, 01372 name_type[rr_type]); 01373 exit(1); 01374 break; 01375 } 01376 01377 fprintf(fp, "%d ", rr_node[inode].ptc_num); 01378 01379 /* Uncomment line below if you're debugging and want to see the switch types * 01380 * used in the routing. */ 01381 /* fprintf (fp, "Switch: %d", tptr->iswitch); */ 01382 01383 fprintf(fp, "\n"); 01384 01385 tptr = tptr->next; 01386 } 01387 } 01388 } 01389 01390 else 01391 { /* Global net. Never routed. */ 01392 fprintf(fp, "\n\nNet %d (%s): global net connecting:\n\n", 01393 inet, clb_net[inet].name); 01394 01395 for(ipin = 0; ipin <= clb_net[inet].num_sinks; ipin++) 01396 { 01397 bnum = clb_net[inet].node_block[ipin]; 01398 01399 node_block_pin = clb_net[inet].node_block_pin[ipin]; 01400 iclass = 01401 block[bnum].type->pin_class[node_block_pin]; 01402 01403 fprintf(fp, 01404 "Block %s (#%d) at (%d, %d), Pin class %d.\n", 01405 block[bnum].name, bnum, block[bnum].x, 01406 block[bnum].y, iclass); 01407 } 01408 } 01409 } 01410 01411 fclose(fp); 01412 01413 #ifdef CREATE_ECHO_FILES 01414 fp = my_fopen("mem.echo", "w", 0); 01415 fprintf(fp, "\nNum_heap_allocated: %d Num_trace_allocated: %d\n", 01416 num_heap_allocated, num_trace_allocated); 01417 fprintf(fp, "Num_linked_f_pointer_allocated: %d\n", 01418 num_linked_f_pointer_allocated); 01419 fclose(fp); 01420 #endif /* CREATE_ECHO_FILES */ 01421 01422 } 01423 01424 /* TODO: check if this is still necessary for speed */ 01425 void 01426 reserve_locally_used_opins(float pres_fac, 01427 boolean rip_up_local_opins, 01428 t_ivec ** clb_opins_used_locally) 01429 { 01430 01431 /* In the past, this function implicitly allowed LUT duplication when there are free LUTs. 01432 This was especially important for logical equivalence; however, now that we have a very general 01433 logic cluster, it does not make sense to allow LUT duplication implicitly. we'll need to look into how we want to handle this case 01434 01435 */ 01436 01437 int iblk, num_local_opin, inode, from_node, iconn, num_edges, to_node; 01438 int iclass, ipin; 01439 float cost; 01440 struct s_heap *heap_head_ptr; 01441 t_type_ptr type; 01442 01443 if(rip_up_local_opins) 01444 { 01445 for(iblk = 0; iblk < num_blocks; iblk++) 01446 { 01447 type = block[iblk].type; 01448 for(iclass = 0; iclass < type->num_class; iclass++) 01449 { 01450 num_local_opin = 01451 clb_opins_used_locally[iblk][iclass].nelem; 01452 /* Always 0 for pads and for RECEIVER (IPIN) classes */ 01453 for(ipin = 0; ipin < num_local_opin; ipin++) 01454 { 01455 inode = 01456 clb_opins_used_locally[iblk][iclass]. 01457 list[ipin]; 01458 adjust_one_rr_occ_and_pcost(inode, -1, 01459 pres_fac); 01460 } 01461 } 01462 } 01463 } 01464 01465 for(iblk = 0; iblk < num_blocks; iblk++) 01466 { 01467 type = block[iblk].type; 01468 for(iclass = 0; iclass < type->num_class; iclass++) 01469 { 01470 num_local_opin = 01471 clb_opins_used_locally[iblk][iclass].nelem; 01472 /* Always 0 for pads and for RECEIVER (IPIN) classes */ 01473 01474 if(num_local_opin != 0) 01475 { /* Have to reserve (use) some OPINs */ 01476 from_node = rr_blk_source[iblk][iclass]; 01477 num_edges = rr_node[from_node].num_edges; 01478 for(iconn = 0; iconn < num_edges; iconn++) 01479 { 01480 to_node = rr_node[from_node].edges[iconn]; 01481 cost = get_rr_cong_cost(to_node); 01482 node_to_heap(to_node, cost, OPEN, OPEN, 01483 0., 0.); 01484 } 01485 01486 for(ipin = 0; ipin < num_local_opin; ipin++) 01487 { 01488 heap_head_ptr = get_heap_head(); 01489 inode = heap_head_ptr->index; 01490 adjust_one_rr_occ_and_pcost(inode, 1, 01491 pres_fac); 01492 clb_opins_used_locally[iblk][iclass]. 01493 list[ipin] = inode; 01494 free_heap_data(heap_head_ptr); 01495 } 01496 01497 empty_heap(); 01498 } 01499 } 01500 } 01501 } 01502 01503 /** Increments or decrements (depending on add_or_sub) the occupancy of 01504 * one rr_node, and adjusts the present cost of that node appropriately. 01505 */ 01506 static void 01507 adjust_one_rr_occ_and_pcost(int inode, 01508 int add_or_sub, 01509 float pres_fac) 01510 { 01511 01512 int occ, capacity; 01513 01514 occ = rr_node[inode].occ + add_or_sub; 01515 capacity = rr_node[inode].capacity; 01516 rr_node[inode].occ = occ; 01517 01518 if(occ < capacity) 01519 { 01520 rr_node_route_inf[inode].pres_cost = 1.; 01521 } 01522 else 01523 { 01524 rr_node_route_inf[inode].pres_cost = 1. + (occ + 1 - capacity) * 01525 pres_fac; 01526 } 01527 }