VPR-6.0
|
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 }