#include <stdio.h>
#include "util.h"
#include "vpr_types.h"
#include "globals.h"
#include "path_delay.h"
#include "path_delay2.h"
#include "net_delay.h"
#include "vpr_utils.h"
#include <assert.h>
Go to the source code of this file.
Defines | |
#define | T_CONSTANT_GENERATOR -1000 |
Enumerations | |
enum | e_subblock_pin_type { SUB_INPUT = 0, SUB_OUTPUT, SUB_CLOCK, NUM_SUB_PIN_TYPES } |
Functions | |
static int | alloc_and_load_pin_mappings (int ***block_pin_to_tnode_ptr, int *****snode_block_pin_to_tnode_ptr, t_subblock_data subblock_data, int ***num_uses_of_sblk_opin) |
static void | free_pin_mappings (int **block_pin_to_tnode, int ****snode_block_pin_to_tnode, int *num_subblocks_per_block) |
static void | alloc_and_load_fanout_counts (int ***num_uses_of_fb_ipin_ptr, int ****num_uses_of_sblk_opin_ptr, t_subblock_data subblock_data) |
static void | free_fanout_counts (int **num_uses_of_fb_ipin, int ***num_uses_of_sblk_opin) |
static float ** | alloc_net_slack (void) |
static void | compute_net_slacks (float **net_slack) |
static void | alloc_and_load_tnodes_and_net_mapping (int **num_uses_of_fb_ipin, int ***num_uses_of_sblk_opin, int **block_pin_to_tnode, int ****snode_block_pin_to_tnode, t_subblock_data subblock_data, t_timing_inf timing_inf) |
static void | build_fb_tnodes (int iblk, int *n_uses_of_fb_ipin, int **block_pin_to_tnode, int ***sub_pin_to_tnode, int num_subs, t_subblock *sub_inf, float T_fb_ipin_to_sblk_ipin) |
static void | build_subblock_tnodes (int **n_uses_of_sblk_opin, int *node_block_pin_to_tnode, int ***sub_pin_to_tnode, int *num_subblocks_per_block, t_subblock **subblock_inf, t_timing_inf timing_inf, int iblk) |
static boolean | is_global_clock (int iblk, int sub, int subpin, int *num_subblocks_per_block, t_subblock **subblock_inf) |
static void | build_block_output_tnode (int inode, int iblk, int ipin, int **block_pin_to_tnode) |
float ** | alloc_and_load_timing_graph (t_timing_inf timing_inf, t_subblock_data subblock_data) |
void | load_timing_graph_net_delays (float **net_delay) |
void | free_timing_graph (float **net_slack) |
void | print_net_slack (char *fname, float **net_slack) |
void | print_timing_graph (char *fname) |
float | load_net_slack (float **net_slack, float target_cycle_time) |
void | print_critical_path (char *fname, t_subblock_data subblock_data) |
t_linked_int * | allocate_and_load_critical_path (void) |
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) |
Variables | |
static struct s_linked_vptr * | tedge_ch_list_head = NULL |
static int | tedge_ch_bytes_avail = 0 |
static char * | tedge_ch_next_avail = NULL |
#define T_CONSTANT_GENERATOR -1000 |
Definition at line 76 of file path_delay.c.
enum e_subblock_pin_type |
Definition at line 80 of file path_delay.c.
00081 { SUB_INPUT = 0, SUB_OUTPUT, SUB_CLOCK, NUM_SUB_PIN_TYPES };
static void alloc_and_load_fanout_counts | ( | int *** | num_uses_of_fb_ipin_ptr, | |
int **** | num_uses_of_sblk_opin_ptr, | |||
t_subblock_data | subblock_data | |||
) | [static] |
Definition at line 456 of file path_delay.c.
00459 { 00460 00461 /* Allocates and loads two arrays that say how many points each fb input * 00462 * pin and each subblock output fan out to. */ 00463 00464 int iblk; 00465 int **num_uses_of_fb_ipin, ***num_uses_of_sblk_opin; 00466 int *num_subblocks_per_block; 00467 t_subblock **subblock_inf; 00468 00469 num_subblocks_per_block = subblock_data.num_subblocks_per_block; 00470 subblock_inf = subblock_data.subblock_inf; 00471 00472 num_uses_of_fb_ipin = (int **)my_malloc(num_blocks * sizeof(int *)); 00473 00474 num_uses_of_sblk_opin = (int ***)my_malloc(num_blocks * sizeof(int **)); 00475 00476 for(iblk = 0; iblk < num_blocks; iblk++) 00477 { 00478 num_uses_of_fb_ipin[iblk] = 00479 (int *)my_calloc(block[iblk].type->num_pins, sizeof(int)); 00480 num_uses_of_sblk_opin[iblk] = 00481 (int **)alloc_matrix(0, block[iblk].type->max_subblocks - 1, 00482 0, 00483 block[iblk].type->max_subblock_outputs - 00484 1, sizeof(int)); 00485 00486 load_one_fb_fanout_count(subblock_inf[iblk], 00487 num_subblocks_per_block[iblk], 00488 num_uses_of_fb_ipin[iblk], 00489 num_uses_of_sblk_opin[iblk], iblk); 00490 00491 } /* End for all blocks */ 00492 00493 *num_uses_of_fb_ipin_ptr = num_uses_of_fb_ipin; 00494 *num_uses_of_sblk_opin_ptr = num_uses_of_sblk_opin; 00495 }
static int alloc_and_load_pin_mappings | ( | int *** | block_pin_to_tnode_ptr, | |
int ***** | snode_block_pin_to_tnode_ptr, | |||
t_subblock_data | subblock_data, | |||
int *** | num_uses_of_sblk_opin | |||
) | [static] |
Definition at line 279 of file path_delay.c.
00283 { 00284 00285 /* Allocates and loads the block_pin_to_tnode and snode_block_pin_to_tnode * 00286 * structures, and computes num_tnodes. */ 00287 00288 int iblk, isub, ipin, num_subblocks, opin, clk_pin; 00289 int curr_tnode; 00290 int ****snode_block_pin_to_tnode, **block_pin_to_tnode; 00291 int *num_subblocks_per_block; 00292 t_type_ptr type; 00293 t_subblock **subblock_inf; 00294 boolean has_inputs; 00295 00296 num_subblocks_per_block = subblock_data.num_subblocks_per_block; 00297 subblock_inf = subblock_data.subblock_inf; 00298 00299 00300 block_pin_to_tnode = (int **)my_malloc(num_blocks * sizeof(int *)); 00301 00302 snode_block_pin_to_tnode = 00303 (int ****)my_malloc(num_blocks * sizeof(int ***)); 00304 00305 curr_tnode = 0; 00306 00307 for(iblk = 0; iblk < num_blocks; iblk++) 00308 { 00309 type = block[iblk].type; 00310 block_pin_to_tnode[iblk] = 00311 (int *)my_malloc(type->num_pins * sizeof(int)); 00312 /* First do the block mapping */ 00313 for(ipin = 0; ipin < block[iblk].type->num_pins; ipin++) 00314 { 00315 if(block[iblk].nets[ipin] == OPEN) 00316 { 00317 block_pin_to_tnode[iblk][ipin] = OPEN; 00318 } 00319 else 00320 { 00321 block_pin_to_tnode[iblk][ipin] = curr_tnode; 00322 curr_tnode++; 00323 } 00324 } 00325 00326 /* Now do the subblock mapping. */ 00327 00328 num_subblocks = num_subblocks_per_block[iblk]; 00329 snode_block_pin_to_tnode[iblk] = (int ***)alloc_matrix(0, num_subblocks - 1, 0, NUM_SUB_PIN_TYPES - 1, sizeof(int *)); /* [0..max_subblocks_for_type - 1][0..SUB_NUM_PIN_TYPES - 1] */ 00330 00331 for(isub = 0; isub < num_subblocks; isub++) 00332 { 00333 /* Allocate space for each type of subblock pin */ 00334 snode_block_pin_to_tnode[iblk][isub][SUB_INPUT] = 00335 (int *)my_malloc(type->max_subblock_inputs * 00336 sizeof(int)); 00337 snode_block_pin_to_tnode[iblk][isub][SUB_OUTPUT] = 00338 (int *)my_malloc(type->max_subblock_outputs * 00339 sizeof(int)); 00340 snode_block_pin_to_tnode[iblk][isub][SUB_CLOCK] = 00341 (int *)my_malloc(sizeof(int)); 00342 00343 /* Pin ordering: inputs, outputs, clock. */ 00344 00345 has_inputs = FALSE; 00346 for(ipin = 0; ipin < type->max_subblock_inputs; ipin++) 00347 { 00348 if(subblock_inf[iblk][isub].inputs[ipin] != OPEN) 00349 { 00350 has_inputs = TRUE; 00351 snode_block_pin_to_tnode[iblk][isub] 00352 [SUB_INPUT][ipin] = curr_tnode; 00353 curr_tnode++; 00354 if(type == IO_TYPE) 00355 curr_tnode++; /* Output pad needs additional dummy sink node */ 00356 } 00357 else 00358 { 00359 snode_block_pin_to_tnode[iblk][isub] 00360 [SUB_INPUT][ipin] = OPEN; 00361 } 00362 } 00363 00364 /* subblock output */ 00365 00366 /* If the subblock opin is unused the subblock is empty and we * 00367 * shoudn't count it. */ 00368 for(opin = 0; opin < type->max_subblock_outputs; opin++) 00369 { 00370 00371 if(num_uses_of_sblk_opin[iblk][isub][opin] != 0) 00372 { 00373 snode_block_pin_to_tnode[iblk][isub] 00374 [SUB_OUTPUT][opin] = curr_tnode; 00375 00376 if(type == IO_TYPE) 00377 curr_tnode += 2; /* Input pad needs a dummy source node */ 00378 else if(has_inputs) /* Regular sblk */ 00379 curr_tnode++; 00380 else /* Constant generator. Make room for dummy input */ 00381 curr_tnode += 2; 00382 } 00383 else 00384 { 00385 snode_block_pin_to_tnode[iblk][isub] 00386 [SUB_OUTPUT][opin] = OPEN; 00387 } 00388 } 00389 00390 clk_pin = 0; 00391 00392 if(subblock_inf[iblk][isub].clock != OPEN) 00393 { 00394 00395 /* If this is a sequential block, we have two more pins per used output: #1: the 00396 * clock input (connects to the subblock output node) and #2: the 00397 * sequential sink (which the subblock LUT inputs will connect to). */ 00398 snode_block_pin_to_tnode[iblk][isub][SUB_CLOCK] 00399 [clk_pin] = curr_tnode; 00400 00401 for(opin = 0; opin < type->max_subblock_outputs; 00402 opin++) 00403 { 00404 if(subblock_inf[iblk][isub]. 00405 outputs[opin] != OPEN) 00406 curr_tnode += 2; 00407 } 00408 } 00409 else 00410 { 00411 snode_block_pin_to_tnode[iblk][isub][SUB_CLOCK] 00412 [clk_pin] = OPEN; 00413 } 00414 } 00415 00416 } /* End for all blocks */ 00417 00418 *snode_block_pin_to_tnode_ptr = snode_block_pin_to_tnode; 00419 *block_pin_to_tnode_ptr = block_pin_to_tnode; 00420 return (curr_tnode); 00421 }
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 }
static void alloc_and_load_tnodes_and_net_mapping | ( | int ** | num_uses_of_fb_ipin, | |
int *** | num_uses_of_sblk_opin, | |||
int ** | block_pin_to_tnode, | |||
int **** | snode_block_pin_to_tnode, | |||
t_subblock_data | subblock_data, | |||
t_timing_inf | timing_inf | |||
) | [static] |
Definition at line 522 of file path_delay.c.
00528 { 00529 00530 int iblk; 00531 int *num_subblocks_per_block; 00532 t_subblock **subblock_inf; 00533 00534 00535 tnode = (t_tnode *) my_malloc(num_tnodes * sizeof(t_tnode)); 00536 tnode_descript = (t_tnode_descript *) my_malloc(num_tnodes * 00537 sizeof(t_tnode_descript)); 00538 00539 net_to_driver_tnode = (int *)my_malloc(num_nets * sizeof(int)); 00540 00541 subblock_inf = subblock_data.subblock_inf; 00542 num_subblocks_per_block = subblock_data.num_subblocks_per_block; 00543 00544 00545 for(iblk = 0; iblk < num_blocks; iblk++) 00546 { 00547 build_fb_tnodes(iblk, num_uses_of_fb_ipin[iblk], 00548 block_pin_to_tnode, 00549 snode_block_pin_to_tnode[iblk], 00550 num_subblocks_per_block[iblk], subblock_inf[iblk], 00551 block[iblk].type->type_timing_inf. 00552 T_fb_ipin_to_sblk_ipin); 00553 00554 build_subblock_tnodes(num_uses_of_sblk_opin[iblk], 00555 block_pin_to_tnode[iblk], 00556 snode_block_pin_to_tnode[iblk], 00557 num_subblocks_per_block, subblock_inf, 00558 timing_inf, iblk); 00559 } 00560 }
static float ** alloc_net_slack | ( | void | ) | [static] |
Definition at line 253 of file path_delay.c.
00254 { 00255 00256 /* Allocates the net_slack structure. Chunk allocated to save space. */ 00257 00258 float **net_slack; /* [0..num_nets-1][1..num_pins-1] */ 00259 float *tmp_ptr; 00260 int inet; 00261 00262 net_slack = (float **)my_malloc(num_nets * sizeof(float *)); 00263 00264 for(inet = 0; inet < num_nets; inet++) 00265 { 00266 tmp_ptr = 00267 (float *)my_chunk_malloc(((net[inet].num_sinks + 1) - 1) * 00268 sizeof(float), &tedge_ch_list_head, 00269 &tedge_ch_bytes_avail, 00270 &tedge_ch_next_avail); 00271 net_slack[inet] = tmp_ptr - 1; /* [1..num_pins-1] */ 00272 } 00273 00274 return (net_slack); 00275 }
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 }
static void build_block_output_tnode | ( | int | inode, | |
int | iblk, | |||
int | ipin, | |||
int ** | block_pin_to_tnode | |||
) | [static] |
Definition at line 702 of file path_delay.c.
00706 { 00707 00708 /* Sets the number of edges and the edge array for an output pin from a * 00709 * block. This pin must be hooked to something -- i.e. not OPEN. */ 00710 00711 int iedge, to_blk, to_pin, to_node, num_edges, inet; 00712 t_tedge *tedge; 00713 00714 inet = block[iblk].nets[ipin]; /* Won't be OPEN, as inode exists */ 00715 assert(inet != OPEN); /* Sanity check. */ 00716 00717 net_to_driver_tnode[inet] = inode; 00718 00719 num_edges = (net[inet].num_sinks + 1) - 1; 00720 tnode[inode].num_edges = num_edges; 00721 00722 tnode[inode].out_edges = (t_tedge *) my_chunk_malloc(num_edges * 00723 sizeof(t_tedge), 00724 &tedge_ch_list_head, 00725 &tedge_ch_bytes_avail, 00726 &tedge_ch_next_avail); 00727 00728 tedge = tnode[inode].out_edges; 00729 00730 for(iedge = 0; iedge < (net[inet].num_sinks + 1) - 1; iedge++) 00731 { 00732 to_blk = net[inet].node_block[iedge + 1]; 00733 00734 to_pin = net[inet].node_block_pin[iedge + 1]; 00735 00736 to_node = block_pin_to_tnode[to_blk][to_pin]; 00737 tedge[iedge].to_node = to_node; 00738 /* Set delay from net delays with a later call */ 00739 } 00740 }
static void build_fb_tnodes | ( | int | iblk, | |
int * | n_uses_of_fb_ipin, | |||
int ** | block_pin_to_tnode, | |||
int *** | sub_pin_to_tnode, | |||
int | num_subs, | |||
t_subblock * | sub_inf, | |||
float | T_fb_ipin_to_sblk_ipin | |||
) | [static] |
Definition at line 564 of file path_delay.c.
00571 { 00572 00573 /* This routine builds the tnodes corresponding to the fb pins of this 00574 * block, and properly hooks them up to the rest of the graph. Note that 00575 * only the snode_block_pin_to_tnode, etc. element for this block is passed in. 00576 * Assumes that pins are ordered as [inputs][outputs][clk] 00577 */ 00578 00579 int isub, ipin, iedge, from_pin, opin; 00580 int inode, to_node, num_edges; 00581 t_tedge *tedge; 00582 int clk_pin; 00583 t_type_ptr type; 00584 int *next_ipin_edge; 00585 00586 type = block[iblk].type; 00587 next_ipin_edge = (int *)my_malloc(type->num_pins * sizeof(int)); 00588 clk_pin = 0; 00589 00590 /* Start by allocating the edge arrays, and for opins, loading them. */ 00591 00592 for(ipin = 0; ipin < block[iblk].type->num_pins; ipin++) 00593 { 00594 inode = block_pin_to_tnode[iblk][ipin]; 00595 00596 if(inode != OPEN) 00597 { /* Pin is used -> put in graph */ 00598 if(is_opin(ipin, block[iblk].type)) 00599 { 00600 build_block_output_tnode(inode, iblk, ipin, 00601 block_pin_to_tnode); 00602 tnode_descript[inode].type = FB_OPIN; 00603 } 00604 else 00605 { /* FB ipin */ 00606 next_ipin_edge[ipin] = 0; /* Reset */ 00607 num_edges = n_uses_of_fb_ipin[ipin]; 00608 00609 /* if clock pin, timing edges go to each subblock output used */ 00610 for(isub = 0; isub < num_subs; isub++) 00611 { 00612 if(sub_inf[isub].clock == ipin) 00613 { 00614 for(opin = 0; 00615 opin < 00616 type->max_subblock_outputs; 00617 opin++) 00618 { 00619 if(sub_inf[isub]. 00620 outputs[opin] != OPEN) 00621 { 00622 num_edges++; 00623 } 00624 } 00625 num_edges--; /* Remove clock_pin count, replaced by outputs */ 00626 } 00627 } 00628 00629 tnode[inode].num_edges = num_edges; 00630 00631 tnode[inode].out_edges = 00632 (t_tedge *) my_chunk_malloc(num_edges * 00633 sizeof(t_tedge), 00634 &tedge_ch_list_head, 00635 &tedge_ch_bytes_avail, 00636 &tedge_ch_next_avail); 00637 00638 tnode_descript[inode].type = FB_IPIN; 00639 } 00640 00641 tnode_descript[inode].ipin = ipin; 00642 tnode_descript[inode].isubblk = OPEN; 00643 tnode_descript[inode].iblk = iblk; 00644 } 00645 } 00646 00647 /* Now load the edge arrays for the FB input pins. Do this by looking at * 00648 * where the subblock input and clock pins are driven from. */ 00649 00650 for(isub = 0; isub < num_subs; isub++) 00651 { 00652 for(ipin = 0; ipin < type->max_subblock_inputs; ipin++) 00653 { 00654 from_pin = sub_inf[isub].inputs[ipin]; 00655 00656 /* Not OPEN and comes from fb ipin? */ 00657 00658 if(from_pin != OPEN 00659 && from_pin < block[iblk].type->num_pins) 00660 { 00661 inode = block_pin_to_tnode[iblk][from_pin]; 00662 assert(inode != OPEN); 00663 to_node = sub_pin_to_tnode[isub][SUB_INPUT][ipin]; 00664 tedge = tnode[inode].out_edges; 00665 iedge = next_ipin_edge[from_pin]++; 00666 tedge[iedge].to_node = to_node; 00667 tedge[iedge].Tdel = T_fb_ipin_to_sblk_ipin; 00668 } 00669 } 00670 00671 from_pin = sub_inf[isub].clock; 00672 00673 if(from_pin != OPEN && from_pin < block[iblk].type->num_pins) 00674 { 00675 inode = block_pin_to_tnode[iblk][from_pin]; 00676 to_node = sub_pin_to_tnode[isub][SUB_CLOCK][clk_pin]; /* Feeds seq. output */ 00677 /* connect to each output flip flop */ 00678 for(opin = 0; opin < type->max_subblock_outputs; opin++) 00679 { 00680 if(sub_inf[isub].outputs[opin] != OPEN) 00681 { 00682 tedge = tnode[inode].out_edges; 00683 iedge = next_ipin_edge[from_pin]++; 00684 tedge[iedge].to_node = to_node; 00685 00686 /* For the earliest possible clock I want this delay to be zero, so it * 00687 * * arrives at flip flops at T = 0. For later clocks or locally generated * 00688 * * clocks that may accumulate delay (like the clocks in a ripple counter), * 00689 * * I might want to make this delay nonzero. Not worth bothering about now. */ 00690 00691 tedge[iedge].Tdel = 0.; 00692 to_node += 2; 00693 } 00694 } 00695 } 00696 } 00697 free(next_ipin_edge); 00698 }
static void build_subblock_tnodes | ( | int ** | n_uses_of_sblk_opin, | |
int * | node_block_pin_to_tnode, | |||
int *** | sub_pin_to_tnode, | |||
int * | num_subblocks_per_block, | |||
t_subblock ** | subblock_inf, | |||
t_timing_inf | timing_inf, | |||
int | iblk | |||
) | [static] |
Definition at line 744 of file path_delay.c.
00751 { 00752 00753 /* This routine builds the tnodes of the subblock pins within one FB. Note * 00754 * that only the block_pin_to_tnode, etc. data for *this* block are passed * 00755 * in. */ 00756 00757 int isub, ipin, inode, to_node, from_pin, to_pin, opin, from_opin, 00758 clk_pin, used_opin_count; 00759 int num_subs, from_sub; 00760 t_subblock *sub_inf; 00761 int iedge, num_edges; 00762 float sink_delay; 00763 t_tedge *tedge; 00764 boolean has_inputs, has_outputs; 00765 int **next_sblk_opin_edge; /* [0..max_subblocks-1][0..max_subblock_outputs-1] */ 00766 int *num_opin_used_in_sblk; /* [0..max_subblocks-1] */ 00767 t_type_ptr type = block[iblk].type; 00768 00769 sub_inf = subblock_inf[iblk]; 00770 num_subs = num_subblocks_per_block[iblk]; 00771 00772 next_sblk_opin_edge = 00773 (int **)alloc_matrix(0, type->max_subblocks - 1, 0, 00774 type->max_subblock_outputs - 1, sizeof(int)); 00775 num_opin_used_in_sblk = 00776 (int *)my_malloc(type->max_subblocks * sizeof(int)); 00777 00778 clk_pin = 0; 00779 00780 /* Allocate memory for output pins first. */ 00781 for(isub = 0; isub < num_subs; isub++) 00782 { 00783 num_opin_used_in_sblk[isub] = 0; 00784 for(opin = 0; opin < type->max_subblock_outputs; opin++) 00785 { 00786 inode = sub_pin_to_tnode[isub][SUB_OUTPUT][opin]; 00787 00788 if(inode != OPEN) 00789 { /* Output is used -> timing node exists. */ 00790 num_opin_used_in_sblk[isub]++; 00791 next_sblk_opin_edge[isub][opin] = 0; /* Reset */ 00792 num_edges = n_uses_of_sblk_opin[isub][opin]; 00793 tnode[inode].num_edges = num_edges; 00794 00795 tnode[inode].out_edges = 00796 (t_tedge *) my_chunk_malloc(num_edges * 00797 sizeof(t_tedge), 00798 &tedge_ch_list_head, 00799 &tedge_ch_bytes_avail, 00800 &tedge_ch_next_avail); 00801 00802 if(IO_TYPE == type) 00803 { 00804 tnode_descript[inode].type = INPAD_OPIN; 00805 tnode[inode + 1].num_edges = 1; 00806 tnode[inode + 1].out_edges = (t_tedge *) 00807 my_chunk_malloc(sizeof(t_tedge), 00808 &tedge_ch_list_head, 00809 &tedge_ch_bytes_avail, 00810 &tedge_ch_next_avail); 00811 tedge = tnode[inode + 1].out_edges; 00812 tedge[0].to_node = inode; 00813 00814 /* For input pads, use sequential output for source timing delay (treat as register) */ 00815 if(is_global_clock 00816 (iblk, isub, opin, 00817 num_subblocks_per_block, 00818 subblock_inf)) 00819 tedge[0].Tdel = 0.; 00820 else 00821 tedge[0].Tdel = 00822 type->type_timing_inf. 00823 T_subblock[isub].T_seq_out[opin]; 00824 00825 tnode_descript[inode + 1].type = 00826 INPAD_SOURCE; 00827 tnode_descript[inode + 1].ipin = OPEN; 00828 tnode_descript[inode + 1].isubblk = isub; 00829 tnode_descript[inode + 1].iblk = iblk; 00830 } 00831 else 00832 { 00833 tnode_descript[inode].type = SUBBLK_OPIN; 00834 } 00835 00836 tnode_descript[inode].ipin = opin; 00837 tnode_descript[inode].isubblk = isub; 00838 tnode_descript[inode].iblk = iblk; 00839 } 00840 } 00841 } 00842 00843 /* First pass, load the subblock input pins to output pins without connecting edges to output pins. 00844 * If the subblock is used in sequential mode (i.e. is clocked), the two clock pin nodes. 00845 * Connect edges to output pins and take care of constant generators in second pass 00846 */ 00847 for(isub = 0; isub < num_subs; isub++) 00848 { 00849 has_outputs = FALSE; 00850 00851 for(opin = 0; opin < type->max_subblock_outputs; opin++) 00852 { 00853 if(sub_pin_to_tnode[isub][SUB_OUTPUT][opin] != OPEN) 00854 { 00855 has_outputs = TRUE; 00856 } 00857 } 00858 00859 if(!has_outputs && type != IO_TYPE) 00860 { /* Empty, so skip */ 00861 continue; 00862 } 00863 00864 if(sub_inf[isub].clock != OPEN) 00865 { /* Sequential mode */ 00866 inode = sub_pin_to_tnode[isub][SUB_CLOCK][clk_pin]; 00867 /* Each output of a subblock has a flip-flop sink and source */ 00868 for(opin = 0; opin < type->max_subblock_outputs; opin++) 00869 { 00870 if(sub_inf[isub].outputs[opin] != OPEN) 00871 { 00872 /* First node is the clock input pin; it feeds the sequential output */ 00873 tnode[inode].num_edges = 1; 00874 tnode[inode].out_edges = (t_tedge *) 00875 my_chunk_malloc(sizeof(t_tedge), 00876 &tedge_ch_list_head, 00877 &tedge_ch_bytes_avail, 00878 &tedge_ch_next_avail); 00879 00880 tnode_descript[inode].type = FF_SOURCE; 00881 tnode_descript[inode].ipin = OPEN; 00882 tnode_descript[inode].isubblk = isub; 00883 tnode_descript[inode].iblk = iblk; 00884 00885 /* Now create the "sequential sink" -- i.e. the FF input node. */ 00886 00887 inode++; 00888 tnode[inode].num_edges = 0; 00889 tnode[inode].out_edges = NULL; 00890 00891 tnode_descript[inode].type = FF_SINK; 00892 tnode_descript[inode].ipin = OPEN; 00893 tnode_descript[inode].isubblk = isub; 00894 tnode_descript[inode].iblk = iblk; 00895 inode++; 00896 } 00897 } 00898 } 00899 00900 /* Build and hook up subblock inputs. */ 00901 00902 for(ipin = 0; ipin < type->max_subblock_inputs; ipin++) 00903 { 00904 inode = sub_pin_to_tnode[isub][SUB_INPUT][ipin]; 00905 00906 if(inode != OPEN) 00907 { /* tnode exists -> pin is used */ 00908 if(type == IO_TYPE) 00909 { /* Output pad */ 00910 tnode[inode].num_edges = 1; 00911 opin = 0; 00912 tnode[inode].out_edges = (t_tedge *) 00913 my_chunk_malloc(sizeof(t_tedge), 00914 &tedge_ch_list_head, 00915 &tedge_ch_bytes_avail, 00916 &tedge_ch_next_avail); 00917 tnode_descript[inode].type = OUTPAD_IPIN; 00918 tnode[inode + 1].num_edges = 0; 00919 tnode[inode + 1].out_edges = NULL; 00920 tedge = tnode[inode].out_edges; 00921 tedge[0].to_node = inode + 1; 00922 00923 /* For output pads, use subblock combinational time 00924 * and sequential in for timing (treat as register) */ 00925 tedge[0].Tdel = 00926 type->type_timing_inf. 00927 T_subblock[isub].T_comb[ipin][opin] + 00928 type->type_timing_inf. 00929 T_subblock[isub].T_seq_in[opin]; 00930 00931 tnode_descript[inode + 1].type = 00932 OUTPAD_SINK; 00933 tnode_descript[inode + 1].ipin = OPEN; 00934 tnode_descript[inode + 1].isubblk = isub; 00935 tnode_descript[inode + 1].iblk = iblk; 00936 } 00937 else 00938 { 00939 tnode[inode].num_edges = 00940 num_opin_used_in_sblk[isub]; 00941 tnode[inode].out_edges = 00942 (t_tedge *) 00943 my_chunk_malloc(num_opin_used_in_sblk 00944 [isub] * 00945 sizeof(t_tedge), 00946 &tedge_ch_list_head, 00947 &tedge_ch_bytes_avail, 00948 &tedge_ch_next_avail); 00949 tnode[inode].num_edges = 00950 num_opin_used_in_sblk[isub]; 00951 tnode_descript[inode].type = SUBBLK_IPIN; 00952 } 00953 00954 tnode_descript[inode].ipin = ipin; 00955 tnode_descript[inode].isubblk = isub; 00956 tnode_descript[inode].iblk = iblk; 00957 } 00958 } 00959 } /* End for each subblock */ 00960 00961 /* Second pass load the input pins to output pins array */ 00962 /* Load the output pins edge arrays. */ 00963 for(isub = 0; isub < num_subs; isub++) 00964 { 00965 used_opin_count = 0; 00966 for(opin = 0; opin < type->max_subblock_outputs; opin++) 00967 { 00968 if(sub_pin_to_tnode[isub][SUB_OUTPUT][opin] == OPEN) 00969 { /* Empty, so skip */ 00970 continue; 00971 } 00972 for(ipin = 0; ipin < type->max_subblock_inputs; ipin++) 00973 { /* sblk opin to sblk ipin */ 00974 00975 from_pin = sub_inf[isub].inputs[ipin]; 00976 00977 /* Not OPEN and comes from local subblock output? */ 00978 00979 if(from_pin >= type->num_pins) 00980 { 00981 /* Convention for numbering netlist pins. 00982 * Internal connections are numbered subblock_index + subblock_output_index + num_pins 00983 */ 00984 from_sub = 00985 (from_pin - 00986 type->num_pins) / 00987 type->max_subblock_outputs; 00988 from_opin = 00989 (from_pin - 00990 type->num_pins) % 00991 type->max_subblock_outputs; 00992 inode = 00993 sub_pin_to_tnode[from_sub][SUB_OUTPUT] 00994 [from_opin]; 00995 to_node = 00996 sub_pin_to_tnode[isub][SUB_INPUT] 00997 [ipin]; 00998 tedge = tnode[inode].out_edges; 00999 iedge = next_sblk_opin_edge[from_sub] 01000 [from_opin]++; 01001 tedge[iedge].to_node = to_node; 01002 tedge[iedge].Tdel = 01003 type->type_timing_inf. 01004 T_sblk_opin_to_sblk_ipin; 01005 } 01006 } 01007 from_pin = sub_inf[isub].clock; /* sblk opin to sblk clock */ 01008 01009 /* Not OPEN and comes from local subblock output? */ 01010 01011 if(from_pin >= type->num_pins) 01012 { 01013 from_sub = 01014 (from_pin - 01015 type->num_pins) / type->max_subblock_outputs; 01016 from_opin = 01017 (from_pin - 01018 type->num_pins) % type->max_subblock_outputs; 01019 inode = sub_pin_to_tnode[from_sub][SUB_OUTPUT] 01020 [from_opin]; 01021 /* Feeds seq. output, one ff per output pin */ 01022 to_node = 01023 sub_pin_to_tnode[isub][SUB_CLOCK][clk_pin] + 01024 2 * used_opin_count; 01025 tedge = tnode[inode].out_edges; 01026 iedge = 01027 next_sblk_opin_edge[from_sub][from_opin]++; 01028 tedge[iedge].to_node = to_node; 01029 01030 /* NB: Could make sblk opin to clk delay parameter; not worth it right now. */ 01031 tedge[iedge].Tdel = 01032 type->type_timing_inf. 01033 T_sblk_opin_to_sblk_ipin; 01034 } 01035 01036 to_pin = sub_inf[isub].outputs[opin]; 01037 if(to_pin != OPEN) 01038 { /* sblk opin goes to fb opin? */ 01039 01040 /* Check that FB pin connects to something -> * 01041 * not just a mandatory BLE to FB opin connection */ 01042 01043 if(block[iblk].nets[to_pin] != OPEN) 01044 { 01045 to_node = node_block_pin_to_tnode[to_pin]; 01046 inode = sub_pin_to_tnode[isub][SUB_OUTPUT] 01047 [opin]; 01048 tedge = tnode[inode].out_edges; 01049 iedge = next_sblk_opin_edge[isub][opin]++; 01050 tedge[iedge].to_node = to_node; 01051 tedge[iedge].Tdel = 01052 type->type_timing_inf. 01053 T_sblk_opin_to_fb_opin; 01054 } 01055 } 01056 used_opin_count++; 01057 } 01058 } 01059 01060 /* Now load the subblock input pins and, if the subblock is used in * 01061 * sequential mode (i.e. is clocked), the two clock pin nodes for the output pin. */ 01062 for(isub = 0; isub < num_subs; isub++) 01063 { 01064 used_opin_count = 0; 01065 for(opin = 0; opin < type->max_subblock_outputs; opin++) 01066 { 01067 01068 if(sub_pin_to_tnode[isub][SUB_OUTPUT][opin] == OPEN) /* Empty, so skip */ 01069 continue; 01070 /* Begin loading */ 01071 if(sub_inf[isub].clock == OPEN) 01072 { /* Combinational mode */ 01073 to_node = 01074 sub_pin_to_tnode[isub][SUB_OUTPUT][opin]; 01075 sink_delay = 0; 01076 } 01077 else 01078 { /* Sequential mode. Load two clock nodes. */ 01079 inode = 01080 sub_pin_to_tnode[isub][SUB_CLOCK][clk_pin] + 01081 2 * used_opin_count; 01082 01083 /* First node is the clock input pin; it feeds the sequential output */ 01084 tedge = tnode[inode].out_edges; 01085 tedge[0].to_node = 01086 sub_pin_to_tnode[isub][SUB_OUTPUT][opin]; 01087 tedge[0].Tdel = 01088 type->type_timing_inf.T_subblock[isub]. 01089 T_seq_out[opin]; 01090 01091 /* Now create the "sequential sink" -- i.e. the FF input node. */ 01092 01093 inode++; 01094 to_node = inode; 01095 sink_delay = 01096 type->type_timing_inf.T_subblock[isub]. 01097 T_seq_in[opin]; 01098 } 01099 01100 /* Build and hook up subblock inputs. */ 01101 01102 has_inputs = FALSE; 01103 for(ipin = 0; ipin < type->max_subblock_inputs; ipin++) 01104 { 01105 inode = sub_pin_to_tnode[isub][SUB_INPUT][ipin]; 01106 01107 if(inode != OPEN) 01108 { /* tnode exists -> pin is used */ 01109 has_inputs = TRUE; 01110 tedge = tnode[inode].out_edges; 01111 tedge[used_opin_count].to_node = to_node; 01112 tedge[used_opin_count].Tdel = 01113 sink_delay + 01114 type->type_timing_inf. 01115 T_subblock[isub].T_comb[ipin][opin]; 01116 } 01117 } 01118 01119 if(!has_inputs && type != IO_TYPE) 01120 { /* Constant generator. Give fake input. */ 01121 01122 inode = 01123 sub_pin_to_tnode[isub][SUB_OUTPUT][opin] + 1; 01124 tnode[inode].num_edges = 1; 01125 tnode[inode].out_edges = 01126 (t_tedge *) my_chunk_malloc(sizeof(t_tedge), 01127 &tedge_ch_list_head, 01128 &tedge_ch_bytes_avail, 01129 &tedge_ch_next_avail); 01130 tedge = tnode[inode].out_edges; 01131 tedge[used_opin_count].to_node = to_node; 01132 01133 /* Want constants generated early so they never affect the critical path. */ 01134 01135 tedge[used_opin_count].Tdel = 01136 T_CONSTANT_GENERATOR; 01137 01138 tnode_descript[inode].type = CONSTANT_GEN_SOURCE; 01139 tnode_descript[inode].ipin = OPEN; 01140 tnode_descript[inode].isubblk = isub; 01141 tnode_descript[inode].iblk = iblk; 01142 } 01143 used_opin_count++; 01144 } 01145 } 01146 free_matrix(next_sblk_opin_edge, 0, type->max_subblocks - 1, 0, 01147 sizeof(int)); 01148 free(num_opin_used_in_sblk); 01149 }
static void compute_net_slacks | ( | float ** | net_slack | ) | [static] |
Definition at line 1452 of file path_delay.c.
01453 { 01454 01455 /* Puts the slack of each source-sink pair of block pins in net_slack. */ 01456 01457 int inet, iedge, inode, to_node, num_edges; 01458 t_tedge *tedge; 01459 float T_arr, Tdel, T_req; 01460 01461 for(inet = 0; inet < num_nets; inet++) 01462 { 01463 inode = net_to_driver_tnode[inet]; 01464 T_arr = tnode[inode].T_arr; 01465 num_edges = tnode[inode].num_edges; 01466 tedge = tnode[inode].out_edges; 01467 01468 for(iedge = 0; iedge < num_edges; iedge++) 01469 { 01470 to_node = tedge[iedge].to_node; 01471 Tdel = tedge[iedge].Tdel; 01472 T_req = tnode[to_node].T_req; 01473 net_slack[inet][iedge + 1] = T_req - T_arr - Tdel; 01474 } 01475 } 01476 }
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 }
static void free_fanout_counts | ( | int ** | num_uses_of_fb_ipin, | |
int *** | num_uses_of_sblk_opin | |||
) | [static] |
Definition at line 499 of file path_delay.c.
00501 { 00502 00503 /* Frees the fanout count arrays. */ 00504 00505 int iblk; 00506 t_type_ptr type; 00507 00508 for(iblk = 0; iblk < num_blocks; iblk++) 00509 { 00510 type = block[iblk].type; 00511 free(num_uses_of_fb_ipin[iblk]); 00512 free_matrix(num_uses_of_sblk_opin[iblk], 0, 00513 type->max_subblocks - 1, 0, sizeof(int)); 00514 } 00515 00516 free(num_uses_of_fb_ipin); 00517 free(num_uses_of_sblk_opin); 00518 }
static void free_pin_mappings | ( | int ** | block_pin_to_tnode, | |
int **** | snode_block_pin_to_tnode, | |||
int * | num_subblocks_per_block | |||
) | [static] |
Definition at line 425 of file path_delay.c.
00428 { 00429 00430 /* Frees the arrays that map from pins to tnode coordinates. */ 00431 00432 int isub, iblk, isubtype, num_subblocks; 00433 00434 for(iblk = 0; iblk < num_blocks; iblk++) 00435 { 00436 num_subblocks = num_subblocks_per_block[iblk]; 00437 for(isub = 0; isub < num_subblocks; isub++) 00438 { 00439 for(isubtype = 0; isubtype < NUM_SUB_PIN_TYPES; 00440 isubtype++) 00441 { 00442 free(snode_block_pin_to_tnode[iblk][isub] 00443 [isubtype]); 00444 } 00445 } 00446 free_matrix(snode_block_pin_to_tnode[iblk], 0, 00447 num_subblocks_per_block[iblk] - 1, 0, sizeof(int *)); 00448 free(block_pin_to_tnode[iblk]); 00449 } 00450 free(block_pin_to_tnode); 00451 free(snode_block_pin_to_tnode); 00452 }
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 }
static boolean is_global_clock | ( | int | iblk, | |
int | sub, | |||
int | subpin, | |||
int * | num_subblocks_per_block, | |||
t_subblock ** | subblock_inf | |||
) | [static] |
Definition at line 1152 of file path_delay.c.
01157 { 01158 01159 /* Returns TRUE if the net driven by this block (which must be an INPAD) is * 01160 (1) a global signal, and (2) used as a clock input to at least one block. 01161 Assumes that there is only one subblock in an IO 01162 */ 01163 01164 int inet, ipin, to_blk, to_pin, isub; 01165 t_type_ptr type = block[iblk].type; 01166 01167 assert(type == IO_TYPE); 01168 01169 inet = block[iblk].nets[subblock_inf[iblk][sub].outputs[subpin]]; 01170 assert(inet != OPEN); 01171 01172 if(!net[inet].is_global) 01173 return (FALSE); 01174 01175 for(ipin = 1; ipin < (net[inet].num_sinks + 1); ipin++) 01176 { 01177 to_blk = net[inet].node_block[ipin]; 01178 to_pin = net[inet].node_block_pin[ipin]; 01179 01180 for(isub = 0; isub < num_subblocks_per_block[to_blk]; isub++) 01181 { 01182 if(subblock_inf[to_blk][isub].clock == to_pin) 01183 return (TRUE); 01184 } 01185 } 01186 01187 return (FALSE); 01188 }
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 }
int tedge_ch_bytes_avail = 0 [static] |
Definition at line 89 of file path_delay.c.
struct s_linked_vptr* tedge_ch_list_head = NULL [static] |
Definition at line 88 of file path_delay.c.
char* tedge_ch_next_avail = NULL [static] |
Definition at line 90 of file path_delay.c.