VPR-6.0

vpr/SRC/route/rr_graph2.c

Go to the documentation of this file.
00001 #include <stdio.h>
00002 #include <assert.h>
00003 #include "util.h"
00004 #include "vpr_types.h"
00005 #include "globals.h"
00006 #include "rr_graph_util.h"
00007 #include "rr_graph2.h"
00008 #include "rr_graph_sbox.h"
00009 #include "read_xml_arch_file.h"
00010 
00011 #define ALLOW_SWITCH_OFF
00012 
00013 /** WMF: May 07 I put this feature in, but on May 09 in my testing phase
00014  * I found that for Wilton, this feature is bad, since Wilton is already doing
00015  * a reverse. 
00016  */
00017 #define ENABLE_REVERSE 0
00018 
00019 
00020 #define SAME_TRACK -5
00021 #define UN_SET -1
00022 /* Variables below are the global variables shared only amongst the rr_graph *
00023  ************************************ routines. ******************************/
00024 
00025 /** [0..num_rr_nodes-1].  TRUE if a node is already listed in the edges array 
00026  * that's being constructed.  This allows me to ensure that there are never  
00027  *  duplicate edges (two edges between the same thing).                      
00028  */
00029 boolean *rr_edge_done;
00030 
00031 
00032 /** Used to keep my own list of free linked integers, for speed reasons.     */
00033 t_linked_edge *free_edge_list_head = NULL;
00034 
00035 
00036 
00037 /*************************** Variables local to this module *****************/
00038 
00039 /* Two arrays below give the rr_node_index of the channel segment at        *
00040  * (i,j,track) for fast index lookup.                                       */
00041 
00042 /* UDSD Modifications by WMF Begin */
00043 
00044 /* The sblock_pattern_init_mux_lookup contains the assignment of incoming
00045  * wires to muxes. More specifically, it only contains the assignment of 
00046  * M-to-N cases. WMF_BETTER_COMMENTS */
00047 
00048 /* UDSD MOdifications by WMF End */
00049 
00050 
00051 /************************** Subroutines local to this module ****************/
00052 
00053 static void get_switch_type(boolean is_from_sbox,
00054                             boolean is_to_sbox,
00055                             short from_node_switch,
00056                             short to_node_switch,
00057                             short switch_types[2]);
00058 
00059 static void load_chan_rr_indices(INP int nodes_per_chan,
00060                                  INP int chan_len,
00061                                  INP int num_chans,
00062                                  INP t_rr_type type,
00063                                  INP t_seg_details * seg_details,
00064                                  INOUTP int *index,
00065                                  INOUTP t_ivec *** indices);
00066 
00067 static int get_bidir_track_to_chan_seg(INP struct s_ivec conn_tracks,
00068                                        INP t_ivec *** rr_node_indices,
00069                                        INP int to_chan,
00070                                        INP int to_seg,
00071                                        INP int to_sb,
00072                                        INP t_rr_type to_type,
00073                                        INP t_seg_details * seg_details,
00074                                        INP boolean from_is_sbox,
00075                                        INP int from_switch,
00076                                        INOUTP boolean * rr_edge_done,
00077                                        INP enum e_directionality
00078                                        directionality,
00079                                        INOUTP struct s_linked_edge
00080                                        **edge_list);
00081 
00082 static int get_unidir_track_to_chan_seg(INP boolean is_end_sb,
00083                                         INP int from_track,
00084                                         INP int to_chan,
00085                                         INP int to_seg,
00086                                         INP int to_sb,
00087                                         INP t_rr_type to_type,
00088                                         INP int nodes_per_chan,
00089                                         INP int nx,
00090                                         INP int ny,
00091                                         INP enum e_side from_side,
00092                                         INP enum e_side to_side,
00093                                         INP int Fs_per_side,
00094                                         INP int *opin_mux_size,
00095                                         INP short *****sblock_pattern,
00096                                         INP t_ivec *** rr_node_indices,
00097                                         INP t_seg_details * seg_details,
00098                                         INOUTP boolean * rr_edge_done,
00099                                         OUTP boolean * Fs_clipped,
00100                                         INOUTP struct s_linked_edge
00101                                         **edge_list);
00102 
00103 static int vpr_to_phy_track(INP int itrack,
00104                             INP int chan_num,
00105                             INP int seg_num,
00106                             INP t_seg_details * seg_details,
00107                             INP enum e_directionality directionality);
00108 
00109 static int *get_seg_track_counts(INP int num_sets,
00110                                  INP int num_seg_types,
00111                                  INP t_segment_inf * segment_inf,
00112                                  INP boolean use_full_seg_groups);
00113 
00114 static int *label_wire_muxes(INP int chan_num,
00115                              INP int seg_num,
00116                              INP t_seg_details * seg_details,
00117                              INP int max_len,
00118                              INP enum e_direction dir,
00119                              INP int nodes_per_chan,
00120                              OUTP int *num_wire_muxes);
00121 
00122 static int *label_wire_muxes_for_balance(INP int chan_num,
00123                                          INP int seg_num,
00124                                          INP t_seg_details * seg_details,
00125                                          INP int max_len,
00126                                          INP enum e_direction direction,
00127                                          INP int nodes_per_chan,
00128                                          INP int *num_wire_muxes,
00129                                          INP t_rr_type chan_type,
00130                                          INP int *opin_mux_size,
00131                                          INP t_ivec *** rr_node_indices);
00132 
00133 static int *label_incoming_wires(INP int chan_num,
00134                                  INP int seg_num,
00135                                  INP int sb_seg,
00136                                  INP t_seg_details * seg_details,
00137                                  INP int max_len,
00138                                  INP enum e_direction dir,
00139                                  INP int nodes_per_chan,
00140                                  OUTP int *num_incoming_wires,
00141                                  OUTP int *num_ending_wires);
00142 
00143 static int find_label_of_track(int *wire_mux_on_track,
00144                                int num_wire_muxes,
00145                                int from_track);
00146 
00147 /******************** Subroutine definitions *******************************/
00148 
00149 /** This assigns tracks (individually or pairs) to segment types.
00150  * It tries to match requested ratio. If use_full_seg_groups is
00151  * true, then segments are assigned only in multiples of their
00152  * length. This is primarily used for making a tileable unidir
00153  * layout. The effect of using this is that the number of tracks
00154  * requested will not always be met and the result will sometimes
00155  * be over and sometimes under.
00156  * The pattern when using use_full_seg_groups is to keep adding
00157  * one group of the track type that wants the largest number of
00158  * groups of tracks. Each time a group is assigned, the types
00159  * demand is reduced by 1 unit. The process stops when we are
00160  * no longer less than the requested number of tracks. As a final
00161  * step, if we were closer to target before last more, undo it
00162  * and end up with a result that uses fewer tracks than given. 
00163  */
00164 static int *
00165 get_seg_track_counts(INP int num_sets,
00166                      INP int num_seg_types,
00167                      INP t_segment_inf * segment_inf,
00168                      INP boolean use_full_seg_groups)
00169 {
00170     int *result;
00171         double *demand;
00172     int i, imax, freq_sum, assigned, size;
00173         double scale, max, reduce;
00174 
00175     result = (int *)my_malloc(sizeof(int) * num_seg_types);
00176     demand = (double *)my_malloc(sizeof(double) * num_seg_types);
00177 
00178     /* Scale factor so we can divide by any length
00179      * and still use integers */
00180     scale = 1;
00181     freq_sum = 0;
00182     for(i = 0; i < num_seg_types; ++i)
00183         {
00184             scale *= segment_inf[i].length;
00185             freq_sum += segment_inf[i].frequency;
00186         }
00187     reduce = scale * freq_sum;
00188 
00189     /* Init assignments to 0 and set the demand values */
00190     for(i = 0; i < num_seg_types; ++i)
00191         {
00192             result[i] = 0;
00193             demand[i] = scale * num_sets * segment_inf[i].frequency;
00194             if(use_full_seg_groups)
00195                 {
00196                     demand[i] /= segment_inf[i].length;
00197                 }
00198         }
00199 
00200     /* Keep assigning tracks until we use them up */
00201     assigned = 0;
00202     size = 0;
00203     imax = 0;
00204     while(assigned < num_sets)
00205         {
00206             /* Find current maximum demand */
00207             max = 0;
00208             for(i = 0; i < num_seg_types; ++i)
00209                 {
00210                     if(demand[i] > max)
00211                         {
00212                             imax = i;
00213                             max = demand[i];
00214                         }
00215                 }
00216 
00217             /* Assign tracks to the type and reduce the types demand */
00218             size = (use_full_seg_groups ? segment_inf[imax].length : 1);
00219             demand[imax] -= reduce;
00220             result[imax] += size;
00221             assigned += size;
00222         }
00223 
00224     /* Undo last assignment if we were closer to goal without it */
00225     if((assigned - num_sets) > (size / 2))
00226         {
00227             result[imax] -= size;
00228         }
00229 
00230     /* Free temps */
00231     if(demand)
00232         {
00233             free(demand);
00234             demand = NULL;
00235         }
00236 
00237     /* This must be freed by caller */
00238     return result;
00239 }
00240 
00241 /** Allocates and loads the seg_details data structure.  Max_len gives the   
00242  * maximum length of a segment (dimension of array).  The code below tries  
00243  * to:                                                                      
00244  * - (1) stagger the start points of segments of the same type evenly;        
00245  * - (2) spread out the limited number of connection boxes or switch boxes    
00246  *     evenly along the length of a segment, starting at the segment ends;  
00247  * - (3) stagger the connection and switch boxes on different long lines,     
00248  *     as they will not be staggered by different segment start points.     
00249  */
00250 t_seg_details *
00251 alloc_and_load_seg_details(INOUTP int *nodes_per_chan,
00252                            INP int max_len,
00253                            INP int num_seg_types,
00254                            INP t_segment_inf * segment_inf,
00255                            INP boolean use_full_seg_groups,
00256                            INP boolean is_global_graph,
00257                            INP enum e_directionality directionality)
00258 {
00259 
00260     int i, cur_track, ntracks, itrack, length, j, index;
00261     int wire_switch, opin_switch, fac, num_sets, tmp;
00262     int group_start, first_track;
00263     int *sets_per_seg_type = NULL;
00264     t_seg_details *seg_details = NULL;
00265     boolean longline;
00266 
00267     /* Unidir tracks are assigned in pairs, and bidir tracks individually */
00268     if(directionality == BI_DIRECTIONAL)
00269         {
00270             fac = 1;
00271         }
00272     else
00273         {
00274             assert(directionality == UNI_DIRECTIONAL);
00275             fac = 2;
00276         }
00277     assert(*nodes_per_chan % fac == 0);
00278 
00279     /* Map segment type fractions and groupings to counts of tracks */
00280     sets_per_seg_type = get_seg_track_counts((*nodes_per_chan / fac),
00281                                              num_seg_types,
00282                                              segment_inf,
00283                                              use_full_seg_groups);
00284 
00285     /* Count the number tracks actually assigned. */
00286     tmp = 0;
00287     for(i = 0; i < num_seg_types; ++i)
00288         {
00289             tmp += sets_per_seg_type[i] * fac;
00290         }
00291     assert(use_full_seg_groups || (tmp == *nodes_per_chan));
00292     *nodes_per_chan = tmp;
00293 
00294     seg_details = (t_seg_details *)
00295         my_malloc(*nodes_per_chan * sizeof(t_seg_details));
00296 
00297     /* Setup the seg_details data */
00298     cur_track = 0;
00299     for(i = 0; i < num_seg_types; ++i)
00300         {
00301             first_track = cur_track;
00302 
00303             num_sets = sets_per_seg_type[i];
00304             ntracks = fac * num_sets;
00305             if(ntracks < 1)
00306                 {
00307                     continue;
00308                 }
00309             /* Avoid divide by 0 if ntracks */
00310             longline = segment_inf[i].longline;
00311             length = segment_inf[i].length;
00312             if(longline)
00313                 {
00314                     length = max_len;
00315                 }
00316 
00317             wire_switch = segment_inf[i].wire_switch;
00318             opin_switch = segment_inf[i].opin_switch;
00319             assert((wire_switch == opin_switch)
00320                    || (directionality != UNI_DIRECTIONAL));
00321 
00322             /* Set up the tracks of same type */
00323             group_start = 0;
00324             for(itrack = 0; itrack < ntracks; itrack++)
00325                 {
00326 
00327                     /* Remember the start track of the current wire group */
00328                     if((itrack / fac) % length == 0 && (itrack % fac) == 0)
00329                         {
00330                             group_start = cur_track;
00331                         }
00332 
00333                     seg_details[cur_track].length = length;
00334                     seg_details[cur_track].longline = longline;
00335 
00336                     /* Stagger the start points in for each track set. The 
00337                      * pin mappings should be aware of this when chosing an
00338                      * intelligent way of connecting pins and tracks.
00339                      * cur_track is used as an offset so that extra tracks
00340                      * from different segment types are hopefully better
00341                      * balanced. */
00342                     seg_details[cur_track].start =
00343                         (cur_track / fac) % length + 1;
00344 
00345                     /* These properties are used for vpr_to_phy_track to determine
00346                      * * twisting of wires. */
00347                     seg_details[cur_track].group_start = group_start;
00348                     seg_details[cur_track].group_size =
00349                         min(ntracks + first_track - group_start,
00350                             length * fac);
00351                     assert(0 == seg_details[cur_track].group_size % fac);
00352                     if(0 == seg_details[cur_track].group_size)
00353                         {
00354                             seg_details[cur_track].group_size = length * fac;
00355                         }
00356 
00357                     /* Setup the cb and sb patterns. Global route graphs can't depopulate cb and sb
00358                      * since this is a property of a detailed route. */
00359                     seg_details[cur_track].cb =
00360                         (boolean *) my_malloc(length * sizeof(boolean));
00361                     seg_details[cur_track].sb =
00362                         (boolean *) my_malloc((length + 1) * sizeof(boolean));
00363                     for(j = 0; j < length; ++j)
00364                         {
00365                             if(is_global_graph)
00366                                 {
00367                                     seg_details[cur_track].cb[j] = TRUE;
00368                                 }
00369                             else
00370                                 {
00371                                     index = j;
00372 
00373                                     /* Rotate longline's so they vary across the FPGA */
00374                                     if(longline)
00375                                         {
00376                                             index = (index + itrack) % length;
00377                                         }
00378 
00379                                     /* Reverse the order for tracks going in DEC_DIRECTION */
00380                                     if(itrack % fac == 1)
00381                                         {
00382                                             index = (length - 1) - j;
00383                                         }
00384 
00385                                     /* Use the segment's pattern. */
00386                                     index = j % segment_inf[i].cb_len;
00387                                     seg_details[cur_track].cb[j] =
00388                                         segment_inf[i].cb[index];
00389                                 }
00390                         }
00391                     for(j = 0; j < (length + 1); ++j)
00392                         {
00393                             if(is_global_graph)
00394                                 {
00395                                     seg_details[cur_track].sb[j] = TRUE;
00396                                 }
00397                             else
00398                                 {
00399                                     index = j;
00400 
00401                                     /* Rotate longline's so they vary across the FPGA */
00402                                     if(longline)
00403                                         {
00404                                             index =
00405                                                 (index + itrack) % (length +
00406                                                                     1);
00407                                         }
00408 
00409                                     /* Reverse the order for tracks going in DEC_DIRECTION */
00410                                     if(itrack % fac == 1)
00411                                         {
00412                                             index = ((length + 1) - 1) - j;
00413                                         }
00414 
00415                                     /* Use the segment's pattern. */
00416                                     index = j % segment_inf[i].sb_len;
00417                                     seg_details[cur_track].sb[j] =
00418                                         segment_inf[i].sb[index];
00419                                 }
00420                         }
00421 
00422                     seg_details[cur_track].Rmetal = segment_inf[i].Rmetal;
00423                     seg_details[cur_track].Cmetal = segment_inf[i].Cmetal;
00424 
00425                     seg_details[cur_track].wire_switch = wire_switch;
00426                     seg_details[cur_track].opin_switch = opin_switch;
00427 
00428                     if(BI_DIRECTIONAL == directionality)
00429                         {
00430                             seg_details[cur_track].direction = BI_DIRECTION;
00431                         }
00432                     else
00433                         {
00434                             assert(UNI_DIRECTIONAL == directionality);
00435                             seg_details[cur_track].direction =
00436                                 (itrack % 2) ? DEC_DIRECTION : INC_DIRECTION;
00437                         }
00438 
00439                     switch (segment_inf[i].directionality)
00440                         {
00441                         case UNI_DIRECTIONAL:
00442                             seg_details[cur_track].drivers = SINGLE;
00443                             break;
00444                         case BI_DIRECTIONAL:
00445                             seg_details[cur_track].drivers = MULTI_BUFFERED;
00446                             break;
00447                         }
00448 
00449                     seg_details[cur_track].index = i;
00450 
00451                     ++cur_track;
00452                 }
00453         }                       /* End for each segment type. */
00454 
00455         /* free variables */
00456         free(sets_per_seg_type);
00457 
00458     return seg_details;
00459 }
00460 
00461 /** Frees all the memory allocated to an array of seg_details structures. */
00462 void
00463 free_seg_details(t_seg_details * seg_details,
00464                  int nodes_per_chan)
00465 {
00466     int i;
00467 
00468     for(i = 0; i < nodes_per_chan; i++)
00469         {
00470             free(seg_details[i].cb);
00471             free(seg_details[i].sb);
00472         }
00473     free(seg_details);
00474 }
00475 
00476 
00477 /** Dumps out an array of seg_details structures to file fname.  Used only   
00478  * for debugging.                                                           
00479  */
00480 void
00481 dump_seg_details(t_seg_details * seg_details,
00482                  int nodes_per_chan,
00483                  char *fname)
00484 {
00485 
00486     FILE *fp;
00487     int i, j;
00488     const char *drivers_names[] = { "multi_buffered",
00489         "single"
00490     };
00491     const char *direction_names[] = { "inc_direction",
00492         "dec_direction",
00493         "bi_direction"
00494     };
00495 
00496     fp = my_fopen(fname, "w", 0);
00497 
00498     for(i = 0; i < nodes_per_chan; i++)
00499         {
00500             fprintf(fp, "Track: %d.\n", i);
00501             fprintf(fp, "Length: %d,  Start: %d,  Long line: %d  "
00502                     "wire_switch: %d  opin_switch: %d.\n",
00503                     seg_details[i].length,
00504                     seg_details[i].start,
00505                     seg_details[i].longline,
00506                     seg_details[i].wire_switch, seg_details[i].opin_switch);
00507 
00508             fprintf(fp, "Rmetal: %g  Cmetal: %g\n",
00509                     seg_details[i].Rmetal, seg_details[i].Cmetal);
00510 
00511             fprintf(fp, "Direction: %s  Drivers: %s\n",
00512                     direction_names[seg_details[i].direction],
00513                     drivers_names[seg_details[i].drivers]);
00514 
00515             fprintf(fp, "cb list:  ");
00516             for(j = 0; j < seg_details[i].length; j++)
00517                 fprintf(fp, "%d ", seg_details[i].cb[j]);
00518             fprintf(fp, "\n");
00519 
00520             fprintf(fp, "sb list: ");
00521             for(j = 0; j <= seg_details[i].length; j++)
00522                 fprintf(fp, "%d ", seg_details[i].sb[j]);
00523             fprintf(fp, "\n");
00524 
00525             fprintf(fp, "\n");
00526         }
00527 
00528     fclose(fp);
00529 }
00530 
00531 
00532 
00533 /** Returns the segment number at which the segment this track lies on        
00534  * started.                                                                  
00535  */
00536 int
00537 get_seg_start(INP t_seg_details * seg_details,
00538               INP int itrack,
00539               INP int chan_num,
00540               INP int seg_num)
00541 {
00542 
00543     int seg_start, length, start;
00544 
00545     seg_start = 1;
00546     if(FALSE == seg_details[itrack].longline)
00547         {
00548 
00549             length = seg_details[itrack].length;
00550             start = seg_details[itrack].start;
00551 
00552             /* Start is guaranteed to be between 1 and length.  Hence adding length to *
00553              * the quantity in brackets below guarantees it will be nonnegative.       */
00554 
00555             assert(start > 0);
00556             assert(start <= length);
00557 
00558             /* NOTE: Start points are staggered between different channels.
00559              * The start point must stagger backwards as chan_num increases.
00560              * Unidirectional routing expects this to allow the N-to-N 
00561              * assumption to be made with respect to ending wires in the core. */
00562             seg_start =
00563                 seg_num - (seg_num + length + chan_num - start) % length;
00564             if(seg_start < 1)
00565                 {
00566                     seg_start = 1;
00567                 }
00568         }
00569 
00570     return seg_start;
00571 }
00572 
00573 int
00574 get_seg_end(INP t_seg_details * seg_details,
00575             INP int itrack,
00576             INP int istart,
00577             INP int chan_num,
00578             INP int seg_max)
00579 {
00580     int len, ofs, end, first_full;
00581 
00582     len = seg_details[itrack].length;
00583     ofs = seg_details[itrack].start;
00584 
00585     /* Normal endpoint */
00586     end = istart + len - 1;
00587 
00588     /* If start is against edge it may have been clipped */
00589     if(1 == istart)
00590         {
00591             /* If the (staggered) startpoint of first full wire wasn't
00592              * also 1, we must be the clipped wire */
00593             first_full = (len - (chan_num % len) + ofs - 1) % len + 1;
00594             if(first_full > 1)
00595                 {
00596                     /* then we stop just before the first full seg */
00597                     end = first_full - 1;
00598                 }
00599         }
00600 
00601     /* Clip against far edge */
00602     if(end > seg_max)
00603         {
00604             end = seg_max;
00605         }
00606 
00607     return end;
00608 }
00609 
00610 
00611 
00612 
00613 /** Returns the number of tracks to which clb opin #ipin at (i,j) connects.   
00614  * Also stores the nodes to which this pin connects in the linked list       
00615  * pointed to by *edge_list_ptr.                                             
00616  */
00617 int
00618 get_bidir_opin_connections(INP int i,
00619                            INP int j,
00620                            INP int ipin,
00621                            INP struct s_linked_edge **edge_list,
00622                            INP int *****opin_to_track_map,
00623                            INP int Fc,
00624                            INP boolean * rr_edge_done,
00625                            INP t_ivec *** rr_node_indices,
00626                            INP t_seg_details * seg_details)
00627 {
00628 
00629     int iside, num_conn, ofs, tr_i, tr_j, chan, seg;
00630     int to_track, to_switch, to_node, iconn;
00631         int is_connected_track;
00632     t_type_ptr type;
00633     t_rr_type to_type;
00634 
00635     type = grid[i][j].type;
00636     ofs = grid[i][j].offset;
00637 
00638     num_conn = 0;
00639 
00640     /* [0..num_types-1][0..num_pins-1][0..height][0..3][0..Fc-1] */
00641     for(iside = 0; iside < 4; iside++)
00642         {
00643 
00644             /* Figure out coords of channel segment based on side */
00645             tr_i = ((iside == LEFT) ? (i - 1) : i);
00646             tr_j = ((iside == BOTTOM) ? (j - 1) : j);
00647 
00648             to_type = ((iside == LEFT) || (iside == RIGHT)) ? CHANY : CHANX;
00649 
00650             chan = ((to_type == CHANX) ? tr_j : tr_i);
00651             seg = ((to_type == CHANX) ? tr_i : tr_j);
00652 
00653             /* Don't connect where no tracks on fringes */
00654             if((tr_i < 0) || (tr_i > nx))
00655                 {
00656                     continue;
00657                 }
00658             if((tr_j < 0) || (tr_j > ny))
00659                 {
00660                     continue;
00661                 }
00662             if((CHANX == to_type) && (tr_i < 1))
00663                 {
00664                     continue;
00665                 }
00666             if((CHANY == to_type) && (tr_j < 1))
00667                 {
00668                     continue;
00669                 }
00670 
00671                 is_connected_track = FALSE;
00672 
00673             /* Itterate of the opin to track connections */
00674             for(iconn = 0; iconn < Fc; ++iconn)
00675                 {
00676                     to_track =
00677                         opin_to_track_map[type->
00678                                           index][ipin][ofs][iside][iconn];
00679 
00680                     /* Skip unconnected connections */
00681                     if(OPEN == to_track || is_connected_track)
00682                         {
00683                                 is_connected_track = TRUE;
00684                             assert(OPEN ==
00685                                    opin_to_track_map[type->
00686                                                      index][ipin][ofs][iside]
00687                                    [0]);
00688                             continue;
00689                         }
00690 
00691                     /* Only connect to wire if there is a CB */
00692                     if(is_cbox
00693                        (chan, seg, to_track, seg_details, BI_DIRECTIONAL))
00694                         {
00695                             to_switch = seg_details[to_track].wire_switch;
00696                             to_node =
00697                                 get_rr_node_index(tr_i, tr_j, to_type,
00698                                                   to_track, rr_node_indices);
00699 
00700                             *edge_list =
00701                                 insert_in_edge_list(*edge_list, to_node,
00702                                                     to_switch);
00703                             rr_edge_done[to_node] = TRUE;
00704                             ++num_conn;
00705                         }
00706                 }
00707         }
00708 
00709     return num_conn;
00710 }
00711 
00712 
00713 /** Gets a linked list of Fc nodes to connect to in given
00714  * chan seg.  Fc_ofs is used for the for the opin staggering
00715  * pattern. */
00716 int
00717 get_unidir_opin_connections(INP int chan,
00718                             INP int seg,
00719                             INP int Fc,
00720                             INP t_rr_type chan_type,
00721                             INP t_seg_details * seg_details,
00722                             INOUTP t_linked_edge ** edge_list_ptr,
00723                             INOUTP int **Fc_ofs,
00724                             INOUTP boolean * rr_edge_done,
00725                             INP int max_len,
00726                             INP int nodes_per_chan,
00727                             INP t_ivec *** rr_node_indices,
00728                             OUTP boolean * Fc_clipped)
00729 {
00730     int *inc_muxes = NULL;
00731     int *dec_muxes = NULL;
00732     int num_inc_muxes, num_dec_muxes, iconn;
00733     int inc_inode, dec_inode;
00734     int inc_mux, dec_mux;
00735     int inc_track, dec_track;
00736     int x, y;
00737     int num_edges;
00738 
00739     *Fc_clipped = FALSE;
00740 
00741     /* Fc is assigned in pairs so check it is even. */
00742     assert(Fc % 2 == 0);
00743 
00744     /* get_rr_node_indices needs x and y coords. */
00745     x = ((CHANX == chan_type) ? seg : chan);
00746     y = ((CHANX == chan_type) ? chan : seg);
00747 
00748     /* Get the lists of possible muxes. */
00749     inc_muxes = label_wire_muxes(chan, seg, seg_details, max_len,
00750                                  INC_DIRECTION, nodes_per_chan,
00751                                  &num_inc_muxes);
00752     dec_muxes =
00753         label_wire_muxes(chan, seg, seg_details, max_len, DEC_DIRECTION,
00754                          nodes_per_chan, &num_dec_muxes);
00755 
00756     /* Clip Fc to the number of muxes. */
00757     if(((Fc / 2) > num_inc_muxes) || ((Fc / 2) > num_dec_muxes))
00758         {
00759             *Fc_clipped = TRUE;
00760             Fc = 2 * min(num_inc_muxes, num_dec_muxes);
00761         }
00762 
00763     /* Assign tracks to meet Fc demand */
00764     num_edges = 0;
00765     for(iconn = 0; iconn < (Fc / 2); ++iconn)
00766         {
00767             /* Figure of the next mux to use */
00768             inc_mux = Fc_ofs[chan][seg] % num_inc_muxes;
00769             dec_mux = Fc_ofs[chan][seg] % num_dec_muxes;
00770             ++Fc_ofs[chan][seg];
00771 
00772             /* Figure out the track it corresponds to. */
00773             inc_track = inc_muxes[inc_mux];
00774             dec_track = dec_muxes[dec_mux];
00775 
00776             /* Figure the inodes of those muxes */
00777             inc_inode =
00778                 get_rr_node_index(x, y, chan_type, inc_track,
00779                                   rr_node_indices);
00780             dec_inode =
00781                 get_rr_node_index(x, y, chan_type, dec_track,
00782                                   rr_node_indices);
00783 
00784             /* Add to the list. */
00785             if(FALSE == rr_edge_done[inc_inode])
00786                 {
00787                     rr_edge_done[inc_inode] = TRUE;
00788                     *edge_list_ptr = insert_in_edge_list(*edge_list_ptr,
00789                                                          inc_inode,
00790                                                          seg_details
00791                                                          [inc_track].
00792                                                          opin_switch);
00793                     ++num_edges;
00794                 }
00795             if(FALSE == rr_edge_done[dec_inode])
00796                 {
00797                     rr_edge_done[dec_inode] = TRUE;
00798                     *edge_list_ptr = insert_in_edge_list(*edge_list_ptr,
00799                                                          dec_inode,
00800                                                          seg_details
00801                                                          [dec_track].
00802                                                          opin_switch);
00803                     ++num_edges;
00804                 }
00805         }
00806 
00807     if(inc_muxes)
00808         {
00809             free(inc_muxes);
00810             inc_muxes = NULL;
00811         }
00812     if(dec_muxes)
00813         {
00814             free(dec_muxes);
00815             dec_muxes = NULL;
00816         }
00817 
00818     return num_edges;
00819 }
00820 
00821 boolean
00822 is_cbox(INP int chan,
00823         INP int seg,
00824         INP int track,
00825         INP t_seg_details * seg_details,
00826         INP enum e_directionality directionality)
00827 {
00828 
00829     int start, length, ofs, fac, start_seg;
00830 
00831     fac = 1;
00832     if(UNI_DIRECTIONAL == directionality)
00833         {
00834             fac = 2;
00835         }
00836 
00837     start = seg_details[track].start;
00838     length = seg_details[track].length;
00839 
00840     /* Make sure they gave us correct start */
00841     start_seg = get_seg_start(seg_details, track, chan, seg);
00842 
00843     ofs = seg - start_seg;
00844 
00845     assert(ofs >= 0);
00846     assert(ofs < length);
00847 
00848     /* If unidir segment that is going backwards, we need to flip the ofs */
00849     if(DEC_DIRECTION == seg_details[track].direction)
00850         {
00851             ofs = (length - 1) - ofs;
00852         }
00853 
00854     return seg_details[track].cb[ofs];
00855 }
00856 
00857 
00858 static void
00859 load_chan_rr_indices(INP int nodes_per_chan,
00860                      INP int chan_len,
00861                      INP int num_chans,
00862                      INP t_rr_type type,
00863                      INP t_seg_details * seg_details,
00864                      INOUTP int *index,
00865                      INOUTP t_ivec *** indices)
00866 {
00867     int chan, seg, track, start, inode;
00868 
00869     indices[type] = (t_ivec **) my_malloc(sizeof(t_ivec *) * num_chans);
00870     for(chan = 0; chan < num_chans; ++chan)
00871         {
00872             indices[type][chan] =
00873                 (t_ivec *) my_malloc(sizeof(t_ivec) * chan_len);
00874 
00875             indices[type][chan][0].nelem = 0;
00876             indices[type][chan][0].list = NULL;
00877 
00878             for(seg = 1; seg < chan_len; ++seg)
00879                 {
00880                     /* Alloc the track inode lookup list */
00881                     indices[type][chan][seg].nelem = nodes_per_chan;
00882                     indices[type][chan][seg].list =
00883                         (int *)my_malloc(sizeof(int) * nodes_per_chan);
00884                     for(track = 0; track < nodes_per_chan; ++track)
00885                         {
00886                             indices[type][chan][seg].list[track] = OPEN;
00887                         }
00888                 }
00889         }
00890 
00891     for(chan = 0; chan < num_chans; ++chan)
00892         {
00893             for(seg = 1; seg < chan_len; ++seg)
00894                 {
00895                     /* Assign an inode to the starts of tracks */
00896                     for(track = 0; track < indices[type][chan][seg].nelem;
00897                         ++track)
00898                         {
00899                             start =
00900                                 get_seg_start(seg_details, track, chan, seg);
00901 
00902                             /* If the start of the wire doesn't have a inode, 
00903                              * assign one to it. */
00904                             inode = indices[type][chan][start].list[track];
00905                             if(OPEN == inode)
00906                                 {
00907                                     inode = *index;
00908                                     ++(*index);
00909 
00910                                     indices[type][chan][start].list[track] =
00911                                         inode;
00912                                 }
00913 
00914                             /* Assign inode of start of wire to current position */
00915                             indices[type][chan][seg].list[track] = inode;
00916                         }
00917                 }
00918         }
00919 }
00920 
00921 /** Allocates and loads all the structures needed for fast lookups of the   
00922  * index of an rr_node.  rr_node_indices is a matrix containing the index  
00923  * of the *first* rr_node at a given (i,j) location.                       
00924  */
00925 struct s_ivec ***
00926 alloc_and_load_rr_node_indices(INP int nodes_per_chan,
00927                                INP int nx,
00928                                INP int ny,
00929                                INOUTP int *index,
00930                                INP t_seg_details * seg_details)
00931 {
00932 
00933     int i, j, k, ofs;
00934     t_ivec ***indices;
00935     t_ivec tmp;
00936     t_type_ptr type;
00937 
00938     /* Alloc the lookup table */
00939     indices = (t_ivec ***) my_malloc(sizeof(t_ivec **) * NUM_RR_TYPES);
00940     indices[IPIN] = (t_ivec **) my_malloc(sizeof(t_ivec *) * (nx + 2));
00941     indices[SINK] = (t_ivec **) my_malloc(sizeof(t_ivec *) * (nx + 2));
00942     for(i = 0; i <= (nx + 1); ++i)
00943         {
00944             indices[IPIN][i] =
00945                 (t_ivec *) my_malloc(sizeof(t_ivec) * (ny + 2));
00946             indices[SINK][i] =
00947                 (t_ivec *) my_malloc(sizeof(t_ivec) * (ny + 2));
00948             for(j = 0; j <= (ny + 1); ++j)
00949                 {
00950                     indices[IPIN][i][j].nelem = 0;
00951                     indices[IPIN][i][j].list = NULL;
00952 
00953                     indices[SINK][i][j].nelem = 0;
00954                     indices[SINK][i][j].list = NULL;
00955                 }
00956         }
00957 
00958 
00959     /* Count indices for block nodes */
00960     for(i = 0; i <= (nx + 1); i++)
00961         {
00962             for(j = 0; j <= (ny + 1); j++)
00963                 {
00964                     ofs = grid[i][j].offset;
00965                     if(0 == ofs)
00966                         {
00967                             type = grid[i][j].type;
00968 
00969                             /* Load the pin class lookups. The ptc nums for SINK and SOURCE
00970                              * are disjoint so they can share the list. */
00971                             tmp.nelem = type->num_class;
00972                             tmp.list = NULL;
00973                             if(tmp.nelem > 0)
00974                                 {
00975                                     tmp.list =
00976                                         (int *)my_malloc(sizeof(int) *
00977                                                          tmp.nelem);
00978                                     for(k = 0; k < tmp.nelem; ++k)
00979                                         {
00980                                             tmp.list[k] = *index;
00981                                             ++(*index);
00982                                         }
00983                                 }
00984                             indices[SINK][i][j] = tmp;
00985 
00986                             /* Load the pin lookups. The ptc nums for IPIN and OPIN
00987                              * are disjoint so they can share the list. */
00988                             tmp.nelem = type->num_pins;
00989                             tmp.list = NULL;
00990                             if(tmp.nelem > 0)
00991                                 {
00992                                     tmp.list =
00993                                         (int *)my_malloc(sizeof(int) *
00994                                                          tmp.nelem);
00995                                     for(k = 0; k < tmp.nelem; ++k)
00996                                         {
00997                                             tmp.list[k] = *index;
00998                                             ++(*index);
00999                                         }
01000                                 }
01001                             indices[IPIN][i][j] = tmp;
01002                         }
01003                 }
01004         }
01005 
01006     /* Point offset blocks of a large block to base block */
01007     for(i = 0; i <= (nx + 1); i++)
01008         {
01009             for(j = 0; j <= (ny + 1); j++)
01010                 {
01011                     ofs = grid[i][j].offset;
01012                     if(ofs > 0)
01013                         {
01014                             /* NOTE: this only supports vertical large blocks */
01015                             indices[SINK][i][j] = indices[SINK][i][j - ofs];
01016                             indices[IPIN][i][j] = indices[IPIN][i][j - ofs];
01017                         }
01018                 }
01019         }
01020 
01021     /* SOURCE and SINK have unique ptc values so their data can be shared.
01022      * IPIN and OPIN have unique ptc values so their data can be shared. */
01023     indices[SOURCE] = indices[SINK];
01024     indices[OPIN] = indices[IPIN];
01025 
01026     /* Load the data for x and y channels */
01027     load_chan_rr_indices(nodes_per_chan, nx + 1, ny + 1, CHANX,
01028                          seg_details, index, indices);
01029     load_chan_rr_indices(nodes_per_chan, ny + 1, nx + 1, CHANY,
01030                          seg_details, index, indices);
01031 
01032     return indices;
01033 }
01034 
01035 
01036 /** This function must unallocate the structure allocated in 
01037  * alloc_and_load_rr_node_indices. 
01038  */
01039 void
01040 free_rr_node_indices(INP t_ivec *** rr_node_indices)
01041 {
01042         int i, j, ofs;
01043         for(i = 0; i <= (nx + 1); ++i)
01044         {
01045                 for(j = 0; j <= (ny + 1); ++j)
01046                 {
01047                         ofs = grid[i][j].offset;
01048                     if(ofs > 0)
01049                         {
01050                             /* Vertical large blocks reference is same as offset 0 */
01051                             rr_node_indices[SINK][i][j].list = NULL;
01052                                 rr_node_indices[IPIN][i][j].list = NULL;
01053                                 continue;
01054                         }
01055                         if(rr_node_indices[SINK][i][j].list != NULL) {
01056                                 free(rr_node_indices[SINK][i][j].list);
01057                         }
01058                         if(rr_node_indices[IPIN][i][j].list != NULL) {
01059                                 free(rr_node_indices[IPIN][i][j].list);
01060                         }
01061                 }
01062                 free(rr_node_indices[SINK][i]);
01063                 free(rr_node_indices[IPIN][i]);
01064         }
01065         free(rr_node_indices[SINK]);
01066         free(rr_node_indices[IPIN]);
01067 
01068         for(i = 0; i < (nx + 1); ++i)
01069         {
01070                 for(j = 0; j < (ny + 1); ++j)
01071                 {
01072                         if(rr_node_indices[CHANY][i][j].list != NULL) {
01073                                 free(rr_node_indices[CHANY][i][j].list);
01074                         }
01075                 }
01076                 free(rr_node_indices[CHANY][i]);
01077         }
01078         free(rr_node_indices[CHANY]);
01079 
01080         for(i = 0; i < (ny + 1); ++i)
01081         {
01082                 for(j = 0; j < (nx + 1); ++j)
01083                 {
01084                         if(rr_node_indices[CHANX][i][j].list != NULL) {
01085                                 free(rr_node_indices[CHANX][i][j].list);
01086                         }
01087                 }
01088                 free(rr_node_indices[CHANX][i]);
01089         }
01090         free(rr_node_indices[CHANX]);
01091 
01092         free(rr_node_indices);
01093 }
01094 
01095 /** Returns the index of the specified routing resource node.  (x,y) are    
01096  * the location within the FPGA, rr_type specifies the type of resource,    
01097  * and ptc gives the number of this resource.  ptc is the class number,   
01098  * pin number or track number, depending on what type of resource this      
01099  * is.  All ptcs start at 0 and go up to pins_per_clb-1 or the equivalent. 
01100  * The order within a clb is:  SOURCEs + SINKs (type->num_class of them); IPINs,  
01101  * and OPINs (pins_per_clb of them); CHANX; and CHANY (nodes_per_chan of    
01102  * each).  For (x,y) locations that point at pads the order is:  type->capacity     
01103  * occurances of SOURCE, SINK, OPIN, IPIN (one for each pad), then one      
01104  * associated channel (if there is a channel at (x,y)).  All IO pads are    
01105  * bidirectional, so while each will be used only as an INPAD or as an      
01106  * OUTPAD, all the switches necessary to do both must be in each pad.       
01107  *                                                                          
01108  * Note that for segments (CHANX and CHANY) of length > 1, the segment is   
01109  * given an rr_index based on the (x,y) location at which it starts (i.e.   
01110  * lowest (x,y) location at which this segment exists).                     
01111  * This routine also performs error checking to make sure the node in       
01112  * question exists.                                                         
01113  */
01114 int
01115 get_rr_node_index(int x,
01116                   int y,
01117                   t_rr_type rr_type,
01118                   int ptc,
01119                   t_ivec *** rr_node_indices)
01120 {
01121     int iclass, tmp;
01122     t_type_ptr type;
01123     t_ivec lookup;
01124 
01125     assert(ptc >= 0);
01126     assert(x >= 0 && x <= (nx + 1));
01127     assert(y >= 0 && y <= (ny + 1));
01128 
01129     type = grid[x][y].type;
01130 
01131     /* Currently need to swap x and y for CHANX because of chan, seg convention */
01132     if(CHANX == rr_type)
01133         {
01134             tmp = x;
01135             x = y;
01136             y = tmp;
01137         }
01138 
01139     /* Start of that block.  */
01140     lookup = rr_node_indices[rr_type][x][y];
01141 
01142     /* Check valid ptc num */
01143     assert(ptc >= 0);
01144     assert(ptc < lookup.nelem);
01145 
01146 #ifdef DEBUG
01147     switch (rr_type)
01148         {
01149         case SOURCE:
01150             assert(ptc < type->num_class);
01151             assert(type->class_inf[ptc].type == DRIVER);
01152             break;
01153 
01154         case SINK:
01155             assert(ptc < type->num_class);
01156             assert(type->class_inf[ptc].type == RECEIVER);
01157             break;
01158 
01159         case OPIN:
01160             assert(ptc < type->num_pins);
01161             iclass = type->pin_class[ptc];
01162             assert(type->class_inf[iclass].type == DRIVER);
01163             break;
01164 
01165         case IPIN:
01166             assert(ptc < type->num_pins);
01167             iclass = type->pin_class[ptc];
01168             assert(type->class_inf[iclass].type == RECEIVER);
01169             break;
01170 
01171         case CHANX:
01172         case CHANY:
01173             break;
01174 
01175         default:
01176             printf("Error:  Bad rr_node passed to get_rr_node_index.\n"
01177                    "Request for type=%d ptc=%d at (%d, %d).\n",
01178                    rr_type, ptc, x, y);
01179             exit(1);
01180         }
01181 #endif
01182 
01183     return lookup.list[ptc];
01184 }
01185 
01186 
01187 /** This counts the fan-out from wire segment (chan, seg, track) to blocks on either side */
01188 int
01189 get_track_to_ipins(int seg,
01190                    int chan,
01191                    int track,
01192                    t_linked_edge ** edge_list_ptr,
01193                    t_ivec *** rr_node_indices,
01194                    struct s_ivec ****track_to_ipin_lookup,
01195                    t_seg_details * seg_details,
01196                    enum e_rr_type chan_type,
01197                    int chan_length,
01198                    int wire_to_ipin_switch,
01199                    enum e_directionality directionality)
01200 {
01201     t_linked_edge *edge_list_head;
01202     int j, pass, iconn, phy_track, end, to_node, max_conn, ipin, side, x,
01203         y, num_conn;
01204     t_type_ptr type;
01205     int off;
01206 
01207     /* End of this wire */
01208     end = get_seg_end(seg_details, track, seg, chan, chan_length);
01209 
01210     edge_list_head = *edge_list_ptr;
01211     num_conn = 0;
01212 
01213     for(j = seg; j <= end; j++)
01214         {
01215             if(is_cbox(chan, j, track, seg_details, directionality))
01216                 {
01217                     for(pass = 0; pass < 2; ++pass)
01218                         {
01219                             if(CHANX == chan_type)
01220                                 {
01221                                     x = j;
01222                                     y = chan + pass;
01223                                     side = (0 == pass ? TOP : BOTTOM);
01224                                 }
01225                             else
01226                                 {
01227                                     assert(CHANY == chan_type);
01228                                     x = chan + pass;
01229                                     y = j;
01230                                     side = (0 == pass ? RIGHT : LEFT);
01231                                 }
01232 
01233                             /* PAJ - if the pointed to is an EMPTY then shouldn't look for ipins */
01234                             if(grid[x][y].type == EMPTY_TYPE)
01235                                 continue;
01236 
01237                             /* Move from logical (straight) to physical (twisted) track index 
01238                              * - algorithm assigns ipin connections to same physical track index
01239                              * so that the logical track gets distributed uniformly */
01240                             phy_track =
01241                                 vpr_to_phy_track(track, chan, j, seg_details,
01242                                                  directionality);
01243 
01244                             /* We need the type to find the ipin map for this type */
01245                             type = grid[x][y].type;
01246                             off = grid[x][y].offset;
01247 
01248                             max_conn =
01249                                 track_to_ipin_lookup[type->
01250                                                      index][phy_track][off]
01251                                 [side].nelem;
01252                             for(iconn = 0; iconn < max_conn; iconn++)
01253                                 {
01254                                     ipin =
01255                                         track_to_ipin_lookup[type->
01256                                                              index][phy_track]
01257                                         [off][side].list[iconn];
01258 
01259                                     /* Check there is a connection and Fc map isn't wrong */
01260                                     assert(type->pinloc[off][side][ipin]);
01261                                     assert(type->is_global_pin[ipin] ==
01262                                            FALSE);
01263 
01264                                     to_node =
01265                                         get_rr_node_index(x, y, IPIN, ipin,
01266                                                           rr_node_indices);
01267                                     edge_list_head =
01268                                         insert_in_edge_list(edge_list_head,
01269                                                             to_node,
01270                                                             wire_to_ipin_switch);
01271                                 }
01272                             num_conn += max_conn;
01273                         }
01274                 }
01275         }
01276 
01277     *edge_list_ptr = edge_list_head;
01278     return (num_conn);
01279 }
01280 
01281 
01282 /** Counts how many connections should be made from this segment to the y-   
01283  * segments in the adjacent channels at to_j.  It returns the number of     
01284  * connections, and updates edge_list_ptr to point at the head of the       
01285  * (extended) linked list giving the nodes to which this segment connects   
01286  * and the switch type used to connect to each.                             
01287  *                                                                          
01288  * An edge is added from this segment to a y-segment if:                    
01289  * - (1) this segment should have a switch box at that location, or           
01290  * - (2) the y-segment to which it would connect has a switch box, and the    
01291  *     switch type of that y-segment is unbuffered (bidirectional pass      
01292  *     transistor).                                                         
01293  *                                                                          
01294  * For bidirectional:                                                       
01295  * If the switch in each direction is a pass transistor (unbuffered), both  
01296  * switches are marked as being of the types of the larger (lower R) pass   
01297  * transistor.                                                              
01298  */
01299 int
01300 get_track_to_tracks(INP int from_chan,
01301                     INP int from_seg,
01302                     INP int from_track,
01303                     INP t_rr_type from_type,
01304                     INP int to_seg,
01305                     INP t_rr_type to_type,
01306                     INP int chan_len,
01307                     INP int nodes_per_chan,
01308                     INP int *opin_mux_size,
01309                     INP int Fs_per_side,
01310                     INP short *****sblock_pattern,
01311                     INOUTP struct s_linked_edge **edge_list,
01312                     INP t_seg_details * seg_details,
01313                     INP enum e_directionality directionality,
01314                     INP t_ivec *** rr_node_indices,
01315                     INOUTP boolean * rr_edge_done,
01316                     INP struct s_ivec ***switch_block_conn)
01317 {
01318     int num_conn;
01319     int from_switch, from_end, from_sb, from_first;
01320     int to_chan, to_sb;
01321     int start, end;
01322     struct s_ivec conn_tracks;
01323     boolean from_is_sbox, is_behind, Fs_clipped;
01324     enum e_side from_side_a, from_side_b, to_side;
01325 
01326     assert(from_seg ==
01327            get_seg_start(seg_details, from_track, from_chan, from_seg));
01328 
01329     from_switch = seg_details[from_track].wire_switch;
01330     from_end =
01331         get_seg_end(seg_details, from_track, from_seg, from_chan, chan_len);
01332     from_first = from_seg - 1;
01333 
01334     /* Figure out the sides of SB the from_wire will use */
01335     if(CHANX == from_type)
01336         {
01337             from_side_a = RIGHT;
01338             from_side_b = LEFT;
01339         }
01340     else
01341         {
01342             assert(CHANY == from_type);
01343             from_side_a = TOP;
01344             from_side_b = BOTTOM;
01345         }
01346 
01347     /* Figure out if the to_wire is connecting to a SB 
01348      * that is behind it. */
01349     is_behind = FALSE;
01350     if(to_type == from_type)
01351         {
01352             /* If inline, check that they only are trying
01353              * to connect at endpoints. */
01354             assert((to_seg == (from_end + 1)) || (to_seg == (from_seg - 1)));
01355             if(to_seg > from_end)
01356                 {
01357                     is_behind = TRUE;
01358                 }
01359         }
01360     else
01361         {
01362             /* If bending, check that they are adjacent to
01363              * our channel. */
01364             assert((to_seg == from_chan) || (to_seg == (from_chan + 1)));
01365             if(to_seg > from_chan)
01366                 {
01367                     is_behind = TRUE;
01368                 }
01369         }
01370 
01371     /* Figure out the side of SB the to_wires will use.
01372      * The to_seg and from_chan are in same direction. */
01373     if(CHANX == to_type)
01374         {
01375             to_side = (is_behind ? RIGHT : LEFT);
01376         }
01377     else
01378         {
01379             assert(CHANY == to_type);
01380             to_side = (is_behind ? TOP : BOTTOM);
01381         }
01382 
01383     /* Set the loop bounds */
01384     start = from_first;
01385     end = from_end;
01386 
01387     /* If we are connecting in same direction the connection is 
01388      * on one of the two sides so clip the bounds to the SB of
01389      * interest and proceed normally. */
01390     if(to_type == from_type)
01391         {
01392             start = (is_behind ? end : start);
01393             end = start;
01394         }
01395 
01396     /* Iterate over the SBs */
01397     num_conn = 0;
01398     for(from_sb = start; from_sb <= end; ++from_sb)
01399         {
01400             /* Figure out if we are at a sbox */
01401             from_is_sbox = is_sbox(from_chan, from_seg, from_sb, from_track,
01402                                    seg_details, directionality);
01403             /* end of wire must be an sbox */
01404             if(from_sb == from_end || from_sb == from_first)
01405                 {
01406                     from_is_sbox = TRUE;        /* Endpoints always default to true */
01407                 }
01408 
01409             /* to_chan is the current segment if different directions,
01410              * otherwise to_chan is the from_chan */
01411             to_chan = from_sb;
01412             to_sb = from_chan;
01413             if(from_type == to_type)
01414                 {
01415                     to_chan = from_chan;
01416                     to_sb = from_sb;
01417                 }
01418 
01419             /* Do the edges going to the left or down */
01420             if(from_sb < from_end)
01421                 {
01422                     if(BI_DIRECTIONAL == directionality)
01423                         {
01424                             conn_tracks =
01425                                 switch_block_conn[from_side_a][to_side]
01426                                 [from_track];
01427                             num_conn +=
01428                                 get_bidir_track_to_chan_seg(conn_tracks,
01429                                                             rr_node_indices,
01430                                                             to_chan, to_seg,
01431                                                             to_sb, to_type,
01432                                                             seg_details,
01433                                                             from_is_sbox,
01434                                                             from_switch,
01435                                                             rr_edge_done,
01436                                                             directionality,
01437                                                             edge_list);
01438                         }
01439                     if(UNI_DIRECTIONAL == directionality)
01440                         {
01441                             /* No fanout if no SB. */
01442                             /* We are connecting from the top or right of SB so it
01443                              * makes the most sense to only there from DEC_DIRECTION wires. */
01444                             if((from_is_sbox) &&
01445                                (DEC_DIRECTION ==
01446                                 seg_details[from_track].direction))
01447                                 {
01448                                     num_conn +=
01449                                         get_unidir_track_to_chan_seg((from_sb
01450                                                                       ==
01451                                                                       from_first),
01452                                                                      from_track,
01453                                                                      to_chan,
01454                                                                      to_seg,
01455                                                                      to_sb,
01456                                                                      to_type,
01457                                                                      nodes_per_chan,
01458                                                                      nx, ny,
01459                                                                      from_side_a,
01460                                                                      to_side,
01461                                                                      Fs_per_side,
01462                                                                      opin_mux_size,
01463                                                                      sblock_pattern,
01464                                                                      rr_node_indices,
01465                                                                      seg_details,
01466                                                                      rr_edge_done,
01467                                                                      &Fs_clipped,
01468                                                                      edge_list);
01469                                 }
01470                         }
01471                 }
01472 
01473             /* Do the edges going to the right or up */
01474             if(from_sb > from_first)
01475                 {
01476                     if(BI_DIRECTIONAL == directionality)
01477                         {
01478                             conn_tracks =
01479                                 switch_block_conn[from_side_b][to_side]
01480                                 [from_track];
01481                             num_conn +=
01482                                 get_bidir_track_to_chan_seg(conn_tracks,
01483                                                             rr_node_indices,
01484                                                             to_chan, to_seg,
01485                                                             to_sb, to_type,
01486                                                             seg_details,
01487                                                             from_is_sbox,
01488                                                             from_switch,
01489                                                             rr_edge_done,
01490                                                             directionality,
01491                                                             edge_list);
01492                         }
01493                     if(UNI_DIRECTIONAL == directionality)
01494                         {
01495                             /* No fanout if no SB. */
01496                             /* We are connecting from the bottom or left of SB so it
01497                              * makes the most sense to only there from INC_DIRECTION wires. */
01498                             if((from_is_sbox) &&
01499                                (INC_DIRECTION ==
01500                                 seg_details[from_track].direction))
01501                                 {
01502                                     num_conn +=
01503                                         get_unidir_track_to_chan_seg((from_sb
01504                                                                       ==
01505                                                                       from_end),
01506                                                                      from_track,
01507                                                                      to_chan,
01508                                                                      to_seg,
01509                                                                      to_sb,
01510                                                                      to_type,
01511                                                                      nodes_per_chan,
01512                                                                      nx, ny,
01513                                                                      from_side_b,
01514                                                                      to_side,
01515                                                                      Fs_per_side,
01516                                                                      opin_mux_size,
01517                                                                      sblock_pattern,
01518                                                                      rr_node_indices,
01519                                                                      seg_details,
01520                                                                      rr_edge_done,
01521                                                                      &Fs_clipped,
01522                                                                      edge_list);
01523                                 }
01524                         }
01525                 }
01526         }
01527 
01528     return num_conn;
01529 }
01530 
01531 
01532 
01533 static int
01534 get_bidir_track_to_chan_seg(INP struct s_ivec conn_tracks,
01535                             INP t_ivec *** rr_node_indices,
01536                             INP int to_chan,
01537                             INP int to_seg,
01538                             INP int to_sb,
01539                             INP t_rr_type to_type,
01540                             INP t_seg_details * seg_details,
01541                             INP boolean from_is_sbox,
01542                             INP int from_switch,
01543                             INOUTP boolean * rr_edge_done,
01544                             INP enum e_directionality directionality,
01545                             INOUTP struct s_linked_edge **edge_list)
01546 {
01547     int iconn, to_track, to_node, to_switch, num_conn, to_x, to_y, i;
01548     boolean to_is_sbox;
01549     short switch_types[2];
01550 
01551     /* x, y coords for get_rr_node lookups */
01552     if(CHANX == to_type)
01553         {
01554             to_x = to_seg;
01555             to_y = to_chan;
01556         }
01557     else
01558         {
01559             assert(CHANY == to_type);
01560             to_x = to_chan;
01561             to_y = to_seg;
01562         }
01563 
01564     /* Go through the list of tracks we can connect to */
01565     num_conn = 0;
01566     for(iconn = 0; iconn < conn_tracks.nelem; ++iconn)
01567         {
01568             to_track = conn_tracks.list[iconn];
01569             to_node = get_rr_node_index(to_x, to_y, to_type, to_track,
01570                                         rr_node_indices);
01571 
01572             /* Skip edge if already done */
01573             if(rr_edge_done[to_node])
01574                 {
01575                     continue;
01576                 }
01577 
01578             /* Get the switches for any edges between the two tracks */
01579             to_switch = seg_details[to_track].wire_switch;
01580 
01581             to_is_sbox = is_sbox(to_chan, to_seg, to_sb, to_track,
01582                                  seg_details, directionality);
01583             get_switch_type(from_is_sbox, to_is_sbox,
01584                             from_switch, to_switch, switch_types);
01585 
01586             /* There are up to two switch edges allowed from track to track */
01587             for(i = 0; i < 2; ++i)
01588                 {
01589                     /* If the switch_type entry is empty, skip it */
01590                     if(OPEN == switch_types[i])
01591                         {
01592                             continue;
01593                         }
01594 
01595                     /* Add the edge to the list */
01596                     *edge_list = insert_in_edge_list(*edge_list,
01597                                                      to_node,
01598                                                      switch_types[i]);
01599                     /* Mark the edge as now done */
01600                     rr_edge_done[to_node] = TRUE;
01601                     ++num_conn;
01602                 }
01603         }
01604 
01605     return num_conn;
01606 }
01607 
01608 static int
01609 get_unidir_track_to_chan_seg(INP boolean is_end_sb,
01610                              INP int from_track,
01611                              INP int to_chan,
01612                              INP int to_seg,
01613                              INP int to_sb,
01614                              INP t_rr_type to_type,
01615                              INP int nodes_per_chan,
01616                              INP int nx,
01617                              INP int ny,
01618                              INP enum e_side from_side,
01619                              INP enum e_side to_side,
01620                              INP int Fs_per_side,
01621                              INP int *opin_mux_size,
01622                              INP short *****sblock_pattern,
01623                              INP t_ivec *** rr_node_indices,
01624                              INP t_seg_details * seg_details,
01625                              INOUTP boolean * rr_edge_done,
01626                              OUTP boolean * Fs_clipped,
01627                              INOUTP struct s_linked_edge **edge_list)
01628 {
01629     int to_track, to_mux, to_node, to_x, to_y, i, max_len, num_labels;
01630     int sb_x, sb_y, count;
01631     int *mux_labels = NULL;
01632     enum e_direction to_dir;
01633     boolean is_fringe, is_core, is_corner, is_straight;
01634 
01635     /* x, y coords for get_rr_node lookups */
01636     if(CHANX == to_type)
01637         {
01638             to_x = to_seg;
01639             to_y = to_chan;
01640             sb_x = to_sb;
01641             sb_y = to_chan;
01642             max_len = nx;
01643         }
01644     else
01645         {
01646             assert(CHANY == to_type);
01647             to_x = to_chan;
01648             to_y = to_seg;
01649             sb_x = to_chan;
01650             sb_y = to_sb;
01651             max_len = ny;
01652         }
01653 
01654 
01655     to_dir = DEC_DIRECTION;
01656     if(to_sb < to_seg)
01657         {
01658             to_dir = INC_DIRECTION;
01659         }
01660 
01661     *Fs_clipped = FALSE;
01662 
01663     /* SBs go from (0, 0) to (nx, ny) */
01664     is_corner = ((sb_x < 1) || (sb_x >= nx)) && ((sb_y < 1) || (sb_y >= ny));
01665     is_fringe = (FALSE == is_corner) && ((sb_x < 1) || (sb_y < 1)
01666                                          || (sb_x >= nx) || (sb_y >= ny));
01667     is_core = (FALSE == is_corner) && (FALSE == is_fringe);
01668     is_straight = (from_side == RIGHT && to_side == LEFT) ||
01669         (from_side == LEFT && to_side == RIGHT) ||
01670         (from_side == TOP && to_side == BOTTOM) ||
01671         (from_side == BOTTOM && to_side == TOP);
01672 
01673     /* Ending wires use N-to-N mapping if not fringe or if goes straight */
01674     if(is_end_sb && (is_core || is_corner || is_straight))
01675         {
01676             /* Get the list of possible muxes for the N-to-N mapping. */
01677             mux_labels = label_wire_muxes(to_chan, to_seg, seg_details,
01678                                           max_len, to_dir, nodes_per_chan,
01679                                           &num_labels);
01680         }
01681     else
01682         {
01683             assert(is_fringe || !is_end_sb);
01684 
01685             mux_labels = label_wire_muxes_for_balance(to_chan, to_seg,
01686                                                       seg_details, max_len,
01687                                                       to_dir, nodes_per_chan,
01688                                                       &num_labels, to_type,
01689                                                       opin_mux_size,
01690                                                       rr_node_indices);
01691         }
01692 
01693     /* Can't connect if no muxes. */
01694     if(num_labels < 1)
01695         {
01696             if(mux_labels)
01697                 {
01698                     free(mux_labels);
01699                     mux_labels = NULL;
01700                 }
01701             return 0;
01702         }
01703 
01704     /* Check if Fs demand was too high. */
01705     if(Fs_per_side > num_labels)
01706         {
01707             *Fs_clipped = TRUE;
01708         }
01709 
01710     /* Get the target label */
01711     to_mux = sblock_pattern[sb_x][sb_y][from_side][to_side][from_track];
01712     assert(to_mux != UN_SET);
01713 
01714     /* Handle Fs > 3 but assigning consecutive muxes. */
01715     count = 0;
01716     for(i = 0; i < Fs_per_side; ++i)
01717         {
01718             /* Use the balanced labeling for passing and fringe wires */
01719             to_track = mux_labels[(to_mux + i) % num_labels];
01720             to_node =
01721                 get_rr_node_index(to_x, to_y, to_type, to_track,
01722                                   rr_node_indices);
01723 
01724             /* Add edge to list. */
01725             if(FALSE == rr_edge_done[to_node])
01726                 {
01727                     rr_edge_done[to_node] = TRUE;
01728                     *edge_list =
01729                         insert_in_edge_list(*edge_list, to_node,
01730                                             seg_details[to_track].
01731                                             wire_switch);
01732                     ++count;
01733                 }
01734         }
01735 
01736     if(mux_labels)
01737         {
01738             free(mux_labels);
01739             mux_labels = NULL;
01740         }
01741 
01742     return count;
01743 }
01744 
01745 boolean
01746 is_sbox(INP int chan,
01747         INP int wire_seg,
01748         INP int sb_seg,
01749         INP int track,
01750         INP t_seg_details * seg_details,
01751         INP enum e_directionality directionality)
01752 {
01753 
01754     int start, length, ofs, fac;
01755 
01756     fac = 1;
01757     if(UNI_DIRECTIONAL == directionality)
01758         {
01759             fac = 2;
01760         }
01761 
01762     start = seg_details[track].start;
01763     length = seg_details[track].length;
01764 
01765     /* Make sure they gave us correct start */
01766     wire_seg = get_seg_start(seg_details, track, chan, wire_seg);
01767 
01768     ofs = sb_seg - wire_seg + 1;        /* Ofset 0 is behind us, so add 1 */
01769 
01770     assert(ofs >= 0);
01771     assert(ofs < (length + 1));
01772 
01773     /* If unidir segment that is going backwards, we need to flip the ofs */
01774     if((ofs % fac) > 0)
01775         {
01776             ofs = length - ofs;
01777         }
01778 
01779     return seg_details[track].sb[ofs];
01780 }
01781 
01782 
01783 /** This routine looks at whether the from_node and to_node want a switch,  
01784  * and what type of switch is used to connect *to* each type of node       
01785  * (from_node_switch and to_node_switch).  It decides what type of switch, 
01786  * if any, should be used to go from from_node to to_node.  If no switch   
01787  * should be inserted (i.e. no connection), it returns OPEN.  Its returned 
01788  * values are in the switch_types array.  It needs to return an array      
01789  * because one topology (a buffer in the forward direction and a pass      
01790  * transistor in the backward direction) results in *two* switches.        
01791  */
01792 static void
01793 get_switch_type(boolean is_from_sbox,
01794                 boolean is_to_sbox,
01795                 short from_node_switch,
01796                 short to_node_switch,
01797                 short switch_types[2])
01798 {
01799 
01800 
01801     boolean forward_pass_trans;
01802     boolean backward_pass_trans;
01803     int used, min, max;
01804 
01805     switch_types[0] = OPEN;     /* No switch */
01806     switch_types[1] = OPEN;
01807     used = 0;
01808     forward_pass_trans = FALSE;
01809     backward_pass_trans = FALSE;
01810 
01811     /* Connect forward if we are a sbox */
01812     if(is_from_sbox)
01813         {
01814             switch_types[used] = to_node_switch;
01815             if(FALSE == switch_inf[to_node_switch].buffered)
01816                 {
01817                     forward_pass_trans = TRUE;
01818                 }
01819             ++used;
01820         }
01821 
01822     /* Check for pass_trans coming backwards */
01823     if(is_to_sbox)
01824         {
01825             if(FALSE == switch_inf[from_node_switch].buffered)
01826                 {
01827                     switch_types[used] = from_node_switch;
01828                     backward_pass_trans = TRUE;
01829                     ++used;
01830                 }
01831         }
01832 
01833     /* Take the larger pass trans if there are two */
01834     if(forward_pass_trans && backward_pass_trans)
01835         {
01836             min = min(to_node_switch, from_node_switch);
01837             max = max(to_node_switch, from_node_switch);
01838 
01839             /* Take the smaller index unless the other 
01840              * pass_trans is bigger (smaller R). */
01841             switch_types[used] = min;
01842             if(switch_inf[max].R < switch_inf[min].R)
01843                 {
01844                     switch_types[used] = max;
01845                 }
01846             ++used;
01847         }
01848 }
01849 
01850 static int
01851 vpr_to_phy_track(INP int itrack,
01852                  INP int chan_num,
01853                  INP int seg_num,
01854                  INP t_seg_details * seg_details,
01855                  INP enum e_directionality directionality)
01856 {
01857     int group_start, group_size;
01858     int vpr_offset_for_first_phy_track;
01859     int vpr_offset, phy_offset;
01860     int phy_track;
01861     int fac;
01862 
01863     /* Assign in pairs if unidir. */
01864     fac = 1;
01865     if(UNI_DIRECTIONAL == directionality)
01866         {
01867             fac = 2;
01868         }
01869 
01870     group_start = seg_details[itrack].group_start;
01871     group_size = seg_details[itrack].group_size;
01872 
01873     vpr_offset_for_first_phy_track =
01874         (chan_num + seg_num - 1) % (group_size / fac);
01875     vpr_offset = (itrack - group_start) / fac;
01876     phy_offset =
01877         (vpr_offset_for_first_phy_track + vpr_offset) % (group_size / fac);
01878     phy_track =
01879         group_start + (fac * phy_offset) + (itrack - group_start) % fac;
01880 
01881     return phy_track;
01882 }
01883 
01884 
01885 
01886 short *****
01887 alloc_sblock_pattern_lookup(INP int nx,
01888                             INP int ny,
01889                             INP int nodes_per_chan)
01890 {
01891     int i, j, from_side, to_side, itrack, items;
01892     short *****result;
01893     short *****i_list;
01894     short ****j_list;
01895     short ***from_list;
01896     short **to_list;
01897     short *track_list;
01898 
01899     /* loading up the sblock connection pattern matrix. It's a huge matrix because
01900      * for nonquantized W, it's impossible to make simple permutations to figure out
01901      * where muxes are and how to connect to them such that their sizes are balanced */
01902 
01903     /* Do chunked allocations to make freeing easier, speed up malloc and free, and
01904      * reduce some of the memory overhead. Could use fewer malloc's but this way
01905      * avoids all considerations of pointer sizes and allignment. */
01906 
01907     /* Alloc each list of pointers in one go. items is a running product that increases
01908      * with each new dimension of the matrix. */
01909     items = 1;
01910     items *= (nx + 1);
01911     i_list = (short *****)my_malloc(sizeof(short ****) * items);
01912     items *= (ny + 1);
01913     j_list = (short ****)my_malloc(sizeof(short ***) * items);
01914     items *= (4);
01915     from_list = (short ***)my_malloc(sizeof(short **) * items);
01916     items *= (4);
01917     to_list = (short **)my_malloc(sizeof(short *) * items);
01918     items *= (nodes_per_chan);
01919     track_list = (short *)my_malloc(sizeof(short) * items);
01920 
01921     /* Build the pointer lists to form the multidimensional array */
01922     result = i_list;
01923     i_list += (nx + 1);         /* Skip forward nx+1 items */
01924     for(i = 0; i < (nx + 1); ++i)
01925         {
01926 
01927             result[i] = j_list;
01928             j_list += (ny + 1); /* Skip forward ny+1 items */
01929             for(j = 0; j < (ny + 1); ++j)
01930                 {
01931 
01932                     result[i][j] = from_list;
01933                     from_list += (4);   /* Skip forward 4 items */
01934                     for(from_side = 0; from_side < 4; ++from_side)
01935                         {
01936 
01937                             result[i][j][from_side] = to_list;
01938                             to_list += (4);     /* Skip forward 4 items */
01939                             for(to_side = 0; to_side < 4; ++to_side)
01940                                 {
01941 
01942                                     result[i][j][from_side][to_side] =
01943                                         track_list;
01944                                     track_list += (nodes_per_chan);     /* Skip forward nodes_per_chan items */
01945                                     for(itrack = 0; itrack < nodes_per_chan;
01946                                         itrack++)
01947                                         {
01948 
01949                                             /* Set initial value to be unset */
01950                                             result[i][j][from_side][to_side]
01951                                                 [itrack] = UN_SET;
01952                                         }
01953                                 }
01954                         }
01955                 }
01956         }
01957 
01958     /* This is the outer pointer to the full matrix */
01959     return result;
01960 }
01961 
01962 /** This free function corresponds to the chunked matrix 
01963  * allocation above and there should only be one free
01964  * call for each dimension. 
01965  */
01966 void
01967 free_sblock_pattern_lookup(INOUTP short *****sblock_pattern)
01968 {
01969     /* Free dimensions from the inner one, outwards so
01970      * we can still access them. The comments beside
01971      * each one indicate the corresponding name used when
01972      * allocating them. */
01973     free(****sblock_pattern);   /* track_list */
01974     free(***sblock_pattern);    /* to_list */
01975     free(**sblock_pattern);     /* from_list */
01976     free(*sblock_pattern);      /* j_list */
01977     free(sblock_pattern);       /* i_list */
01978 }
01979 
01980 /** This routine loads a lookup table for sblock topology. The lookup table is huge
01981  * because the sblock varies from location to location. The i, j means the owning
01982  * location of the sblock under investigation. 
01983  */
01984 void
01985 load_sblock_pattern_lookup(INP int i,
01986                            INP int j,
01987                            INP int nodes_per_chan,
01988                            INP t_seg_details * seg_details,
01989                            INP int Fs,
01990                            INP enum e_switch_block_type switch_block_type,
01991                            INOUTP short *****sblock_pattern)
01992 {
01993 
01994     int side_cw_incoming_wire_count, side_ccw_incoming_wire_count,
01995         opp_incoming_wire_count;
01996     int to_side, side, side_cw, side_ccw, side_opp, itrack;
01997     int Fs_per_side, chan, seg, chan_len, sb_seg;
01998     boolean is_core_sblock, is_corner_sblock, x_edge, y_edge;
01999     int *incoming_wire_label[4];
02000     int *wire_mux_on_track[4];
02001     int num_incoming_wires[4];
02002     int num_ending_wires[4];
02003     int num_wire_muxes[4];
02004     boolean skip, vert, pos_dir;
02005     enum e_direction dir;
02006 
02007     Fs_per_side = 1;
02008     if(Fs != -1)
02009         {
02010             Fs_per_side = Fs / 3;
02011         }
02012 
02013     /* SB's have coords from (0, 0) to (nx, ny) */
02014     assert(i >= 0);
02015     assert(i <= nx);
02016     assert(j >= 0);
02017     assert(j <= ny);
02018 
02019     /* May 12 - 15, 2007
02020      *
02021      * I identify three types of sblocks in the chip: 1) The core sblock, whose special
02022      * property is that the number of muxes (and ending wires) on each side is the same (very useful
02023      * property, since it leads to a N-to-N assignment problem with ending wires). 2) The corner sblock
02024      * which is same as a L=1 core sblock with 2 sides only (again N-to-N assignment problem). 3) The
02025      * fringe / chip edge sblock which is most troublesome, as balance in each side of muxes is 
02026      * attainable but balance in the entire sblock is not. The following code first identifies the
02027      * incoming wires, which can be classified into incoming passing wires with sbox and incoming
02028      * ending wires (the word "incoming" is sometimes dropped for ease of discussion). It appropriately 
02029      * labels all the wires on each side by the following order: By the call to label_incoming_wires, 
02030      * which labels for one side, the order is such that the incoming ending wires (always with sbox) 
02031      * are labelled first 0,1,2,... p-1, then the incoming passing wires with sbox are labelled 
02032      * p,p+1,p+2,... k-1 (for total of k). By this convention, one can easily distinguish the ending
02033      * wires from the passing wires by checking a label against num_ending_wires variable. 
02034      *
02035      * After labelling all the incoming wires, this routine labels the muxes on the side we're currently
02036      * connecting to (iterated for four sides of the sblock), called the to_side. The label scheme is
02037      * the natural order of the muxes by their track #. Also we find the number of muxes.
02038      *
02039      * For each to_side, the total incoming wires that connect to the muxes on to_side 
02040      * come from three sides: side_1 (to_side's right), side_2 (to_side's left) and opp_side.
02041      * The problem of balancing mux size is then: considering all incoming passing wires
02042      * with sbox on side_1, side_2 and opp_side, how to assign them to the muxes on to_side
02043      * (with specified Fs) in a way that mux size is imbalanced by at most 1. I solve this
02044      * problem by this approach: the first incoming passing wire will connect to 0, 1, 2, 
02045      * ..., Fs_per_side - 1, then the next incoming passing wire will connect to 
02046      * Fs_per_side, Fs_per_side+1, ..., Fs_per_side*2-1, and so on. This consistent STAGGERING
02047      * ensures N-to-N assignment is perfectly balanced and M-to-N assignment is imbalanced by no
02048      * more than 1.
02049      *
02050      * For the sblock_pattern_init_mux_lookup lookup table, I will only need the lookup
02051      * table to remember the first/init mux to connect, since the convention is Fs_per_side consecutive
02052      * muxes to connect. Then how do I determine the order of the incoming wires? I use the labels
02053      * on side_1, then labels on side_2, then labels on opp_side. Effectively I listed all
02054      * incoming passing wires from the three sides, and order them to each make Fs_per_side
02055      * consecutive connections to muxes, and use % to rotate to keep imbalance at most 1. 
02056      */
02057 
02058     /* SB's range from (0, 0) to (nx, ny) */
02059     /* First find all four sides' incoming wires */
02060     x_edge = ((i < 1) || (i >= nx));
02061     y_edge = ((j < 1) || (j >= ny));
02062 
02063     is_corner_sblock = (x_edge && y_edge);
02064     is_core_sblock = (!x_edge && !y_edge);
02065 
02066     /* "Label" the wires around the switch block by connectivity. */
02067     for(side = 0; side < 4; ++side)
02068         {
02069             /* Assume the channel segment doesn't exist. */
02070             wire_mux_on_track[side] = NULL;
02071             incoming_wire_label[side] = NULL;
02072             num_incoming_wires[side] = 0;
02073             num_ending_wires[side] = 0;
02074             num_wire_muxes[side] = 0;
02075 
02076             /* Skip the side and leave the zero'd value if the
02077              * channel segment doesn't exist. */
02078             skip = TRUE;
02079             switch (side)
02080                 {
02081                 case TOP:
02082                     if(j < ny)
02083                         {
02084                             skip = FALSE;
02085                         };
02086                     break;
02087                 case RIGHT:
02088                     if(i < nx)
02089                         {
02090                             skip = FALSE;
02091                         }
02092                     break;
02093                 case BOTTOM:
02094                     if(j > 0)
02095                         {
02096                             skip = FALSE;
02097                         }
02098                     break;
02099                 case LEFT:
02100                     if(i > 0)
02101                         {
02102                             skip = FALSE;
02103                         }
02104                     break;
02105                 }
02106             if(skip)
02107                 {
02108                     continue;
02109                 }
02110 
02111             /* Figure out the channel and segment for a certain direction */
02112             vert = ((side == TOP) || (side == BOTTOM));
02113             pos_dir = ((side == TOP) || (side == RIGHT));
02114             chan = (vert ? i : j);
02115             sb_seg = (vert ? j : i);
02116             seg = (pos_dir ? (sb_seg + 1) : sb_seg);
02117             chan_len = (vert ? ny : nx);
02118 
02119             /* Figure out all the tracks on a side that are ending and the
02120              * ones that are passing through and have a SB. */
02121             dir = (pos_dir ? DEC_DIRECTION : INC_DIRECTION);
02122             incoming_wire_label[side] =
02123                 label_incoming_wires(chan, seg, sb_seg, seg_details, chan_len,
02124                                      dir, nodes_per_chan,
02125                                      &num_incoming_wires[side],
02126                                      &num_ending_wires[side]);
02127 
02128             /* Figure out all the tracks on a side that are starting. */
02129             dir = (pos_dir ? INC_DIRECTION : DEC_DIRECTION);
02130             wire_mux_on_track[side] = label_wire_muxes(chan, seg,
02131                                                        seg_details, chan_len,
02132                                                        dir, nodes_per_chan,
02133                                                        &num_wire_muxes[side]);
02134         }
02135 
02136     for(to_side = 0; to_side < 4; to_side++)
02137         {
02138             /* Can't do anything if no muxes on this side. */
02139             if(0 == num_wire_muxes[to_side])
02140                 {
02141                     continue;
02142                 }
02143 
02144             /* Figure out side rotations */
02145             assert((TOP == 0) && (RIGHT == 1) && (BOTTOM == 2)
02146                    && (LEFT == 3));
02147             side_cw = (to_side + 1) % 4;
02148             side_opp = (to_side + 2) % 4;
02149             side_ccw = (to_side + 3) % 4;
02150 
02151             /* For the core sblock:
02152              * The new order for passing wires should appear as
02153              * 0,1,2..,scw-1, for passing wires with sbox on side_cw 
02154              * scw,scw+1,...,sccw-1, for passing wires with sbox on side_ccw
02155              * sccw,sccw+1,... for passing wires with sbox on side_opp.
02156              * This way, I can keep the imbalance to at most 1.
02157              *
02158              * For the fringe sblocks, I don't distinguish between
02159              * passing and ending wires so the above statement still holds
02160              * if you replace "passing" by "incoming" */
02161 
02162             side_cw_incoming_wire_count = 0;
02163             if(incoming_wire_label[side_cw])
02164                 {
02165                     for(itrack = 0; itrack < nodes_per_chan; itrack++)
02166                         {
02167                             /* Ending wire, or passing wire with sbox. */
02168                             if(incoming_wire_label[side_cw][itrack] != UN_SET)
02169                                 {
02170 
02171                                     if((is_corner_sblock || is_core_sblock) &&
02172                                        (incoming_wire_label[side_cw][itrack] <
02173                                         num_ending_wires[side_cw]))
02174                                         {
02175                                             /* The ending wires in core sblocks form N-to-N assignment 
02176                                              * problem, so can use any pattern such as Wilton. This N-to-N 
02177                                              * mapping depends on the fact that start points stagger across
02178                                              * channels. */
02179                                             assert(num_ending_wires[side_cw]
02180                                                    ==
02181                                                    num_wire_muxes[to_side]);
02182                                             sblock_pattern[i][j][side_cw]
02183                                                 [to_side][itrack] =
02184                                                 get_simple_switch_block_track
02185                                                 (side_cw, to_side,
02186                                                  incoming_wire_label[side_cw]
02187                                                  [itrack], switch_block_type,
02188                                                  num_wire_muxes[to_side]);
02189 
02190                                         }
02191                                     else
02192                                         {
02193 
02194                                             /* These are passing wires with sbox only for core sblocks
02195                                              * or passing and ending wires (for fringe cases). */
02196                                             sblock_pattern[i][j][side_cw]
02197                                                 [to_side][itrack] =
02198                                                 (side_cw_incoming_wire_count *
02199                                                  Fs_per_side) %
02200                                                 num_wire_muxes[to_side];
02201                                             side_cw_incoming_wire_count++;
02202                                         }
02203                                 }
02204                         }
02205                 }
02206 
02207 
02208             side_ccw_incoming_wire_count = 0;
02209             for(itrack = 0; itrack < nodes_per_chan; itrack++)
02210                 {
02211 
02212                     /* if that side has no channel segment skip it */
02213                     if(incoming_wire_label[side_ccw] == NULL)
02214                         break;
02215 
02216                     /* not ending wire nor passing wire with sbox */
02217                     if(incoming_wire_label[side_ccw][itrack] != UN_SET)
02218                         {
02219 
02220                             if((is_corner_sblock || is_core_sblock) &&
02221                                (incoming_wire_label[side_ccw][itrack] <
02222                                 num_ending_wires[side_ccw]))
02223                                 {
02224                                     /* The ending wires in core sblocks form N-to-N assignment problem, so can
02225                                      * use any pattern such as Wilton */
02226                                     assert(incoming_wire_label[side_ccw]
02227                                            [itrack] <
02228                                            num_wire_muxes[to_side]);
02229                                     sblock_pattern[i][j][side_ccw][to_side]
02230                                         [itrack] =
02231                                         get_simple_switch_block_track
02232                                         (side_ccw, to_side,
02233                                          incoming_wire_label[side_ccw]
02234                                          [itrack], switch_block_type,
02235                                          num_wire_muxes[to_side]);
02236                                 }
02237                             else
02238                                 {
02239 
02240                                     /* These are passing wires with sbox only for core sblocks
02241                                      * or passing and ending wires (for fringe cases). */
02242                                     sblock_pattern[i][j][side_ccw][to_side]
02243                                         [itrack] =
02244                                         ((side_ccw_incoming_wire_count +
02245                                           side_cw_incoming_wire_count) *
02246                                          Fs_per_side) %
02247                                         num_wire_muxes[to_side];
02248                                     side_ccw_incoming_wire_count++;
02249                                 }
02250                         }
02251                 }
02252 
02253 
02254             opp_incoming_wire_count = 0;
02255             if(incoming_wire_label[side_opp])
02256                 {
02257                     for(itrack = 0; itrack < nodes_per_chan; itrack++)
02258                         {
02259                             /* not ending wire nor passing wire with sbox */
02260                             if(incoming_wire_label[side_opp][itrack] !=
02261                                UN_SET)
02262                                 {
02263 
02264                                     /* corner sblocks for sure have no opposite channel segments so don't care about them */
02265                                     if(is_core_sblock)
02266                                         {
02267                                             if(incoming_wire_label[side_opp]
02268                                                [itrack] <
02269                                                num_ending_wires[side_opp])
02270                                                 {
02271                                                     /* The ending wires in core sblocks form N-to-N assignment problem, so can
02272                                                      * use any pattern such as Wilton */
02273                                                     /* In the direct connect case, I know for sure the init mux is at the same track #
02274                                                      * as this ending wire, but still need to find the init mux label for Fs > 3 */
02275                                                     sblock_pattern[i][j]
02276                                                         [side_opp][to_side]
02277                                                         [itrack] =
02278                                                         find_label_of_track
02279                                                         (wire_mux_on_track
02280                                                          [to_side],
02281                                                          num_wire_muxes
02282                                                          [to_side], itrack);
02283                                                 }
02284                                             else
02285                                                 {
02286                                                     /* These are passing wires with sbox for core sblocks */
02287                                                     sblock_pattern[i][j]
02288                                                         [side_opp][to_side]
02289                                                         [itrack] =
02290                                                         ((side_ccw_incoming_wire_count + side_cw_incoming_wire_count) * Fs_per_side + opp_incoming_wire_count * (Fs_per_side - 1)) % num_wire_muxes[to_side];
02291                                                     opp_incoming_wire_count++;
02292                                                 }
02293                                         }
02294                                     else
02295                                         {
02296                                             if(incoming_wire_label[side_opp]
02297                                                [itrack] <
02298                                                num_ending_wires[side_opp])
02299                                                 {
02300                                                     sblock_pattern[i][j]
02301                                                         [side_opp][to_side]
02302                                                         [itrack] =
02303                                                         find_label_of_track
02304                                                         (wire_mux_on_track
02305                                                          [to_side],
02306                                                          num_wire_muxes
02307                                                          [to_side], itrack);
02308                                                 }
02309                                             else
02310                                                 {
02311                                                     /* These are passing wires with sbox for fringe sblocks */
02312                                                     sblock_pattern[i][j]
02313                                                         [side_opp][to_side]
02314                                                         [itrack] =
02315                                                         ((side_ccw_incoming_wire_count + side_cw_incoming_wire_count) * Fs_per_side + opp_incoming_wire_count * (Fs_per_side - 1)) % num_wire_muxes[to_side];
02316                                                     opp_incoming_wire_count++;
02317                                                 }
02318                                         }
02319                                 }
02320                         }
02321                 }
02322         }
02323 
02324     for(side = 0; side < 4; ++side)
02325         {
02326             if(incoming_wire_label[side])
02327                 {
02328                     free(incoming_wire_label[side]);
02329                 }
02330             if(wire_mux_on_track[side])
02331                 {
02332                     free(wire_mux_on_track[side]);
02333                 }
02334         }
02335 }
02336 
02337 /** Labels the muxes on that side (seg_num, chan_num, direction). The returned array
02338  * maps a label to the actual track #: array[0] = <the track number of the first mux> 
02339  */
02340 static int *
02341 label_wire_muxes_for_balance(INP int chan_num,
02342                              INP int seg_num,
02343                              INP t_seg_details * seg_details,
02344                              INP int max_len,
02345                              INP enum e_direction direction,
02346                              INP int nodes_per_chan,
02347                              INP int *num_wire_muxes,
02348                              INP t_rr_type chan_type,
02349                              INP int *opin_mux_size,
02350                              INP t_ivec *** rr_node_indices)
02351 {
02352 
02353     /* Sblock (aka wire2mux) pattern generation occurs after opin2mux connections have been 
02354      * made. Since opin2muxes are done with a pattern with which I guarantee imbalance of at most 1 due 
02355      * to them, we will observe that, for each side of an sblock some muxes have one fewer size 
02356      * than the others, considering only the contribution from opins. I refer to these muxes as "holes"
02357      * as they have one fewer opin connection going to them than the rest (like missing one electron)*/
02358 
02359     /* Before May 14, I was labelling wire muxes in the natural order of their track # (lowest first). 
02360      * Now I want to label wire muxes like this: first label the holes in order of their track #,
02361      * then label the non-holes in order of their track #. This way the wire2mux generation will 
02362      * not overlap its own "holes" with the opin "holes", thus creating imbalance greater than 1. */
02363 
02364     /* The best approach in sblock generation is do one assignment of all incoming wires from 3 other
02365      * sides to the muxes on the fourth side, connecting the "opin hole" muxes first (i.e. filling
02366      * the holes) then the rest -> this means after all opin2mux and wire2mux connections the 
02367      * mux size imbalance on one side is at most 1. The mux size imbalance in one sblock is thus
02368      * also one, since the number of muxes per side is identical for all four sides, and they number
02369      * of incoming wires per side is identical for full pop, and almost the same for depop (due to 
02370      * staggering) within +1 or -1. For different tiles (different sblocks) the imbalance is irrelevant,
02371      * since if the tiles are different in mux count then they have to be designed with a different
02372      * physical tile. */
02373 
02374     int num_labels, max_opin_mux_size, min_opin_mux_size;
02375     int inode, i, j, x, y;
02376     int *pre_labels, *final_labels;
02377 
02378         if (chan_type == CHANX){
02379                 x = seg_num;
02380                 y = chan_num;
02381         }
02382         else if (chan_type == CHANY){
02383                 x = chan_num;
02384                 y = seg_num;
02385         }
02386         else {
02387                 printf("Error: Bad channel type (%d).\n", chan_type);
02388                 exit(1);
02389         }
02390 
02391     /* Generate the normal labels list as the baseline. */
02392     pre_labels =
02393         label_wire_muxes(chan_num, seg_num, seg_details, max_len,
02394                          direction, nodes_per_chan, &num_labels);
02395 
02396     /* Find the min and max mux size. */
02397     min_opin_mux_size = MAX_SHORT;
02398     max_opin_mux_size = 0;
02399     for(i = 0; i < num_labels; ++i)
02400         {
02401             inode = get_rr_node_index(x, y, chan_type, pre_labels[i],
02402                                   rr_node_indices);
02403             if(opin_mux_size[inode] < min_opin_mux_size)
02404                 {
02405                     min_opin_mux_size = opin_mux_size[inode];
02406                 }
02407             if(opin_mux_size[inode] > max_opin_mux_size)
02408                 {
02409                     max_opin_mux_size = opin_mux_size[inode];
02410                 }
02411         }
02412     if(max_opin_mux_size > (min_opin_mux_size + 1))
02413         {
02414             printf(ERRTAG "opin muxes are not balanced!\n");
02415                 printf("max_opin_mux_size %d min_opin_mux_size %d chan_type %d x %d y %d\n", 
02416                 max_opin_mux_size, min_opin_mux_size, chan_type, x, y);
02417             exit(1);
02418         }
02419         
02420     /* Create a new list that we will move the muxes with 'holes' to the start of list. */
02421     final_labels = (int *)my_malloc(sizeof(int) * num_labels);
02422     j = 0;
02423     for(i = 0; i < num_labels; ++i)
02424         {
02425             inode = pre_labels[i];
02426             if(opin_mux_size[inode] < max_opin_mux_size)
02427                 {
02428                     final_labels[j] = inode;
02429                     ++j;
02430                 }
02431         }
02432     for(i = 0; i < num_labels; ++i)
02433         {
02434             inode = pre_labels[i];
02435             if(opin_mux_size[inode] >= max_opin_mux_size)
02436                 {
02437                     final_labels[j] = inode;
02438                     ++j;
02439                 }
02440         }
02441 
02442     /* Free the baseline labelling. */
02443     if(pre_labels)
02444         {
02445             free(pre_labels);
02446             pre_labels = NULL;
02447         }
02448 
02449     *num_wire_muxes = num_labels;
02450     return final_labels;
02451 }
02452 
02453 /** Labels the muxes on that side (seg_num, chan_num, direction). The returned array
02454  * maps a label to the actual track #: array[0] = <the track number of the first/lowest mux> 
02455  * This routine orders wire muxes by their natural order, i.e. track # 
02456  */
02457 static int *
02458 label_wire_muxes(INP int chan_num,
02459                  INP int seg_num,
02460                  INP t_seg_details * seg_details,
02461                  INP int max_len,
02462                  INP enum e_direction dir,
02463                  INP int nodes_per_chan,
02464                  OUTP int *num_wire_muxes)
02465 {
02466 
02467     int itrack, start, end, num_labels, pass;
02468     int *labels = NULL;
02469     boolean is_endpoint;
02470 
02471     /* COUNT pass then a LOAD pass */
02472     num_labels = 0;
02473     for(pass = 0; pass < 2; ++pass)
02474         {
02475             /* Alloc the list on LOAD pass */
02476             if(pass > 0)
02477                 {
02478                     labels = (int *)my_malloc(sizeof(int) * num_labels);
02479                     num_labels = 0;
02480                 }
02481 
02482             /* Find the tracks that are starting. */
02483             for(itrack = 0; itrack < nodes_per_chan; ++itrack)
02484                 {
02485                     start =
02486                         get_seg_start(seg_details, itrack, chan_num, seg_num);
02487                     end =
02488                         get_seg_end(seg_details, itrack, start, chan_num,
02489                                     max_len);
02490 
02491                     /* Skip tracks going the wrong way */
02492                     if(seg_details[itrack].direction != dir)
02493                         {
02494                             continue;
02495                         }
02496 
02497                     /* Determine if we are a wire startpoint */
02498                     is_endpoint = (seg_num == start);
02499                     if(DEC_DIRECTION == seg_details[itrack].direction)
02500                         {
02501                             is_endpoint = (seg_num == end);
02502                         }
02503 
02504                     /* Count the labels and load if LOAD pass */
02505                     if(is_endpoint)
02506                         {
02507                             if(pass > 0)
02508                                 {
02509                                     labels[num_labels] = itrack;
02510                                 }
02511                             ++num_labels;
02512                         }
02513                 }
02514         }
02515 
02516     *num_wire_muxes = num_labels;
02517     return labels;
02518 }
02519 
02520 
02521 /** Labels the incoming wires on that side (seg_num, chan_num, direction). 
02522  * The returned array maps a track # to a label: array[0] = <the new hash value/label for track 0>,
02523  * the labels 0,1,2,.. identify consecutive incoming wires that have sbox (passing wires with sbox and ending wires) 
02524  */
02525 static int *
02526 label_incoming_wires(INP int chan_num,
02527                      INP int seg_num,
02528                      INP int sb_seg,
02529                      INP t_seg_details * seg_details,
02530                      INP int max_len,
02531                      INP enum e_direction dir,
02532                      INP int nodes_per_chan,
02533                      OUTP int *num_incoming_wires,
02534                      OUTP int *num_ending_wires)
02535 {
02536 
02537     int itrack, start, end, i, num_passing, num_ending, pass;
02538     int *labels;
02539     boolean sbox_exists, is_endpoint;
02540 
02541     /* Alloc the list of labels for the tracks */
02542     labels = (int *)my_malloc(nodes_per_chan * sizeof(int));
02543     for(i = 0; i < nodes_per_chan; ++i)
02544         {
02545             labels[i] = UN_SET; /* crash hard if unset */
02546         }
02547 
02548     num_ending = 0;
02549     num_passing = 0;
02550     for(pass = 0; pass < 2; ++pass)
02551         {
02552             for(itrack = 0; itrack < nodes_per_chan; ++itrack)
02553                 {
02554                     if(seg_details[itrack].direction == dir)
02555                         {
02556                             start =
02557                                 get_seg_start(seg_details, itrack, chan_num,
02558                                               seg_num);
02559                             end =
02560                                 get_seg_end(seg_details, itrack, start,
02561                                             chan_num, max_len);
02562 
02563                             /* Determine if we are a wire endpoint */
02564                             is_endpoint = (seg_num == end);
02565                             if(DEC_DIRECTION == seg_details[itrack].direction)
02566                                 {
02567                                     is_endpoint = (seg_num == start);
02568                                 }
02569 
02570                             /* Determine if we have a sbox on the wire */
02571                             sbox_exists = is_sbox(chan_num, seg_num, sb_seg,
02572                                                   itrack, seg_details,
02573                                                   UNI_DIRECTIONAL);
02574 
02575                             switch (pass)
02576                                 {
02577                                     /* On first pass, only load ending wire labels. */
02578                                 case 0:
02579                                     if(is_endpoint)
02580                                         {
02581                                             labels[itrack] = num_ending;
02582                                             ++num_ending;
02583                                         }
02584                                     break;
02585 
02586                                     /* On second pass, load the passing wire labels. They
02587                                      * will follow after the ending wire labels. */
02588                                 case 1:
02589                                     if((FALSE == is_endpoint) && sbox_exists)
02590                                         {
02591                                             labels[itrack] =
02592                                                 num_ending + num_passing;
02593                                             ++num_passing;
02594                                         }
02595                                     break;
02596                                 }
02597                         }
02598                 }
02599         }
02600 
02601     *num_incoming_wires = num_passing + num_ending;
02602     *num_ending_wires = num_ending;
02603     return labels;
02604 }
02605 
02606 
02607 /** Returns the index/label in array wire_mux_on_track whose entry equals from_track. If none are
02608  * found, then returns the index of the entry whose value is the largest 
02609  */
02610 static int
02611 find_label_of_track(int *wire_mux_on_track,
02612                     int num_wire_muxes,
02613                     int from_track)
02614 {
02615     int i, max_label, nearest_label, max_entry, nearest_entry;
02616 
02617     max_label = nearest_label = max_entry = nearest_entry = -1;
02618 
02619     for(i = 0; i < num_wire_muxes; i++)
02620         {
02621             if(wire_mux_on_track[i] == from_track)
02622                 {
02623                     return i;   /* matched, return now */
02624                 }
02625         }
02626 
02627     printf("Error: Expected mux not found.\n");
02628     exit(1);
02629 }