VPR-6.0
|
00001 #include <assert.h> 00002 #include <stdio.h> 00003 #include <math.h> 00004 #include "util.h" 00005 #include "vpr_types.h" 00006 #include "globals.h" 00007 #include "rr_graph_area.h" 00008 #include "segment_stats.h" 00009 #include "stats.h" 00010 #include "net_delay.h" 00011 #include "path_delay.h" 00012 #include "read_xml_arch_file.h" 00013 00014 /********************** Subroutines local to this module *********************/ 00015 00016 static void load_channel_occupancies(int **chanx_occ, 00017 int **chany_occ); 00018 00019 static void get_length_and_bends_stats(void); 00020 00021 static void get_channel_occupancy_stats(void); 00022 00023 00024 00025 /************************* Subroutine definitions ****************************/ 00026 00027 00028 /** Prints out various statistics about the current routing. Both a routing 00029 * and an rr_graph must exist when you call this routine. 00030 */ 00031 void 00032 routing_stats(boolean full_stats, 00033 enum e_route_type route_type, 00034 int num_switch, 00035 t_segment_inf * segment_inf, 00036 int num_segment, 00037 float R_minW_nmos, 00038 float R_minW_pmos, 00039 enum e_directionality directionality, 00040 boolean timing_analysis_enabled, 00041 float **net_slack, 00042 float **net_delay) 00043 { 00044 float T_crit; 00045 float area, used_area; 00046 int i, j; 00047 00048 get_length_and_bends_stats(); 00049 get_channel_occupancy_stats(); 00050 00051 printf("Logic Area (in minimum width transistor areas, excludes I/Os and empty grid tiles):\n"); 00052 00053 area = 0; 00054 for(i = 1; i <= nx; i++) { 00055 for(j = 1; j <= ny; j++) { 00056 if(grid[i][j].offset == 0) { 00057 if(grid[i][j].type->area == UNDEFINED) { 00058 area += grid_logic_tile_area * grid[i][j].type->height; 00059 } else { 00060 area += grid[i][j].type->area; 00061 } 00062 } 00063 } 00064 } 00065 /* Todo: need to add pitch of routing to blocks with height > 3 */ 00066 printf("Total Logic Block Area (Warning, need to add pitch of routing to blocks with height > 3): %g \n", area); 00067 00068 used_area = 0; 00069 for(i = 0; i < num_blocks; i++) { 00070 if(block[i].type != IO_TYPE) { 00071 if(block[i].type->area == UNDEFINED) { 00072 used_area += grid_logic_tile_area * block[i].type->height; 00073 } else { 00074 used_area += block[i].type->area; 00075 } 00076 } 00077 } 00078 printf("Total Used Logic Block Area: %g \n", used_area); 00079 00080 if(route_type == DETAILED) 00081 { 00082 count_routing_transistors(directionality, num_switch, segment_inf, 00083 R_minW_nmos, R_minW_pmos); 00084 get_segment_usage_stats(num_segment, segment_inf); 00085 00086 if(timing_analysis_enabled) 00087 { 00088 load_net_delay_from_routing(net_delay, clb_net, num_nets); 00089 00090 #ifdef CREATE_ECHO_FILES 00091 print_net_delay(net_delay, "net_delay.echo", clb_net, num_nets); 00092 #endif /* CREATE_ECHO_FILES */ 00093 00094 load_timing_graph_net_delays(net_delay); 00095 T_crit = load_net_slack(net_slack, 0); 00096 00097 #ifdef CREATE_ECHO_FILES 00098 print_timing_graph("timing_graph.echo"); 00099 print_net_slack("net_slack.echo", net_slack); 00100 print_critical_path("critical_path.echo"); 00101 #endif /* CREATE_ECHO_FILES */ 00102 00103 printf("\n"); 00104 if(pb_max_internal_delay == UNDEFINED || pb_max_internal_delay < T_crit) { 00105 printf("Critical Path: %g (s)\n", T_crit); 00106 } else { 00107 printf("Critical Path: %g (s) - capped by fmax of block type %s\n", pb_max_internal_delay, pbtype_max_internal_delay->name); 00108 } 00109 } 00110 } 00111 00112 if(full_stats == TRUE) 00113 print_wirelen_prob_dist(); 00114 } 00115 00116 00117 /** Figures out maximum, minimum and average number of bends and net length 00118 * in the routing. 00119 */ 00120 void 00121 get_length_and_bends_stats(void) 00122 { 00123 int inet, bends, total_bends, max_bends; 00124 int length, total_length, max_length; 00125 int segments, total_segments, max_segments; 00126 float av_bends, av_length, av_segments; 00127 int num_global_nets, num_clb_opins_reserved; 00128 00129 00130 max_bends = 0; 00131 total_bends = 0; 00132 max_length = 0; 00133 total_length = 0; 00134 max_segments = 0; 00135 total_segments = 0; 00136 num_global_nets = 0; 00137 num_clb_opins_reserved = 0; 00138 00139 for(inet = 0; inet < num_nets; inet++) 00140 { 00141 if(clb_net[inet].is_global == FALSE && clb_net[inet].num_sinks != 0) 00142 { /* Globals don't count. */ 00143 get_num_bends_and_length(inet, &bends, &length, 00144 &segments); 00145 00146 total_bends += bends; 00147 max_bends = max(bends, max_bends); 00148 00149 total_length += length; 00150 max_length = max(length, max_length); 00151 00152 total_segments += segments; 00153 max_segments = max(segments, max_segments); 00154 } 00155 else if (clb_net[inet].is_global) 00156 { 00157 num_global_nets++; 00158 } else { 00159 num_clb_opins_reserved++; 00160 } 00161 } 00162 00163 00164 av_bends = (float)total_bends / (float)(num_nets - num_global_nets); 00165 printf 00166 ("\nAverage number of bends per net: %#g Maximum # of bends: %d\n\n", 00167 av_bends, max_bends); 00168 00169 av_length = (float)total_length / (float)(num_nets - num_global_nets); 00170 printf("\nThe number of routed nets (nonglobal): %d\n", 00171 num_nets - num_global_nets); 00172 printf("Wirelength results (all in units of 1 clb segments):\n"); 00173 printf("\tTotal wirelength: %d Average net length: %#g\n", 00174 total_length, av_length); 00175 printf("\tMaximum net length: %d\n\n", max_length); 00176 00177 av_segments = (float)total_segments / (float)(num_nets - num_global_nets); 00178 printf("Wirelength results in terms of physical segments:\n"); 00179 printf("\tTotal wiring segments used: %d Av. wire segments per net: " 00180 "%#g\n", total_segments, av_segments); 00181 printf("\tMaximum segments used by a net: %d\n\n", max_segments); 00182 printf("\tTotal local nets with reserved CLB opins: %d\n\n", num_clb_opins_reserved); 00183 } 00184 00185 00186 /** Determines how many tracks are used in each channel. */ 00187 static void 00188 get_channel_occupancy_stats(void) 00189 { 00190 int i, j, max_occ, total_x, total_y; 00191 float av_occ; 00192 int **chanx_occ; /* [1..nx][0..ny] */ 00193 int **chany_occ; /* [0..nx][1..ny] */ 00194 00195 00196 chanx_occ = (int **)alloc_matrix(1, nx, 0, ny, sizeof(int)); 00197 chany_occ = (int **)alloc_matrix(0, nx, 1, ny, sizeof(int)); 00198 load_channel_occupancies(chanx_occ, chany_occ); 00199 00200 printf("\nX - Directed channels:\n\n"); 00201 printf("j\tmax occ\tav_occ\t\tcapacity\n"); 00202 00203 total_x = 0; 00204 00205 for(j = 0; j <= ny; j++) 00206 { 00207 total_x += chan_width_x[j]; 00208 av_occ = 0.; 00209 max_occ = -1; 00210 00211 for(i = 1; i <= nx; i++) 00212 { 00213 max_occ = max(chanx_occ[i][j], max_occ); 00214 av_occ += chanx_occ[i][j]; 00215 } 00216 av_occ /= nx; 00217 printf("%d\t%d\t%-#9g\t%d\n", j, max_occ, av_occ, 00218 chan_width_x[j]); 00219 } 00220 00221 00222 printf("\nY - Directed channels:\n\n"); 00223 printf("i\tmax occ\tav_occ\t\tcapacity\n"); 00224 00225 total_y = 0; 00226 00227 for(i = 0; i <= nx; i++) 00228 { 00229 total_y += chan_width_y[i]; 00230 av_occ = 0.; 00231 max_occ = -1; 00232 00233 for(j = 1; j <= ny; j++) 00234 { 00235 max_occ = max(chany_occ[i][j], max_occ); 00236 av_occ += chany_occ[i][j]; 00237 } 00238 av_occ /= ny; 00239 printf("%d\t%d\t%-#9g\t%d\n", i, max_occ, av_occ, 00240 chan_width_y[i]); 00241 } 00242 00243 printf("\nTotal Tracks in X-direction: %d in Y-direction: %d\n\n", 00244 total_x, total_y); 00245 00246 free_matrix(chanx_occ, 1, nx, 0, sizeof(int)); 00247 free_matrix(chany_occ, 0, nx, 1, sizeof(int)); 00248 } 00249 00250 00251 /** Loads the two arrays passed in with the total occupancy at each of the 00252 * channel segments in the FPGA. 00253 */ 00254 static void 00255 load_channel_occupancies(int **chanx_occ, 00256 int **chany_occ) 00257 { 00258 00259 int i, j, inode, inet; 00260 struct s_trace *tptr; 00261 t_rr_type rr_type; 00262 00263 /* First set the occupancy of everything to zero. */ 00264 00265 for(i = 1; i <= nx; i++) 00266 for(j = 0; j <= ny; j++) 00267 chanx_occ[i][j] = 0; 00268 00269 for(i = 0; i <= nx; i++) 00270 for(j = 1; j <= ny; j++) 00271 chany_occ[i][j] = 0; 00272 00273 /* Now go through each net and count the tracks and pins used everywhere */ 00274 00275 for(inet = 0; inet < num_nets; inet++) 00276 { 00277 00278 if(clb_net[inet].is_global && clb_net[inet].num_sinks != 0) /* Skip global and empty nets. */ 00279 continue; 00280 00281 tptr = trace_head[inet]; 00282 while(tptr != NULL) 00283 { 00284 inode = tptr->index; 00285 rr_type = rr_node[inode].type; 00286 00287 if(rr_type == SINK) 00288 { 00289 tptr = tptr->next; /* Skip next segment. */ 00290 if(tptr == NULL) 00291 break; 00292 } 00293 00294 else if(rr_type == CHANX) 00295 { 00296 j = rr_node[inode].ylow; 00297 for(i = rr_node[inode].xlow; 00298 i <= rr_node[inode].xhigh; i++) 00299 chanx_occ[i][j]++; 00300 } 00301 00302 else if(rr_type == CHANY) 00303 { 00304 i = rr_node[inode].xlow; 00305 for(j = rr_node[inode].ylow; 00306 j <= rr_node[inode].yhigh; j++) 00307 chany_occ[i][j]++; 00308 } 00309 00310 tptr = tptr->next; 00311 } 00312 } 00313 } 00314 00315 00316 /** Counts and returns the number of bends, wirelength, and number of routing 00317 * resource segments in net inet's routing. 00318 */ 00319 void 00320 get_num_bends_and_length(int inet, 00321 int *bends_ptr, 00322 int *len_ptr, 00323 int *segments_ptr) 00324 { 00325 struct s_trace *tptr, *prevptr; 00326 int inode; 00327 t_rr_type curr_type, prev_type; 00328 int bends, length, segments; 00329 00330 bends = 0; 00331 length = 0; 00332 segments = 0; 00333 00334 prevptr = trace_head[inet]; /* Should always be SOURCE. */ 00335 if(prevptr == NULL) 00336 { 00337 printf 00338 ("Error in get_num_bends_and_length: net #%d has no traceback.\n", 00339 inet); 00340 exit(1); 00341 } 00342 inode = prevptr->index; 00343 prev_type = rr_node[inode].type; 00344 00345 tptr = prevptr->next; 00346 00347 while(tptr != NULL) 00348 { 00349 inode = tptr->index; 00350 curr_type = rr_node[inode].type; 00351 00352 if(curr_type == SINK) 00353 { /* Starting a new segment */ 00354 tptr = tptr->next; /* Link to existing path - don't add to len. */ 00355 if(tptr == NULL) 00356 break; 00357 00358 curr_type = rr_node[tptr->index].type; 00359 } 00360 00361 else if(curr_type == CHANX || curr_type == CHANY) 00362 { 00363 segments++; 00364 length += 1 + rr_node[inode].xhigh - rr_node[inode].xlow + 00365 rr_node[inode].yhigh - rr_node[inode].ylow; 00366 00367 if(curr_type != prev_type 00368 && (prev_type == CHANX || prev_type == CHANY)) 00369 bends++; 00370 } 00371 00372 prev_type = curr_type; 00373 tptr = tptr->next; 00374 } 00375 00376 *bends_ptr = bends; 00377 *len_ptr = length; 00378 *segments_ptr = segments; 00379 } 00380 00381 00382 /** Prints out the probability distribution of the wirelength / number 00383 * input pins on a net -- i.e. simulates 2-point net length probability 00384 * distribution. 00385 */ 00386 void 00387 print_wirelen_prob_dist(void) 00388 { 00389 00390 float *prob_dist; 00391 float norm_fac, two_point_length; 00392 int inet, bends, length, segments, index; 00393 float av_length; 00394 int prob_dist_size, i, incr; 00395 00396 prob_dist_size = nx + ny + 10; 00397 prob_dist = (float *)my_calloc(prob_dist_size, sizeof(float)); 00398 norm_fac = 0.; 00399 00400 for(inet = 0; inet < num_nets; inet++) 00401 { 00402 if(clb_net[inet].is_global == FALSE && clb_net[inet].num_sinks != 0) 00403 { 00404 get_num_bends_and_length(inet, &bends, &length, 00405 &segments); 00406 00407 /* Assign probability to two integer lengths proportionately -- i.e. * 00408 * if two_point_length = 1.9, add 0.9 of the pins to prob_dist[2] and * 00409 * only 0.1 to prob_dist[1]. */ 00410 00411 two_point_length = 00412 (float)length / (float)(clb_net[inet].num_sinks); 00413 index = (int)two_point_length; 00414 if(index >= prob_dist_size) 00415 { 00416 00417 printf 00418 ("Warning: index (%d) to prob_dist exceeds its allocated size (%d)\n", 00419 index, prob_dist_size); 00420 printf 00421 ("Realloc'ing to increase 2-pin wirelen prob distribution array\n"); 00422 incr = index - prob_dist_size + 2; 00423 prob_dist_size += incr; 00424 prob_dist = 00425 my_realloc(prob_dist, 00426 prob_dist_size * sizeof(float)); 00427 for(i = prob_dist_size - incr; i < prob_dist_size; 00428 i++) 00429 prob_dist[i] = 0.0; 00430 } 00431 prob_dist[index] += 00432 (clb_net[inet].num_sinks) * (1 - two_point_length + 00433 index); 00434 00435 index++; 00436 if(index >= prob_dist_size) 00437 { 00438 00439 printf 00440 ("Warning: index (%d) to prob_dist exceeds its allocated size (%d)\n", 00441 index, prob_dist_size); 00442 printf 00443 ("Realloc'ing to increase 2-pin wirelen prob distribution array\n"); 00444 incr = index - prob_dist_size + 2; 00445 prob_dist_size += incr; 00446 prob_dist = 00447 my_realloc(prob_dist, 00448 prob_dist_size * sizeof(float)); 00449 for(i = prob_dist_size - incr; i < prob_dist_size; 00450 i++) 00451 prob_dist[i] = 0.0; 00452 } 00453 prob_dist[index] += (clb_net[inet].num_sinks) * (1 - index + 00454 two_point_length); 00455 00456 norm_fac += clb_net[inet].num_sinks; 00457 } 00458 } 00459 00460 /* Normalize so total probability is 1 and print out. */ 00461 00462 printf("\nProbability distribution of 2-pin net lengths:\n\n"); 00463 printf("Length p(Lenth)\n"); 00464 00465 av_length = 0; 00466 00467 for(index = 0; index < prob_dist_size; index++) 00468 { 00469 prob_dist[index] /= norm_fac; 00470 printf("%6d %10.6f\n", index, prob_dist[index]); 00471 av_length += prob_dist[index] * index; 00472 } 00473 00474 printf("\nThe number of 2-pin nets is ;%g;\n", norm_fac); 00475 printf("\nExpected value of 2-pin net length (R) is ;%g;\n", av_length); 00476 printf("\nTotal wire length is ;%g;\n", norm_fac * av_length); 00477 00478 free(prob_dist); 00479 } 00480 00481 00482 /** Finds the average number of input pins used per clb. Does not 00483 * count inputs which are hooked to global nets (i.e. the clock 00484 * when it is marked global). 00485 */ 00486 void 00487 print_lambda(void) 00488 { 00489 int bnum, ipin; 00490 int num_inputs_used = 0; 00491 int iclass, inet; 00492 float lambda; 00493 t_type_ptr type; 00494 00495 for(bnum = 0; bnum < num_blocks; bnum++) 00496 { 00497 type = block[bnum].type; 00498 assert(type != NULL); 00499 if(type != IO_TYPE) 00500 { 00501 for(ipin = 0; ipin < type->num_pins; ipin++) 00502 { 00503 iclass = type->pin_class[ipin]; 00504 if(type->class_inf[iclass].type == RECEIVER) 00505 { 00506 inet = block[bnum].nets[ipin]; 00507 if(inet != OPEN) /* Pin is connected? */ 00508 if(clb_net[inet].is_global == FALSE) /* Not a global clock */ 00509 num_inputs_used++; 00510 } 00511 } 00512 } 00513 } 00514 00515 lambda = (float)num_inputs_used / (float)num_blocks; 00516 printf("Average lambda (input pins used per clb) is: %g\n", lambda); 00517 }