VPR-6.0
|
00001 #include <assert.h> 00002 #include <stdio.h> 00003 #include "util.h" 00004 #include "vpr_types.h" 00005 #include "globals.h" 00006 #include "mst.h" 00007 #include "route_export.h" 00008 #include "check_route.h" 00009 #include "rr_graph.h" 00010 #include "check_rr_graph.h" 00011 #include "read_xml_arch_file.h" 00012 00013 00014 /******************** Subroutines local to this module **********************/ 00015 static void check_node_and_range(int inode, 00016 enum e_route_type route_type); 00017 static void check_source(int inode, 00018 int inet); 00019 static void check_sink(int inode, 00020 int inet, 00021 boolean * pin_done); 00022 static void check_switch(struct s_trace *tptr, 00023 int num_switch); 00024 static boolean check_adjacent(int from_node, 00025 int to_node); 00026 static int pin_and_chan_adjacent(int pin_node, 00027 int chan_node); 00028 static int chanx_chany_adjacent(int chanx_node, 00029 int chany_node); 00030 static void reset_flags(int inet, 00031 boolean * connected_to_route); 00032 static void recompute_occupancy_from_scratch(t_ivec ** clb_opins_used_locally); 00033 static void check_locally_used_clb_opins(t_ivec ** clb_opins_used_locally, 00034 enum e_route_type route_type); 00035 00036 /************************ Subroutine definitions ****************************/ 00037 00038 /** This routine checks that a routing: (1) Describes a properly 00039 * connected path for each net, (2) this path connects all the 00040 * pins spanned by that net, and (3) that no routing resources are 00041 * oversubscribed (the occupancy of everything is recomputed from 00042 * scratch). 00043 */ 00044 void 00045 check_route(enum e_route_type route_type, 00046 int num_switch, 00047 t_ivec ** clb_opins_used_locally) 00048 { 00049 00050 int inet, ipin, max_pins, inode, prev_node; 00051 boolean valid, connects; 00052 boolean *connected_to_route; /* [0 .. num_rr_nodes-1] */ 00053 struct s_trace *tptr; 00054 boolean *pin_done; 00055 00056 printf("\nChecking to ensure routing is legal ...\n"); 00057 00058 /* Recompute the occupancy from scratch and check for overuse of routing * 00059 * resources. This was already checked in order to determine that this * 00060 * is a successful routing, but I want to double check it here. */ 00061 00062 recompute_occupancy_from_scratch(clb_opins_used_locally); 00063 valid = feasible_routing(); 00064 if(valid == FALSE) 00065 { 00066 printf 00067 ("Error in check_route -- routing resources are overused.\n"); 00068 exit(1); 00069 } 00070 00071 check_locally_used_clb_opins(clb_opins_used_locally, route_type); 00072 00073 connected_to_route = (boolean *) my_calloc(num_rr_nodes, sizeof(boolean)); 00074 00075 max_pins = 0; 00076 for(inet = 0; inet < num_nets; inet++) 00077 max_pins = max(max_pins, (clb_net[inet].num_sinks + 1)); 00078 00079 pin_done = (boolean *) my_malloc(max_pins * sizeof(boolean)); 00080 00081 /* Now check that all nets are indeed connected. */ 00082 00083 for(inet = 0; inet < num_nets; inet++) 00084 { 00085 00086 if(clb_net[inet].is_global || clb_net[inet].num_sinks == 0) /* Skip global nets. */ 00087 continue; 00088 00089 for(ipin = 0; ipin < (clb_net[inet].num_sinks + 1); ipin++) 00090 pin_done[ipin] = FALSE; 00091 00092 /* Check the SOURCE of the net. */ 00093 00094 tptr = trace_head[inet]; 00095 if(tptr == NULL) 00096 { 00097 printf("Error in check_route: net %d has no routing.\n", 00098 inet); 00099 exit(1); 00100 } 00101 00102 inode = tptr->index; 00103 check_node_and_range(inode, route_type); 00104 check_switch(tptr, num_switch); 00105 connected_to_route[inode] = TRUE; /* Mark as in path. */ 00106 00107 check_source(inode, inet); 00108 pin_done[0] = TRUE; 00109 00110 prev_node = inode; 00111 tptr = tptr->next; 00112 00113 /* Check the rest of the net */ 00114 00115 while(tptr != NULL) 00116 { 00117 inode = tptr->index; 00118 check_node_and_range(inode, route_type); 00119 check_switch(tptr, num_switch); 00120 00121 if(rr_node[prev_node].type == SINK) 00122 { 00123 if(connected_to_route[inode] == FALSE) 00124 { 00125 printf 00126 ("Error in check_route. Node %d does not link " 00127 "into the existing routing for net %d.\n", 00128 inode, inet); 00129 exit(1); 00130 } 00131 } 00132 00133 else 00134 { 00135 connects = check_adjacent(prev_node, inode); 00136 if(!connects) 00137 { 00138 printf 00139 ("Error in check_route while checking net %d.\n", 00140 inet); 00141 printf 00142 ("Non-adjacent segments in traceback.\n"); 00143 exit(1); 00144 } 00145 00146 if(connected_to_route[inode] 00147 && rr_node[inode].type != SINK) 00148 { 00149 00150 /* Note: Can get multiple connections to the same logically-equivalent * 00151 * SINK in some logic blocks. */ 00152 00153 printf 00154 ("Error in check_route: net %d routing is not a tree.\n", 00155 inet); 00156 exit(1); 00157 } 00158 00159 connected_to_route[inode] = TRUE; /* Mark as in path. */ 00160 00161 if(rr_node[inode].type == SINK) 00162 check_sink(inode, inet, pin_done); 00163 00164 } /* End of prev_node type != SINK */ 00165 prev_node = inode; 00166 tptr = tptr->next; 00167 } /* End while */ 00168 00169 if(rr_node[prev_node].type != SINK) 00170 { 00171 printf("Error in check_route. Net %d does not end\n", 00172 inet); 00173 printf("with a SINK.\n"); 00174 exit(1); 00175 } 00176 00177 for(ipin = 0; ipin < (clb_net[inet].num_sinks + 1); ipin++) 00178 { 00179 if(pin_done[ipin] == FALSE) 00180 { 00181 printf 00182 ("Error in check_route. Net %d does not \n", 00183 inet); 00184 printf("connect to pin %d.\n", ipin); 00185 exit(1); 00186 } 00187 } 00188 00189 reset_flags(inet, connected_to_route); 00190 00191 } /* End for each net */ 00192 00193 free(pin_done); 00194 free(connected_to_route); 00195 printf("Completed routing consistency check successfully.\n\n"); 00196 } 00197 00198 /** Checks that this SINK node is one of the terminals of inet, and marks 00199 * the appropriate pin as being reached. 00200 */ 00201 static void 00202 check_sink(int inode, 00203 int inet, 00204 boolean * pin_done) 00205 { 00206 00207 int i, j, ipin, ifound, ptc_num, bnum, iclass, node_block_pin, iblk; 00208 t_type_ptr type; 00209 00210 assert(rr_node[inode].type == SINK); 00211 i = rr_node[inode].xlow; 00212 j = rr_node[inode].ylow; 00213 type = grid[i][j].type; 00214 ptc_num = rr_node[inode].ptc_num; /* For sinks, ptc_num is the class */ 00215 ifound = 0; 00216 00217 for(iblk = 0; iblk < type->capacity; iblk++) 00218 { 00219 bnum = grid[i][j].blocks[iblk]; /* Hardcoded to one block */ 00220 for(ipin = 1; ipin < (clb_net[inet].num_sinks + 1); ipin++) 00221 { /* All net SINKs */ 00222 if(clb_net[inet].node_block[ipin] == bnum) 00223 { 00224 node_block_pin = clb_net[inet].node_block_pin[ipin]; 00225 iclass = type->pin_class[node_block_pin]; 00226 if(iclass == ptc_num) 00227 { 00228 /* Could connect to same pin class on the same clb more than once. Only * 00229 * update pin_done for a pin that hasn't been reached yet. */ 00230 00231 if(pin_done[ipin] == FALSE) 00232 { 00233 ifound++; 00234 pin_done[ipin] = TRUE; 00235 } 00236 } 00237 } 00238 } 00239 } 00240 00241 if(ifound > 1 && type == IO_TYPE) 00242 { 00243 printf("Error in check_sink: found %d terminals of net %d of pad" 00244 "\n %d at location (%d, %d).\n", ifound, inet, ptc_num, i, 00245 j); 00246 exit(1); 00247 } 00248 00249 if(ifound < 1) 00250 { 00251 printf 00252 ("Error in check_sink: node %d does not connect to any terminal " 00253 "\n of net %d.\n", inode, inet); 00254 exit(1); 00255 } 00256 } 00257 00258 00259 /** Checks that the node passed in is a valid source for this net. */ 00260 static void 00261 check_source(int inode, 00262 int inet) 00263 { 00264 t_rr_type rr_type; 00265 t_type_ptr type; 00266 int i, j, ptc_num, bnum, node_block_pin, iclass; 00267 00268 rr_type = rr_node[inode].type; 00269 if(rr_type != SOURCE) 00270 { 00271 printf 00272 ("Error in check_source: net %d begins with a node of type %d.\n", 00273 inet, rr_type); 00274 exit(1); 00275 } 00276 00277 i = rr_node[inode].xlow; 00278 j = rr_node[inode].ylow; 00279 ptc_num = rr_node[inode].ptc_num; /* for sinks and sources, ptc_num is class */ 00280 bnum = clb_net[inet].node_block[0]; /* First node_block for net is the source */ 00281 type = grid[i][j].type; 00282 00283 if(block[bnum].x != i || block[bnum].y != j) 00284 { 00285 printf 00286 ("Error in check_source: net SOURCE is in wrong location (%d,%d)." 00287 "\n", i, j); 00288 exit(1); 00289 } 00290 00291 node_block_pin = clb_net[inet].node_block_pin[0]; 00292 iclass = type->pin_class[node_block_pin]; 00293 00294 if(ptc_num != iclass) 00295 { 00296 printf 00297 ("Error in check_source: net SOURCE is of wrong class (%d).\n", 00298 ptc_num); 00299 exit(1); 00300 } 00301 } 00302 00303 00304 /** Checks that the switch leading from this traceback element to the next 00305 * one is a legal switch type. 00306 */ 00307 static void 00308 check_switch(struct s_trace *tptr, 00309 int num_switch) 00310 { 00311 int inode; 00312 short switch_type; 00313 00314 inode = tptr->index; 00315 switch_type = tptr->iswitch; 00316 00317 if(rr_node[inode].type != SINK) 00318 { 00319 if(switch_type < 0 || switch_type >= num_switch) 00320 { 00321 printf 00322 ("Error in check_switch: rr_node %d left via switch type %d.\n", 00323 inode, switch_type); 00324 printf("Switch type is out of range.\n"); 00325 exit(1); 00326 } 00327 } 00328 00329 else 00330 { /* Is a SINK */ 00331 00332 /* Without feedthroughs, there should be no switch. If feedthroughs are * 00333 * allowed, change to treat a SINK like any other node (as above). */ 00334 00335 if(switch_type != OPEN) 00336 { 00337 printf 00338 ("Error in check_switch: rr_node %d is a SINK, but attempts \n" 00339 "to use a switch of type %d.\n", inode, switch_type); 00340 exit(1); 00341 } 00342 } 00343 } 00344 00345 /** This routine resets the flags of all the channel segments contained 00346 * in the traceback of net inet to 0. This allows us to check the 00347 * next net for connectivity (and the default state of the flags 00348 * should always be zero after they have been used). 00349 */ 00350 static void 00351 reset_flags(int inet, 00352 boolean * connected_to_route) 00353 { 00354 00355 struct s_trace *tptr; 00356 int inode; 00357 00358 tptr = trace_head[inet]; 00359 00360 while(tptr != NULL) 00361 { 00362 inode = tptr->index; 00363 connected_to_route[inode] = FALSE; /* Not in routed path now. */ 00364 tptr = tptr->next; 00365 } 00366 } 00367 00368 /** This routine checks if the rr_node to_node is reachable from from_node. 00369 * It returns TRUE if is reachable and FALSE if it is not. Check_node has 00370 * already been used to verify that both nodes are valid rr_nodes, so only 00371 * adjacency is checked here. 00372 */ 00373 static boolean 00374 check_adjacent(int from_node, 00375 int to_node) 00376 { 00377 int from_xlow, from_ylow, to_xlow, to_ylow, from_ptc, to_ptc, iclass; 00378 int num_adj, to_xhigh, to_yhigh, from_xhigh, from_yhigh, iconn; 00379 boolean reached; 00380 t_rr_type from_type, to_type; 00381 t_type_ptr from_grid_type, to_grid_type; 00382 00383 reached = FALSE; 00384 00385 for(iconn = 0; iconn < rr_node[from_node].num_edges; iconn++) 00386 { 00387 if(rr_node[from_node].edges[iconn] == to_node) 00388 { 00389 reached = TRUE; 00390 break; 00391 } 00392 } 00393 00394 if(!reached) 00395 return (FALSE); 00396 00397 /* Now we know the rr graph says these two nodes are adjacent. Double * 00398 * check that this makes sense, to verify the rr graph. */ 00399 00400 num_adj = 0; 00401 00402 from_type = rr_node[from_node].type; 00403 from_xlow = rr_node[from_node].xlow; 00404 from_ylow = rr_node[from_node].ylow; 00405 from_xhigh = rr_node[from_node].xhigh; 00406 from_yhigh = rr_node[from_node].yhigh; 00407 from_ptc = rr_node[from_node].ptc_num; 00408 to_type = rr_node[to_node].type; 00409 to_xlow = rr_node[to_node].xlow; 00410 to_ylow = rr_node[to_node].ylow; 00411 to_xhigh = rr_node[to_node].xhigh; 00412 to_yhigh = rr_node[to_node].yhigh; 00413 to_ptc = rr_node[to_node].ptc_num; 00414 00415 switch (from_type) 00416 { 00417 00418 case SOURCE: 00419 assert(to_type == OPIN); 00420 if(from_xlow == to_xlow && from_ylow == to_ylow 00421 && from_xhigh == to_xhigh && from_yhigh == to_yhigh) 00422 { 00423 00424 from_grid_type = grid[from_xlow][from_ylow].type; 00425 to_grid_type = grid[to_xlow][to_ylow].type; 00426 assert(from_grid_type == to_grid_type); 00427 00428 iclass = to_grid_type->pin_class[to_ptc]; 00429 if(iclass == from_ptc) 00430 num_adj++; 00431 } 00432 break; 00433 00434 case SINK: 00435 /* SINKS are adjacent to not connected */ 00436 break; 00437 00438 case OPIN: 00439 assert(to_type == CHANX || to_type == CHANY); 00440 num_adj += pin_and_chan_adjacent(from_node, to_node); 00441 00442 break; 00443 00444 case IPIN: 00445 assert(to_type == SINK); 00446 if(from_xlow == to_xlow && from_ylow == to_ylow 00447 && from_xhigh == to_xhigh && from_yhigh == to_yhigh) 00448 { 00449 00450 from_grid_type = grid[from_xlow][from_ylow].type; 00451 to_grid_type = grid[to_xlow][to_ylow].type; 00452 assert(from_grid_type == to_grid_type); 00453 00454 iclass = from_grid_type->pin_class[from_ptc]; 00455 if(iclass == to_ptc) 00456 num_adj++; 00457 } 00458 break; 00459 00460 case CHANX: 00461 if(to_type == IPIN) 00462 { 00463 num_adj += pin_and_chan_adjacent(to_node, from_node); 00464 } 00465 else if(to_type == CHANX) 00466 { 00467 from_xhigh = rr_node[from_node].xhigh; 00468 to_xhigh = rr_node[to_node].xhigh; 00469 if(from_ylow == to_ylow) 00470 { 00471 /* UDSD Modification by WMF Begin */ 00472 /*For Fs > 3, can connect to overlapping wire segment */ 00473 if(to_xhigh == from_xlow - 1 00474 || from_xhigh == to_xlow - 1) 00475 { 00476 num_adj++; 00477 } 00478 /* Overlapping */ 00479 else 00480 { 00481 int i; 00482 00483 for(i = from_xlow; i <= from_xhigh; i++) 00484 { 00485 if(i >= to_xlow && i <= to_xhigh) 00486 { 00487 num_adj++; 00488 break; 00489 } 00490 } 00491 } 00492 /* UDSD Modification by WMF End */ 00493 } 00494 } 00495 else if(to_type == CHANY) 00496 { 00497 num_adj += chanx_chany_adjacent(from_node, to_node); 00498 } 00499 else 00500 { 00501 assert(0); 00502 } 00503 break; 00504 00505 case CHANY: 00506 if(to_type == IPIN) 00507 { 00508 num_adj += pin_and_chan_adjacent(to_node, from_node); 00509 } 00510 else if(to_type == CHANY) 00511 { 00512 from_yhigh = rr_node[from_node].yhigh; 00513 to_yhigh = rr_node[to_node].yhigh; 00514 if(from_xlow == to_xlow) 00515 { 00516 /* UDSD Modification by WMF Begin */ 00517 if(to_yhigh == from_ylow - 1 00518 || from_yhigh == to_ylow - 1) 00519 { 00520 num_adj++; 00521 } 00522 /* Overlapping */ 00523 else 00524 { 00525 int j; 00526 00527 for(j = from_ylow; j <= from_yhigh; j++) 00528 { 00529 if(j >= to_ylow && j <= to_yhigh) 00530 { 00531 num_adj++; 00532 break; 00533 } 00534 } 00535 } 00536 /* UDSD Modification by WMF End */ 00537 } 00538 } 00539 else if(to_type == CHANX) 00540 { 00541 num_adj += chanx_chany_adjacent(to_node, from_node); 00542 } 00543 else 00544 { 00545 assert(0); 00546 } 00547 break; 00548 00549 default: 00550 break; 00551 00552 } 00553 00554 if(num_adj == 1) 00555 return (TRUE); 00556 else if(num_adj == 0) 00557 return (FALSE); 00558 00559 printf("Error in check_adjacent: num_adj = %d. Expected 0 or 1.\n", 00560 num_adj); 00561 exit(1); 00562 } 00563 00564 /** Returns 1 if the specified CHANX and CHANY nodes are adjacent, 0 00565 * otherwise. 00566 */ 00567 static int 00568 chanx_chany_adjacent(int chanx_node, 00569 int chany_node) 00570 { 00571 00572 int chanx_y, chanx_xlow, chanx_xhigh; 00573 int chany_x, chany_ylow, chany_yhigh; 00574 00575 chanx_y = rr_node[chanx_node].ylow; 00576 chanx_xlow = rr_node[chanx_node].xlow; 00577 chanx_xhigh = rr_node[chanx_node].xhigh; 00578 00579 chany_x = rr_node[chany_node].xlow; 00580 chany_ylow = rr_node[chany_node].ylow; 00581 chany_yhigh = rr_node[chany_node].yhigh; 00582 00583 if(chany_ylow > chanx_y + 1 || chany_yhigh < chanx_y) 00584 return (0); 00585 00586 if(chanx_xlow > chany_x + 1 || chanx_xhigh < chany_x) 00587 return (0); 00588 00589 return (1); 00590 } 00591 00592 /** Checks if pin_node is adjacent to chan_node. It returns 1 if the two 00593 * nodes are adjacent and 0 if they are not (any other value means there's 00594 * a bug in this routine). 00595 */ 00596 static int 00597 pin_and_chan_adjacent(int pin_node, 00598 int chan_node) 00599 { 00600 00601 int num_adj, pin_xlow, pin_ylow, pin_xhigh, pin_yhigh, chan_xlow, 00602 chan_ylow, chan_xhigh, chan_yhigh; 00603 int pin_ptc, i; 00604 t_rr_type chan_type; 00605 t_type_ptr pin_grid_type; 00606 00607 num_adj = 0; 00608 pin_xlow = rr_node[pin_node].xlow; 00609 pin_ylow = rr_node[pin_node].ylow; 00610 pin_xhigh = rr_node[pin_node].xhigh; 00611 pin_yhigh = rr_node[pin_node].yhigh; 00612 pin_grid_type = grid[pin_xlow][pin_ylow].type; 00613 pin_ptc = rr_node[pin_node].ptc_num; 00614 chan_type = rr_node[chan_node].type; 00615 chan_xlow = rr_node[chan_node].xlow; 00616 chan_ylow = rr_node[chan_node].ylow; 00617 chan_xhigh = rr_node[chan_node].xhigh; 00618 chan_yhigh = rr_node[chan_node].yhigh; 00619 00620 if(chan_type == CHANX) 00621 { 00622 if(chan_ylow == pin_yhigh) 00623 { /* CHANX above CLB */ 00624 if(pin_grid_type-> 00625 pinloc[pin_grid_type->height - 1][TOP][pin_ptc] == 1 00626 && pin_xlow <= chan_xhigh && pin_xhigh >= chan_xlow) 00627 num_adj++; 00628 } 00629 else if(chan_ylow == pin_ylow - 1) 00630 { /* CHANX below CLB */ 00631 if(pin_grid_type->pinloc[0][BOTTOM][pin_ptc] == 1 00632 && pin_xlow <= chan_xhigh && pin_xhigh >= chan_xlow) 00633 num_adj++; 00634 } 00635 } 00636 else if(chan_type == CHANY) 00637 { 00638 for(i = 0; i < pin_grid_type->height; i++) 00639 { 00640 if(chan_xlow == pin_xhigh) 00641 { /* CHANY to right of CLB */ 00642 if(pin_grid_type->pinloc[i][RIGHT][pin_ptc] == 1 00643 && pin_ylow <= chan_yhigh 00644 && pin_yhigh >= chan_ylow) 00645 num_adj++; 00646 } 00647 else if(chan_xlow == pin_xlow - 1) 00648 { /* CHANY to left of CLB */ 00649 if(pin_grid_type->pinloc[i][LEFT][pin_ptc] == 1 00650 && pin_ylow <= chan_yhigh 00651 && pin_yhigh >= chan_ylow) 00652 num_adj++; 00653 } 00654 } 00655 } 00656 return (num_adj); 00657 } 00658 00659 /** This routine updates the occ field in the rr_node structure according to 00660 * the resource usage of the current routing. It does a brute force 00661 * recompute from scratch that is useful for sanity checking. 00662 */ 00663 static void 00664 recompute_occupancy_from_scratch(t_ivec ** clb_opins_used_locally) 00665 { 00666 00667 int inode, inet, iblk, iclass, ipin, num_local_opins; 00668 struct s_trace *tptr; 00669 00670 /* First set the occupancy of everything to zero. */ 00671 00672 for(inode = 0; inode < num_rr_nodes; inode++) 00673 rr_node[inode].occ = 0; 00674 00675 /* Now go through each net and count the tracks and pins used everywhere */ 00676 00677 for(inet = 0; inet < num_nets; inet++) 00678 { 00679 00680 if(clb_net[inet].is_global) /* Skip global nets. */ 00681 continue; 00682 00683 tptr = trace_head[inet]; 00684 if(tptr == NULL) 00685 continue; 00686 00687 for(;;) 00688 { 00689 inode = tptr->index; 00690 rr_node[inode].occ++; 00691 00692 if(rr_node[inode].type == SINK) 00693 { 00694 tptr = tptr->next; /* Skip next segment. */ 00695 if(tptr == NULL) 00696 break; 00697 } 00698 00699 tptr = tptr->next; 00700 } 00701 } 00702 00703 /* Now update the occupancy of each of the "locally used" OPINs on each CLB * 00704 * (CLB outputs used up by being directly wired to subblocks used only * 00705 * locally). */ 00706 00707 for(iblk = 0; iblk < num_blocks; iblk++) 00708 { 00709 for(iclass = 0; iclass < block[iblk].type->num_class; iclass++) 00710 { 00711 num_local_opins = 00712 clb_opins_used_locally[iblk][iclass].nelem; 00713 /* Will always be 0 for pads or SINK classes. */ 00714 for(ipin = 0; ipin < num_local_opins; ipin++) 00715 { 00716 inode = 00717 clb_opins_used_locally[iblk][iclass]. 00718 list[ipin]; 00719 rr_node[inode].occ++; 00720 } 00721 } 00722 } 00723 } 00724 00725 /** Checks that enough OPINs on CLBs have been set aside (used up) to make a 00726 * legal routing if subblocks connect to OPINs directly. 00727 */ 00728 static void 00729 check_locally_used_clb_opins(t_ivec ** clb_opins_used_locally, 00730 enum e_route_type route_type) 00731 { 00732 int iclass, iblk, num_local_opins, inode, ipin; 00733 t_rr_type rr_type; 00734 00735 for(iblk = 0; iblk < num_blocks; iblk++) 00736 { 00737 for(iclass = 0; iclass < block[iblk].type->num_class; iclass++) 00738 { 00739 num_local_opins = 00740 clb_opins_used_locally[iblk][iclass].nelem; 00741 /* Always 0 for pads and for SINK classes */ 00742 00743 for(ipin = 0; ipin < num_local_opins; ipin++) 00744 { 00745 inode = 00746 clb_opins_used_locally[iblk][iclass]. 00747 list[ipin]; 00748 check_node_and_range(inode, route_type); /* Node makes sense? */ 00749 00750 /* Now check that node is an OPIN of the right type. */ 00751 00752 rr_type = rr_node[inode].type; 00753 if(rr_type != OPIN) 00754 { 00755 printf 00756 ("Error in check_locally_used_opins: Block #%d (%s)\n" 00757 "\tclass %d locally used OPIN is of the wrong rr_type --\n" 00758 "\tit is rr_node #%d of type %d.\n", 00759 iblk, block[iblk].name, iclass, 00760 inode, rr_type); 00761 exit(1); 00762 } 00763 00764 ipin = rr_node[inode].ptc_num; 00765 if(block[iblk].type->pin_class[ipin] != iclass) 00766 { 00767 printf 00768 ("Error in check_locally_used_opins: Block #%d (%s):\n" 00769 "\tExpected class %d locally used OPIN, got class %d." 00770 "\trr_node #: %d.\n", iblk, 00771 block[iblk].name, iclass, 00772 block[iblk].type->pin_class[ipin], 00773 inode); 00774 exit(1); 00775 } 00776 } 00777 } 00778 } 00779 } 00780 00781 /** Checks that inode is within the legal range, then calls check_node to 00782 * check that everything else about the node is OK. 00783 */ 00784 static void 00785 check_node_and_range(int inode, 00786 enum e_route_type route_type) 00787 { 00788 if(inode < 0 || inode >= num_rr_nodes) 00789 { 00790 printf 00791 ("Error in check_node_and_range: rr_node #%d is out of legal " 00792 "\trange (0 to %d).\n", inode, num_rr_nodes - 1); 00793 exit(1); 00794 } 00795 check_node(inode, route_type); 00796 }