Go to the source code of this file.
Functions | |
float ** | alloc_and_load_timing_graph (t_timing_inf timing_inf, t_subblock_data subblock_data) |
t_linked_int * | allocate_and_load_critical_path (void) |
void | load_timing_graph_net_delays (float **net_delay) |
float | load_net_slack (float **net_slack, float target_cycle_time) |
void | free_timing_graph (float **net_slack) |
void | print_timing_graph (char *fname) |
void | print_net_slack (char *fname, float **net_slack) |
void | print_critical_path (char *fname, t_subblock_data subblock_data) |
void | get_tnode_block_and_output_net (int inode, int *iblk_ptr, int *inet_ptr) |
void | do_constant_net_delay_timing_analysis (t_timing_inf timing_inf, t_subblock_data subblock_data, float constant_net_delay_value) |
float** alloc_and_load_timing_graph | ( | t_timing_inf | timing_inf, | |
t_subblock_data | subblock_data | |||
) |
Definition at line 158 of file path_delay.c.
00160 { 00161 00162 /* This routine builds the graph used for timing analysis. Every fb or * 00163 * subblock pin is a timing node (tnode). The connectivity between pins is * 00164 * represented by timing edges (tedges). All delay is marked on edges, not * 00165 * on nodes. This routine returns an array that will store slack values: * 00166 * net_slack[0..num_nets-1][1..num_pins-1]. */ 00167 00168 /* The two arrays below are valid only for FBs, not pads. */ 00169 int i; 00170 int **num_uses_of_fb_ipin; /* [0..num_blocks-1][0..type->num_pins-1] */ 00171 int ***num_uses_of_sblk_opin; /* [0..num_blocks-1][0..type->num_subblocks][0..type->max_subblock_outputs] */ 00172 00173 /* Array for mapping from a pin on a block to a tnode index. For pads, only * 00174 * the first two pin locations are used (input to pad is first, output of * 00175 * pad is second). For fbs, all OPEN pins on the fb have their mapping * 00176 * set to OPEN so I won't use it by mistake. */ 00177 00178 int **block_pin_to_tnode; /* [0..num_blocks-1][0..num_pins-1] */ 00179 00180 00181 /* Array for mapping from a pin on a subblock to a tnode index. Unused * 00182 * or nonexistent subblock pins have their mapping set to OPEN. * 00183 * [0..num_blocks-1][0..num_subblocks_per_block-1][0..NUM_SUB_PIN_TYPES][0..total_subblock_pins-1] */ 00184 00185 int ****snode_block_pin_to_tnode; 00186 00187 int num_sinks; 00188 float **net_slack; /* [0..num_nets-1][1..num_pins-1]. */ 00189 00190 /************* End of variable declarations ********************************/ 00191 00192 if(tedge_ch_list_head != NULL) 00193 { 00194 printf("Error in alloc_and_load_timing_graph:\n" 00195 "\tAn old timing graph still exists.\n"); 00196 exit(1); 00197 } 00198 00199 /* If either of the checks below ever fail, change the definition of * 00200 * tnode_descript to use ints instead of shorts for isubblk or ipin. */ 00201 00202 for(i = 0; i < num_types; i++) 00203 { 00204 if(type_descriptors[i].num_pins > MAX_SHORT) 00205 { 00206 printf 00207 ("Error in alloc_and_load_timing_graph: pins for type %s is %d." 00208 "\tWill cause short overflow in tnode_descript.\n", 00209 type_descriptors[i].name, 00210 type_descriptors[i].num_pins); 00211 exit(1); 00212 } 00213 00214 if(type_descriptors[i].max_subblocks > MAX_SHORT) 00215 { 00216 printf 00217 ("Error in alloc_and_load_timing_graph: max_subblocks_per_block" 00218 "\tis %d -- will cause short overflow in tnode_descript.\n", 00219 type_descriptors[i].max_subblocks); 00220 exit(1); 00221 } 00222 } 00223 00224 alloc_and_load_fanout_counts(&num_uses_of_fb_ipin, 00225 &num_uses_of_sblk_opin, subblock_data); 00226 00227 num_tnodes = alloc_and_load_pin_mappings(&block_pin_to_tnode, 00228 &snode_block_pin_to_tnode, 00229 subblock_data, 00230 num_uses_of_sblk_opin); 00231 00232 alloc_and_load_tnodes_and_net_mapping(num_uses_of_fb_ipin, 00233 num_uses_of_sblk_opin, 00234 block_pin_to_tnode, 00235 snode_block_pin_to_tnode, 00236 subblock_data, timing_inf); 00237 00238 num_sinks = alloc_and_load_timing_graph_levels(); 00239 00240 check_timing_graph(subblock_data.num_const_gen, subblock_data.num_ff, 00241 num_sinks); 00242 00243 free_fanout_counts(num_uses_of_fb_ipin, num_uses_of_sblk_opin); 00244 free_pin_mappings(block_pin_to_tnode, snode_block_pin_to_tnode, 00245 subblock_data.num_subblocks_per_block); 00246 00247 net_slack = alloc_net_slack(); 00248 return (net_slack); 00249 }
t_linked_int* allocate_and_load_critical_path | ( | void | ) |
Definition at line 1551 of file path_delay.c.
01552 { 01553 01554 /* Finds the critical path and puts a list of the tnodes on the critical * 01555 * path in a linked list, from the path SOURCE to the path SINK. */ 01556 01557 t_linked_int *critical_path_head, *curr_crit_node, *prev_crit_node; 01558 int inode, iedge, to_node, num_at_level, i, crit_node, num_edges; 01559 float min_slack, slack; 01560 t_tedge *tedge; 01561 01562 num_at_level = tnodes_at_level[0].nelem; 01563 min_slack = HUGE_FLOAT; 01564 crit_node = OPEN; /* Stops compiler warnings. */ 01565 01566 for(i = 0; i < num_at_level; i++) 01567 { /* Path must start at SOURCE (no inputs) */ 01568 inode = tnodes_at_level[0].list[i]; 01569 slack = tnode[inode].T_req - tnode[inode].T_arr; 01570 01571 if(slack < min_slack) 01572 { 01573 crit_node = inode; 01574 min_slack = slack; 01575 } 01576 } 01577 01578 critical_path_head = (t_linked_int *) my_malloc(sizeof(t_linked_int)); 01579 critical_path_head->data = crit_node; 01580 prev_crit_node = critical_path_head; 01581 num_edges = tnode[crit_node].num_edges; 01582 01583 while(num_edges != 0) 01584 { /* Path will end at SINK (no fanout) */ 01585 curr_crit_node = (t_linked_int *) my_malloc(sizeof(t_linked_int)); 01586 prev_crit_node->next = curr_crit_node; 01587 tedge = tnode[crit_node].out_edges; 01588 min_slack = HUGE_FLOAT; 01589 01590 for(iedge = 0; iedge < num_edges; iedge++) 01591 { 01592 to_node = tedge[iedge].to_node; 01593 slack = tnode[to_node].T_req - tnode[to_node].T_arr; 01594 01595 if(slack < min_slack) 01596 { 01597 crit_node = to_node; 01598 min_slack = slack; 01599 } 01600 } 01601 01602 curr_crit_node->data = crit_node; 01603 prev_crit_node = curr_crit_node; 01604 num_edges = tnode[crit_node].num_edges; 01605 } 01606 01607 prev_crit_node->next = NULL; 01608 return (critical_path_head); 01609 }
void do_constant_net_delay_timing_analysis | ( | t_timing_inf | timing_inf, | |
t_subblock_data | subblock_data, | |||
float | constant_net_delay_value | |||
) |
Definition at line 1644 of file path_delay.c.
01647 { 01648 01649 /* Does a timing analysis (simple) where it assumes that each net has a * 01650 * constant delay value. Used only when operation == TIMING_ANALYSIS_ONLY. */ 01651 01652 struct s_linked_vptr *net_delay_chunk_list_head; 01653 float **net_delay, **net_slack; 01654 01655 float T_crit; 01656 01657 net_slack = alloc_and_load_timing_graph(timing_inf, subblock_data); 01658 net_delay = alloc_net_delay(&net_delay_chunk_list_head); 01659 01660 load_constant_net_delay(net_delay, constant_net_delay_value); 01661 load_timing_graph_net_delays(net_delay); 01662 T_crit = load_net_slack(net_slack, 0); 01663 01664 printf("\n"); 01665 printf("\nCritical Path: %g (s)\n", T_crit); 01666 01667 #ifdef CREATE_ECHO_FILES 01668 print_critical_path("critical_path.echo", subblock_data); 01669 print_timing_graph("timing_graph.echo"); 01670 print_net_slack("net_slack.echo", net_slack); 01671 print_net_delay(net_delay, "net_delay.echo"); 01672 #endif /* CREATE_ECHO_FILES */ 01673 01674 free_timing_graph(net_slack); 01675 free_net_delay(net_delay, &net_delay_chunk_list_head); 01676 }
void free_timing_graph | ( | float ** | net_slack | ) |
Definition at line 1217 of file path_delay.c.
01218 { 01219 01220 /* Frees the timing graph data. */ 01221 01222 if(tedge_ch_list_head == NULL) 01223 { 01224 printf("Error in free_timing_graph: No timing graph to free.\n"); 01225 exit(1); 01226 } 01227 01228 free_chunk_memory(tedge_ch_list_head); 01229 free(tnode); 01230 free(tnode_descript); 01231 free(net_to_driver_tnode); 01232 free_ivec_vector(tnodes_at_level, 0, num_tnode_levels - 1); 01233 free(net_slack); 01234 01235 tedge_ch_list_head = NULL; 01236 tedge_ch_bytes_avail = 0; 01237 tedge_ch_next_avail = NULL; 01238 01239 tnode = NULL; 01240 tnode_descript = NULL; 01241 num_tnodes = 0; 01242 net_to_driver_tnode = NULL; 01243 tnodes_at_level = NULL; 01244 num_tnode_levels = 0; 01245 }
void get_tnode_block_and_output_net | ( | int | inode, | |
int * | iblk_ptr, | |||
int * | inet_ptr | |||
) |
Definition at line 1613 of file path_delay.c.
01616 { 01617 01618 /* Returns the index of the block that this tnode is part of. If the tnode * 01619 * is a FB_OPIN or INPAD_OPIN (i.e. if it drives a net), the net index is * 01620 * returned via inet_ptr. Otherwise inet_ptr points at OPEN. */ 01621 01622 int inet, ipin, iblk; 01623 t_tnode_type tnode_type; 01624 01625 iblk = tnode_descript[inode].iblk; 01626 tnode_type = tnode_descript[inode].type; 01627 01628 if(tnode_type == FB_OPIN || tnode_type == INPAD_OPIN) 01629 { 01630 ipin = tnode_descript[inode].ipin; 01631 inet = block[iblk].nets[ipin]; 01632 } 01633 else 01634 { 01635 inet = OPEN; 01636 } 01637 01638 *iblk_ptr = iblk; 01639 *inet_ptr = inet; 01640 }
float load_net_slack | ( | float ** | net_slack, | |
float | target_cycle_time | |||
) |
Definition at line 1345 of file path_delay.c.
01347 { 01348 01349 /* Determines the slack of every source-sink pair of block pins in the * 01350 * circuit. The timing graph must have already been built. target_cycle_ * 01351 * time is the target delay for the circuit -- if 0, the target_cycle_time * 01352 * is set to the critical path found in the timing graph. This routine * 01353 * loads net_slack, and returns the current critical path delay. */ 01354 01355 float T_crit, T_arr, Tdel, T_cycle, T_req; 01356 int inode, ilevel, num_at_level, i, num_edges, iedge, to_node; 01357 t_tedge *tedge; 01358 01359 /* Reset all arrival times to -ve infinity. Can't just set to zero or the * 01360 * constant propagation (constant generators work at -ve infinity) won't * 01361 * work. */ 01362 01363 for(inode = 0; inode < num_tnodes; inode++) 01364 tnode[inode].T_arr = T_CONSTANT_GENERATOR; 01365 01366 /* Compute all arrival times with a breadth-first analysis from inputs to * 01367 * outputs. Also compute critical path (T_crit). */ 01368 01369 T_crit = 0.; 01370 01371 /* Primary inputs arrive at T = 0. */ 01372 01373 num_at_level = tnodes_at_level[0].nelem; 01374 for(i = 0; i < num_at_level; i++) 01375 { 01376 inode = tnodes_at_level[0].list[i]; 01377 tnode[inode].T_arr = 0.; 01378 } 01379 01380 for(ilevel = 0; ilevel < num_tnode_levels; ilevel++) 01381 { 01382 num_at_level = tnodes_at_level[ilevel].nelem; 01383 01384 for(i = 0; i < num_at_level; i++) 01385 { 01386 inode = tnodes_at_level[ilevel].list[i]; 01387 T_arr = tnode[inode].T_arr; 01388 num_edges = tnode[inode].num_edges; 01389 tedge = tnode[inode].out_edges; 01390 T_crit = max(T_crit, T_arr); 01391 01392 for(iedge = 0; iedge < num_edges; iedge++) 01393 { 01394 to_node = tedge[iedge].to_node; 01395 Tdel = tedge[iedge].Tdel; 01396 tnode[to_node].T_arr = 01397 max(tnode[to_node].T_arr, T_arr + Tdel); 01398 } 01399 } 01400 01401 } 01402 01403 if(target_cycle_time > 0.) /* User specified target cycle time */ 01404 T_cycle = target_cycle_time; 01405 else /* Otherwise, target = critical path */ 01406 T_cycle = T_crit; 01407 01408 /* Compute the required arrival times with a backward breadth-first analysis * 01409 * from sinks (output pads, etc.) to primary inputs. */ 01410 01411 for(ilevel = num_tnode_levels - 1; ilevel >= 0; ilevel--) 01412 { 01413 num_at_level = tnodes_at_level[ilevel].nelem; 01414 01415 for(i = 0; i < num_at_level; i++) 01416 { 01417 inode = tnodes_at_level[ilevel].list[i]; 01418 num_edges = tnode[inode].num_edges; 01419 01420 if(num_edges == 0) 01421 { /* sink */ 01422 tnode[inode].T_req = T_cycle; 01423 } 01424 else 01425 { 01426 tedge = tnode[inode].out_edges; 01427 to_node = tedge[0].to_node; 01428 Tdel = tedge[0].Tdel; 01429 T_req = tnode[to_node].T_req - Tdel; 01430 01431 for(iedge = 1; iedge < num_edges; iedge++) 01432 { 01433 to_node = tedge[iedge].to_node; 01434 Tdel = tedge[iedge].Tdel; 01435 T_req = 01436 min(T_req, 01437 tnode[to_node].T_req - Tdel); 01438 } 01439 01440 tnode[inode].T_req = T_req; 01441 } 01442 } 01443 } 01444 01445 compute_net_slacks(net_slack); 01446 01447 return (T_crit); 01448 }
void load_timing_graph_net_delays | ( | float ** | net_delay | ) |
Definition at line 1191 of file path_delay.c.
01192 { 01193 01194 /* Sets the delays of the inter-FB nets to the values specified by * 01195 * net_delay[0..num_nets-1][1..num_pins-1]. These net delays should have * 01196 * been allocated and loaded with the net_delay routines. This routine * 01197 * marks the corresponding edges in the timing graph with the proper delay. */ 01198 01199 int inet, ipin, inode; 01200 t_tedge *tedge; 01201 01202 for(inet = 0; inet < num_nets; inet++) 01203 { 01204 inode = net_to_driver_tnode[inet]; 01205 tedge = tnode[inode].out_edges; 01206 01207 /* Note that the edges of a tnode corresponding to a FB or INPAD opin must * 01208 * be in the same order as the pins of the net driven by the tnode. */ 01209 01210 for(ipin = 1; ipin < (net[inet].num_sinks + 1); ipin++) 01211 tedge[ipin - 1].Tdel = net_delay[inet][ipin]; 01212 } 01213 }
void print_critical_path | ( | char * | fname, | |
t_subblock_data | subblock_data | |||
) |
Definition at line 1480 of file path_delay.c.
01482 { 01483 01484 /* Prints out the critical path to a file. */ 01485 01486 t_linked_int *critical_path_head, *critical_path_node; 01487 FILE *fp; 01488 int non_global_nets_on_crit_path, global_nets_on_crit_path; 01489 int tnodes_on_crit_path, inode, iblk, inet; 01490 t_tnode_type type; 01491 float total_net_delay, total_logic_delay, Tdel; 01492 01493 critical_path_head = allocate_and_load_critical_path(); 01494 critical_path_node = critical_path_head; 01495 01496 fp = my_fopen(fname, "w"); 01497 01498 non_global_nets_on_crit_path = 0; 01499 global_nets_on_crit_path = 0; 01500 tnodes_on_crit_path = 0; 01501 total_net_delay = 0.; 01502 total_logic_delay = 0.; 01503 01504 while(critical_path_node != NULL) 01505 { 01506 Tdel = 01507 print_critical_path_node(fp, critical_path_node, 01508 subblock_data); 01509 inode = critical_path_node->data; 01510 type = tnode_descript[inode].type; 01511 tnodes_on_crit_path++; 01512 01513 if(type == INPAD_OPIN || type == FB_OPIN) 01514 { 01515 get_tnode_block_and_output_net(inode, &iblk, &inet); 01516 01517 if(!net[inet].is_global) 01518 non_global_nets_on_crit_path++; 01519 else 01520 global_nets_on_crit_path++; 01521 01522 total_net_delay += Tdel; 01523 } 01524 else 01525 { 01526 total_logic_delay += Tdel; 01527 } 01528 01529 critical_path_node = critical_path_node->next; 01530 } 01531 01532 fprintf(fp, 01533 "\nTnodes on crit. path: %d Non-global nets on crit. path: %d." 01534 "\n", tnodes_on_crit_path, non_global_nets_on_crit_path); 01535 fprintf(fp, "Global nets on crit. path: %d.\n", global_nets_on_crit_path); 01536 fprintf(fp, "Total logic delay: %g (s) Total net delay: %g (s)\n", 01537 total_logic_delay, total_net_delay); 01538 01539 printf("Nets on crit. path: %d normal, %d global.\n", 01540 non_global_nets_on_crit_path, global_nets_on_crit_path); 01541 01542 printf("Total logic delay: %g (s) Total net delay: %g (s)\n", 01543 total_logic_delay, total_net_delay); 01544 01545 fclose(fp); 01546 free_int_list(&critical_path_head); 01547 }
void print_net_slack | ( | char * | fname, | |
float ** | net_slack | |||
) |
Definition at line 1249 of file path_delay.c.
01251 { 01252 01253 /* Prints the net slacks into a file. */ 01254 01255 int inet, ipin; 01256 FILE *fp; 01257 01258 fp = my_fopen(fname, "w"); 01259 01260 fprintf(fp, "Net #\tSlacks\n\n"); 01261 01262 for(inet = 0; inet < num_nets; inet++) 01263 { 01264 fprintf(fp, "%5d", inet); 01265 for(ipin = 1; ipin < (net[inet].num_sinks + 1); ipin++) 01266 { 01267 fprintf(fp, "\t%g", net_slack[inet][ipin]); 01268 } 01269 fprintf(fp, "\n"); 01270 } 01271 }
void print_timing_graph | ( | char * | fname | ) |
Definition at line 1275 of file path_delay.c.
01276 { 01277 01278 /* Prints the timing graph into a file. */ 01279 01280 FILE *fp; 01281 int inode, iedge, ilevel, i; 01282 t_tedge *tedge; 01283 t_tnode_type itype; 01284 char *tnode_type_names[] = { "INPAD_SOURCE", "INPAD_OPIN", 01285 "OUTPAD_IPIN", "OUTPAD_SINK", "FB_IPIN", "FB_OPIN", 01286 "SUBBLK_IPIN", "SUBBLK_OPIN", "FF_SINK", "FF_SOURCE", 01287 "CONSTANT_GEN_SOURCE" 01288 }; 01289 01290 01291 fp = my_fopen(fname, "w"); 01292 01293 fprintf(fp, "num_tnodes: %d\n", num_tnodes); 01294 fprintf(fp, "Node #\tType\t\tipin\tisubblk\tiblk\t# edges\t" 01295 "Edges (to_node, Tdel)\n\n"); 01296 01297 for(inode = 0; inode < num_tnodes; inode++) 01298 { 01299 fprintf(fp, "%d\t", inode); 01300 01301 itype = tnode_descript[inode].type; 01302 fprintf(fp, "%-15.15s\t", tnode_type_names[itype]); 01303 01304 fprintf(fp, "%d\t%d\t%d\t", tnode_descript[inode].ipin, 01305 tnode_descript[inode].isubblk, 01306 tnode_descript[inode].iblk); 01307 01308 fprintf(fp, "%d\t", tnode[inode].num_edges); 01309 tedge = tnode[inode].out_edges; 01310 for(iedge = 0; iedge < tnode[inode].num_edges; iedge++) 01311 { 01312 fprintf(fp, "\t(%4d,%7.3g)", tedge[iedge].to_node, 01313 tedge[iedge].Tdel); 01314 } 01315 fprintf(fp, "\n"); 01316 } 01317 01318 fprintf(fp, "\n\nnum_tnode_levels: %d\n", num_tnode_levels); 01319 01320 for(ilevel = 0; ilevel < num_tnode_levels; ilevel++) 01321 { 01322 fprintf(fp, "\n\nLevel: %d Num_nodes: %d\nNodes:", ilevel, 01323 tnodes_at_level[ilevel].nelem); 01324 for(i = 0; i < tnodes_at_level[ilevel].nelem; i++) 01325 fprintf(fp, "\t%d", tnodes_at_level[ilevel].list[i]); 01326 } 01327 01328 fprintf(fp, "\n"); 01329 fprintf(fp, "\n\nNet #\tNet_to_driver_tnode\n"); 01330 01331 for(i = 0; i < num_nets; i++) 01332 fprintf(fp, "%4d\t%6d\n", i, net_to_driver_tnode[i]); 01333 01334 fprintf(fp, "\n\nNode #\t\tT_arr\t\tT_req\n\n"); 01335 01336 for(inode = 0; inode < num_tnodes; inode++) 01337 fprintf(fp, "%d\t%12g\t%12g\n", inode, tnode[inode].T_arr, 01338 tnode[inode].T_req); 01339 01340 fclose(fp); 01341 }