VPR-6.0

vpr/SRC/route/check_route.c

Go to the documentation of this file.
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 }