VPR-7.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
path_delay.h File Reference
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define DO_NOT_ANALYSE   -1
 
#define SLACK_DEFINITION   'R'
 

Functions

t_slackalloc_and_load_timing_graph (t_timing_inf timing_inf)
 
t_slackalloc_and_load_pre_packing_timing_graph (float block_delay, float inter_cluster_net_delay, t_model *models, t_timing_inf timing_inf)
 
t_linked_intallocate_and_load_critical_path (void)
 
void load_timing_graph_net_delays (float **net_delay)
 
void do_timing_analysis (t_slack *slacks, boolean is_prepacked, boolean do_lut_input_balancing, boolean is_final_analysis)
 
void free_timing_graph (t_slack *slack)
 
void free_timing_stats (void)
 
void print_timing_graph (const char *fname)
 
void print_lut_remapping (const char *fname)
 
void print_slack (float **slack, boolean slack_is_normalized, const char *fname)
 
void print_criticality (t_slack *slacks, boolean criticality_is_normalized, const char *fname)
 
void print_net_delay (float **net_delay, const char *fname)
 
void print_clustering_timing_info (const char *fname)
 
boolean has_valid_normalized_T_arr (int inode)
 
void print_timing_stats (void)
 
float get_critical_path_delay (void)
 
void print_critical_path (const char *fname)
 
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, float constant_net_delay_value)
 
void print_timing_graph_as_blif (const char *fname, t_model *models)
 

Variables

int num_tnodes
 
t_tnodetnode
 

Macro Definition Documentation

#define DO_NOT_ANALYSE   -1

Definition at line 4 of file path_delay.h.

#define SLACK_DEFINITION   'R'

Definition at line 8 of file path_delay.h.

Function Documentation

t_slack* alloc_and_load_pre_packing_timing_graph ( float  block_delay,
float  inter_cluster_net_delay,
t_model models,
t_timing_inf  timing_inf 
)

Definition at line 288 of file path_delay.c.

289  {
290 
291  /* This routine builds the graph used for timing analysis. Every technology-
292  * mapped netlist pin is a timing node (tnode). The connectivity between pins is *
293  * represented by timing edges (tedges). All delay is marked on edges, not *
294  * on nodes. Returns two arrays that will store slack values: *
295  * slack and criticality ([0..num_nets-1][1..num_pins]). */
296 
297  /* For pads, only the first two pin locations are used (input to pad is first,
298  * output of pad is second). For CLBs, all OPEN pins on the cb have their
299  * mapping set to OPEN so I won't use it by mistake. */
300 
301  int num_sinks;
302  t_slack * slacks = NULL;
303  boolean do_process_constraints = FALSE;
304 
305  if (tedge_ch.chunk_ptr_head != NULL) {
306  vpr_printf(TIO_MESSAGE_ERROR, "in alloc_and_load_timing_graph: An old timing graph still exists.\n");
307  exit(1);
308  }
309 
312 
314  inter_cluster_net_delay);
315 
317 
318  slacks = alloc_slacks();
319 
320  check_timing_graph(num_sinks);
321 
324  }
325 
326  if (g_sdc == NULL) {
327  /* the SDC timing constraints only need to be read in once; *
328  * if they haven't been already, do it now */
329  read_sdc(timing_inf);
330  do_process_constraints = TRUE;
331  }
332 
334 
335  if (do_process_constraints)
337 
338  if (f_timing_stats == NULL)
340 
341  return slacks;
342 }
static void alloc_and_load_tnodes_from_prepacked_netlist(float block_delay, float inter_cluster_net_delay)
Definition: path_delay.c:995
static t_chunk tedge_ch
Definition: path_delay.c:153
void check_timing_graph(int num_sinks)
Definition: path_delay2.c:161
static int num_timing_nets
Definition: path_delay.c:157
void print_timing_graph_as_blif(const char *fname, t_model *models)
Definition: path_delay.c:3360
static t_slack * alloc_slacks(void)
Definition: path_delay.c:344
static t_timing_stats * f_timing_stats
Definition: path_delay.c:159
int num_logical_nets
Definition: globals.c:17
struct s_linked_vptr * chunk_ptr_head
Definition: util.h:58
boolean getEchoEnabled(void)
Definition: ReadOptions.c:67
static void load_clock_domain_and_clock_and_io_delay(boolean is_prepacked)
Definition: path_delay.c:2807
Definition: util.h:12
void read_sdc(t_timing_inf timing_inf)
Definition: read_sdc.c:115
static void process_constraints(void)
Definition: path_delay.c:1489
boolean isEchoFileEnabled(enum e_echo_files echo_option)
Definition: ReadOptions.c:115
static void alloc_timing_stats(void)
Definition: path_delay.c:1598
static struct s_net * timing_nets
Definition: path_delay.c:155
struct s_net * vpack_net
Definition: globals.c:19
char * getEchoFileName(enum e_echo_files echo_option)
Definition: ReadOptions.c:122
t_timing_constraints * g_sdc
Definition: read_sdc.c:65
messagelogger vpr_printf
Definition: util.c:17
Definition: util.h:12
int alloc_and_load_timing_graph_levels(void)
Definition: path_delay2.c:81

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

t_slack* alloc_and_load_timing_graph ( t_timing_inf  timing_inf)

Definition at line 239 of file path_delay.c.

239  {
240 
241  /* This routine builds the graph used for timing analysis. Every cb pin is a
242  * timing node (tnode). The connectivity between pins is *
243  * represented by timing edges (tedges). All delay is marked on edges, not *
244  * on nodes. Returns two arrays that will store slack values: *
245  * slack and criticality ([0..num_nets-1][1..num_pins]). */
246 
247  /* For pads, only the first two pin locations are used (input to pad is first,
248  * output of pad is second). For CLBs, all OPEN pins on the cb have their
249  * mapping set to OPEN so I won't use it by mistake. */
250 
251  int num_sinks;
252  t_slack * slacks = NULL;
253  boolean do_process_constraints = FALSE;
254 
255  if (tedge_ch.chunk_ptr_head != NULL) {
256  vpr_printf(TIO_MESSAGE_ERROR, "in alloc_and_load_timing_graph: An old timing graph still exists.\n");
257  exit(1);
258  }
261 
262  alloc_and_load_tnodes(timing_inf);
263 
265 
266  check_timing_graph(num_sinks);
267 
268  slacks = alloc_slacks();
269 
270  if (g_sdc == NULL) {
271  /* the SDC timing constraints only need to be read in once; *
272  * if they haven't been already, do it now */
273  read_sdc(timing_inf);
274  do_process_constraints = TRUE;
275  }
276 
278 
279  if (do_process_constraints)
281 
282  if (f_timing_stats == NULL)
284 
285  return slacks;
286 }
static t_chunk tedge_ch
Definition: path_delay.c:153
void check_timing_graph(int num_sinks)
Definition: path_delay2.c:161
static int num_timing_nets
Definition: path_delay.c:157
static t_slack * alloc_slacks(void)
Definition: path_delay.c:344
static t_timing_stats * f_timing_stats
Definition: path_delay.c:159
int num_nets
Definition: globals.c:27
struct s_linked_vptr * chunk_ptr_head
Definition: util.h:58
static void load_clock_domain_and_clock_and_io_delay(boolean is_prepacked)
Definition: path_delay.c:2807
Definition: util.h:12
void read_sdc(t_timing_inf timing_inf)
Definition: read_sdc.c:115
struct s_net * clb_net
Definition: globals.c:28
static void process_constraints(void)
Definition: path_delay.c:1489
static void alloc_and_load_tnodes(t_timing_inf timing_inf)
Definition: path_delay.c:730
static void alloc_timing_stats(void)
Definition: path_delay.c:1598
static struct s_net * timing_nets
Definition: path_delay.c:155
t_timing_constraints * g_sdc
Definition: read_sdc.c:65
messagelogger vpr_printf
Definition: util.c:17
Definition: util.h:12
int alloc_and_load_timing_graph_levels(void)
Definition: path_delay2.c:81

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

t_linked_int* allocate_and_load_critical_path ( void  )

Definition at line 2522 of file path_delay.c.

2522  {
2523 
2524  /* Finds the critical path and returns a list of the tnodes on the critical *
2525  * path in a linked list, from the path SOURCE to the path SINK. */
2526 
2527  t_linked_int *critical_path_head, *curr_crit_node, *prev_crit_node;
2528  int inode, iedge, to_node, num_at_level_zero, i, j, crit_node = OPEN, num_edges;
2529  int source_clock_domain = UNDEFINED, sink_clock_domain = UNDEFINED;
2530  float min_slack = HUGE_POSITIVE_FLOAT, slack;
2531  t_tedge *tedge;
2532 
2533  /* If there's only one clock, we can use the arrival and required times
2534  currently on the timing graph to find the critical path. If there are multiple
2535  clocks, however, the values currently on the timing graph correspond to the
2536  last constraint (pair of clock domains) analysed, which may not be the constraint
2537  with the critical path. In this case, we have to find the constraint with the
2538  least slack and redo the timing analysis for this constraint so we get the right
2539  values onto the timing graph. */
2540 
2541  if (g_sdc->num_constrained_clocks > 1) {
2542  /* The critical path belongs to the source and sink clock domains
2543  with the least slack. Find these clock domains now. */
2544 
2545  for (i = 0; i < g_sdc->num_constrained_clocks; i++) {
2546  for (j = 0; j < g_sdc->num_constrained_clocks; j++) {
2547  if (min_slack > f_timing_stats->least_slack[i][j]) {
2548  min_slack = f_timing_stats->least_slack[i][j];
2549  source_clock_domain = i;
2550  sink_clock_domain = j;
2551  }
2552  }
2553  }
2554 
2555  /* Do a timing analysis for this clock domain pair only.
2556  Set is_prepacked to FALSE since we don't care about the clusterer's normalized values.
2557  Set is_final_analysis to FALSE to get actual, rather than relaxed, slacks.
2558  Set max critical input/output paths to NULL since they aren't used unless is_prepacked is TRUE. */
2559  do_timing_analysis_for_constraint(source_clock_domain, sink_clock_domain, FALSE, FALSE, (long*)NULL, (long*)NULL);
2560  }
2561 
2562  /* Start at the source (level-0) tnode with the least slack (T_req-T_arr).
2563  This will form the head of our linked list of tnodes on the critical path. */
2564  min_slack = HUGE_POSITIVE_FLOAT;
2565  num_at_level_zero = tnodes_at_level[0].nelem;
2566  for (i = 0; i < num_at_level_zero; i++) {
2567  inode = tnodes_at_level[0].list[i];
2568  if (has_valid_T_arr(inode) && has_valid_T_req(inode)) { /* Valid arrival and required times */
2569  slack = tnode[inode].T_req - tnode[inode].T_arr;
2570  if (slack < min_slack) {
2571  crit_node = inode;
2572  min_slack = slack;
2573  }
2574  }
2575  }
2576  critical_path_head = (t_linked_int *) my_malloc(sizeof(t_linked_int));
2577  critical_path_head->data = crit_node;
2578  assert(crit_node != OPEN);
2579  prev_crit_node = critical_path_head;
2580  num_edges = tnode[crit_node].num_edges;
2581 
2582  /* Keep adding the tnode in this tnode's fanout which has the least slack
2583  to our critical path linked list, then jump to that tnode and repeat, until
2584  we hit a tnode with no edges, which is the sink of the critical path. */
2585  while (num_edges != 0) {
2586  curr_crit_node = (t_linked_int *) my_malloc(sizeof(t_linked_int));
2587  prev_crit_node->next = curr_crit_node;
2588  tedge = tnode[crit_node].out_edges;
2589  min_slack = HUGE_POSITIVE_FLOAT;
2590 
2591  for (iedge = 0; iedge < num_edges; iedge++) {
2592  to_node = tedge[iedge].to_node;
2593  if (has_valid_T_arr(to_node) && has_valid_T_req(to_node)) { /* Valid arrival and required times */
2594  slack = tnode[to_node].T_req - tnode[to_node].T_arr;
2595  if (slack < min_slack) {
2596  crit_node = to_node;
2597  min_slack = slack;
2598  }
2599  }
2600  }
2601 
2602  curr_crit_node->data = crit_node;
2603  prev_crit_node = curr_crit_node;
2604  num_edges = tnode[crit_node].num_edges;
2605  }
2606 
2607  prev_crit_node->next = NULL;
2608  return (critical_path_head);
2609 }
struct s_ivec * tnodes_at_level
Definition: path_delay2.c:12
float T_req
Definition: vpr_types.h:344
int data
Definition: util.h:40
float ** least_slack
Definition: vpr_types.h:399
int * list
Definition: util.h:49
float T_arr
Definition: vpr_types.h:343
static t_timing_stats * f_timing_stats
Definition: path_delay.c:159
#define UNDEFINED
Definition: vpr_types.h:103
Definition: util.h:12
int num_edges
Definition: vpr_types.h:342
static float do_timing_analysis_for_constraint(int source_clock_domain, int sink_clock_domain, boolean is_prepacked, boolean is_final_analysis, long *max_critical_input_paths_ptr, long *max_critical_output_paths_ptr)
Definition: path_delay.c:1926
#define HUGE_POSITIVE_FLOAT
Definition: vpr_types.h:79
static void * my_malloc(int ibytes)
Definition: graphics.c:499
t_tnode * tnode
Definition: path_delay.c:143
int nelem
Definition: util.h:48
t_tedge * out_edges
Definition: vpr_types.h:336
static boolean has_valid_T_req(int inode)
Definition: path_delay.c:3048
int to_node
Definition: vpr_types.h:296
Definition: slre.c:50
struct s_linked_int * next
Definition: util.h:41
t_timing_constraints * g_sdc
Definition: read_sdc.c:65
static boolean has_valid_T_arr(int inode)
Definition: path_delay.c:3043

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void do_constant_net_delay_timing_analysis ( t_timing_inf  timing_inf,
float  constant_net_delay_value 
)

Definition at line 2636 of file path_delay.c.

2637  {
2638 
2639  /* Does a timing analysis (simple) where it assumes that each net has a *
2640  * constant delay value. Used only when operation == TIMING_ANALYSIS_ONLY. */
2641 
2642  /*struct s_linked_vptr *net_delay_chunk_list_head;*/
2643 
2644  t_chunk net_delay_ch = {NULL, 0, NULL};
2645  t_slack * slacks = NULL;
2646  float **net_delay = NULL;
2647 
2648  slacks = alloc_and_load_timing_graph(timing_inf);
2649  net_delay = alloc_net_delay(&net_delay_ch, timing_nets,
2650  num_timing_nets);
2651 
2652  load_constant_net_delay(net_delay, constant_net_delay_value, timing_nets,
2653  num_timing_nets);
2654  load_timing_graph_net_delays(net_delay);
2655 
2656  do_timing_analysis(slacks, FALSE, FALSE, TRUE);
2657 
2658  if (getEchoEnabled()) {
2660  print_critical_path("critical_path.echo");
2669  }
2670 
2672 
2673  free_timing_graph(slacks);
2674  free_net_delay(net_delay, &net_delay_ch);
2675 }
Definition: util.h:57
void print_timing_stats(void)
Definition: path_delay.c:3081
static int num_timing_nets
Definition: path_delay.c:157
static float ** net_delay
void print_critical_path(const char *fname)
Definition: path_delay.c:2458
void do_timing_analysis(t_slack *slacks, boolean is_prepacked, boolean do_lut_input_balancing, boolean is_final_analysis)
Definition: path_delay.c:1613
float ** slack
Definition: vpr_types.h:405
boolean getEchoEnabled(void)
Definition: ReadOptions.c:67
Definition: util.h:12
static t_chunk net_delay_ch
Definition: timing_place.c:15
boolean isEchoFileEnabled(enum e_echo_files echo_option)
Definition: ReadOptions.c:115
void free_net_delay(float **net_delay, t_chunk *chunk_list_ptr)
Definition: net_delay.c:127
float ** alloc_net_delay(t_chunk *chunk_list_ptr, struct s_net *nets, int n_nets)
Definition: net_delay.c:103
t_slack * alloc_and_load_timing_graph(t_timing_inf timing_inf)
Definition: path_delay.c:239
void print_criticality(t_slack *slacks, boolean criticality_is_normalized, const char *fname)
Definition: path_delay.c:559
static struct s_net * timing_nets
Definition: path_delay.c:155
void load_constant_net_delay(float **net_delay, float delay_value, struct s_net *nets, int n_nets)
Definition: net_delay.c:175
void print_slack(float **slack, boolean slack_is_normalized, const char *fname)
Definition: path_delay.c:441
void print_timing_graph(const char *fname)
Definition: path_delay.c:1388
char * getEchoFileName(enum e_echo_files echo_option)
Definition: ReadOptions.c:122
void free_timing_graph(t_slack *slacks)
Definition: path_delay.c:390
void print_net_delay(float **net_delay, const char *fname)
Definition: path_delay.c:670
void load_timing_graph_net_delays(float **net_delay)
Definition: path_delay.c:368
Definition: util.h:12

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void do_timing_analysis ( t_slack slacks,
boolean  is_prepacked,
boolean  do_lut_input_balancing,
boolean  is_final_analysis 
)

Definition at line 1613 of file path_delay.c.

1613  {
1614 
1615 /* Performs timing analysis on the circuit. Before this routine is called, t_slack * slacks
1616  must have been allocated, and the circuit must have been converted into a timing graph.
1617  The nodes of the timing graph represent pins and the edges between them represent delays
1618  and m dependencies from one pin to another. Most elements are modeled as a pair of nodes so
1619  that the delay through the element can be marked on the edge between them (e.g.
1620  TN_INPAD_SOURCE->TN_INPAD_OPIN, TN_OUTPAD_IPIN->TN_OUTPAD_SINK, TN_PRIMITIVE_OPIN->
1621  TN_PRIMITIVE_OPIN, etc.).
1622 
1623  The timing graph nodes are stored as an array, tnode [0..num_tnodes - 1]. Each tnode
1624  includes an array of all edges, tedge, which fan out from it. Each tedge includes the
1625  index of the node on its far end (in the tnode array), and the delay to that node.
1626 
1627  The timing graph has sources at each TN_FF_SOURCE (Q output), TN_INPAD_SOURCE (input I/O pad)
1628  and TN_CONSTANT_GEN_SOURCE (constant 1 or 0 generator) node and sinks at TN_FF_SINK (D input)
1629  and TN_OUTPAD_SINK (output I/O pad) nodes. Two traversals, one forward (sources to sinks)
1630  and one backward, are performed for each valid constraint (one which is not DO_NOT_ANALYSE)
1631  between a source and a sink clock domain in the matrix g_sdc->domain_constraint
1632  [0..g_sdc->num_constrained_clocks - 1][0..g_sdc->num_constrained_clocks - 1]. This matrix has been
1633  pruned so that all domain pairs with no paths between them have been set to DO_NOT_ANALYSE.
1634 
1635  During the traversal pair for each constraint, all nodes in the fanout of sources on the
1636  source clock domain are assigned a T_arr, the arrival time of the last input signal to the node.
1637  All nodes in the fanin of sinks on the sink clock domain are assigned a T_req, the required
1638  arrival time of the last input signal to the node if the critical path for this constraint is
1639  not to be lengthened. Nodes which receive both a valid T_arr and T_req are flagged with
1640  used_on_this_traversal, and nodes which are used on at least one traversal pair are flagged
1641  with has_valid_slack so that later functions know the slack is valid.
1642 
1643  After each traversal pair, a slack is calculated for each sink pin on each net (or equivalently,
1644  each connection or tedge fanning out from that net's driver tnode). Slack is calculated as:
1645  T_req (dest node) - T_arr (source node) - Tdel (edge)
1646  and represents the amount of delay which could be added to this connection before the critical
1647  path delay for this constraint would worsen. Edges on the critical path have a slack of 0.
1648  Slacks which are never used are set to HUGE_POSITIVE_FLOAT.
1649 
1650  The optimizers actually use a metric called timing_criticality. Timing criticality is defined
1651  as 1 - slack / criticality_denom, where the normalization factor criticality_denom is the max
1652  of all arrival times in the constraint and the constraint itself (T_req-relaxed slacks) or
1653  all arrival times and constraints in the design (shifted slacks). See below for a further
1654  discussion of these two regimes. Timing criticality is always between 0 (not critical) and 1
1655  (very critical). Unlike slack, which is set to HUGE_POSITIVE_FLOAT for unanalysed connections,
1656  timing criticality is 0 for these, meaning no special check has to be made for which connections
1657  have been analysed.
1658 
1659  If path counting is on (PATH_COUNTING is defined in vpr_types.h), the optimizers use a weighted
1660  sum of timing_criticality and path_criticality, the latter of which is an estimate of the
1661  importance of the number of paths using a particular connection. As a path's timing_criticality
1662  decreases, it will become exponentially less important to the path_criticality of any connection
1663  which this path uses. Path criticality also goes from 0 (not critical or unanalysed) to 1.
1664 
1665  Slack and criticalities are only calculated if both the driver of the net and the sink pin were
1666  used_on_this_traversal, and are only overwritten if lower than previously-obtained values.
1667  The optimizers actually use criticality rather than slack, but slack is useful for human
1668  designers and so we calculate it only if we need to print it.
1669 
1670  This routine outputs slack and criticality to t_slack * slacks. It also stores least slack and
1671  critical path delay per constraint [0..g_sdc->num_constrained_clocks - 1][0..g_sdc->num_constrained_clocks - 1]
1672  in the file-scope variable f_timing_stats.
1673 
1674  Is_prepacked flags whether to calculate normalized costs for the clusterer (normalized_slack,
1675  normalized_Tarr, normalized_total_critical_paths). Setting this to FALSE saves time in post-
1676  packed timing analyses.
1677 
1678  Do_lut_input_balancing flags whether to rebalance LUT inputs. LUT rebalancing takes advantage of
1679  the fact that different LUT inputs often have different delays. Since we can freely permute which
1680  LUT inputs are used by just changing the logic in the LUT, these LUT permutations can be performed
1681  late into the routing stage of the flow.
1682 
1683  Is_final_analysis flags whether this is the final, analysis pass. If it is, the analyser will
1684  compute actual slacks instead of relaxed ones. We "relax" slacks by setting the required time to
1685  the maximum arrival time for tight constraints so that no slacks are negative (which confuses
1686  the optimizers). This is called "T_req-relaxed" slack. However, human designers want to see
1687  actual slack values, so we report those in the final analysis. The alternative way of making
1688  slacks positive is shifting them upwards by the value of the largest negative slack, after
1689  all traversals are complete ("shifted slacks"), which can be enabled by changing SLACK_DEFINITION
1690  from 'R' to 'S' in path_delay.h.
1691 
1692  To do: flip-flop to flip-flop and flip-flop to clock domain constraints (set_false_path, set_max_delay,
1693  and especially set_multicycle_path). All the info for these constraints is contained in g_sdc->fc_constraints and
1694  g_sdc->ff_constraints, but graph traversals are not included yet. Probably, an entire traversal will be needed for
1695  each constraint. Clock domain to flip-flop constraints are coded but not tested, and are done within
1696  existing traversals. */
1697 
1698  int i, j, source_clock_domain, sink_clock_domain, inode, inet, ipin;
1699 
1700 #if defined PATH_COUNTING || SLACK_DEFINITION == 'S'
1701  int iedge, num_edges;
1702 #endif
1703 
1704 #ifdef PATH_COUNTING
1705  float max_path_criticality = HUGE_NEGATIVE_FLOAT /* used to normalize path_criticalities */;
1706 #endif
1707 
1708  boolean update_slack = (boolean) (is_final_analysis || getEchoEnabled());
1709  /* Only update slack values if we need to print it, i.e.
1710  for the final output file (is_final_analysis) or echo files. */
1711 
1712  float criticality_denom; /* (SLACK_DEFINITION == 'R' only) For a particular constraint, the maximum of
1713  the constraint and all arrival times for the constraint's traversal. Used to
1714  normalize the clusterer's normalized_slack and, more importantly, criticality. */
1715 
1716  long max_critical_output_paths, max_critical_input_paths;
1717  t_pb *pb;
1718 
1719 #if SLACK_DEFINITION == 'S'
1720  float smallest_slack_in_design = HUGE_POSITIVE_FLOAT;
1721  /* Shift all slacks upwards by this number if it is negative. */
1722 
1723  float criticality_denom_global = HUGE_NEGATIVE_FLOAT;
1724  /* Denominator of criticality for shifted - max of all arrival times and all constraints. */
1725 #endif
1726 
1727  /* Reset LUT input rebalancing. */
1728  for (inode = 0; inode < num_tnodes; inode++) {
1729  if (tnode[inode].type == TN_PRIMITIVE_OPIN && tnode[inode].pb_graph_pin != NULL) {
1731  if (pb != NULL && pb->lut_pin_remap != NULL) {
1732  /* this is a LUT primitive, do pin swapping */
1733  assert(pb->pb_graph_node->pb_type->num_output_pins == 1 && pb->pb_graph_node->pb_type->num_clock_pins == 0); /* ensure LUT properties are valid */
1734  assert(pb->pb_graph_node->num_input_ports == 1);
1735  /* If all input pins are known, perform LUT input delay rebalancing, do nothing otherwise */
1736  for (i = 0; i < pb->pb_graph_node->num_input_pins[0]; i++) {
1737  pb->lut_pin_remap[i] = OPEN;
1738  }
1739  }
1740  }
1741  }
1742 
1743  /* Reset all values which need to be reset once per
1744  timing analysis, rather than once per traversal pair. */
1745 
1746  /* Reset slack and criticality */
1747  for (inet = 0; inet < num_timing_nets; inet++) {
1748  for (ipin = 1; ipin <= timing_nets[inet].num_sinks; ipin++) {
1749  slacks->slack[inet][ipin] = HUGE_POSITIVE_FLOAT;
1750  slacks->timing_criticality[inet][ipin] = 0.;
1751 #ifdef PATH_COUNTING
1752  slacks->path_criticality[inet][ipin] = 0.;
1753 #endif
1754  }
1755  }
1756 
1757  /* Reset f_timing_stats. */
1758  for (i = 0; i < g_sdc->num_constrained_clocks; i++) {
1759  for (j = 0; j < g_sdc->num_constrained_clocks; j++) {
1762  }
1763  }
1764 
1765 #ifndef PATH_COUNTING
1766  /* Reset normalized values for clusterer. */
1767  if (is_prepacked) {
1768  for (inode = 0; inode < num_tnodes; inode++) {
1772  }
1773  }
1774 #endif
1775 
1776  if (do_lut_input_balancing) {
1778  }
1779 
1780  /* For each valid constraint (pair of source and sink clock domains), we do one
1781  forward and one backward topological traversal to find arrival and required times,
1782  in do_timing_analysis_for_constraint. If path counting is on, we then do another,
1783  simpler traversal to find forward and backward weights, relying on the largest
1784  required time we found from the first traversal. After each constraint's traversals,
1785  we update the slacks, timing criticalities and (if necessary) path criticalities or
1786  normalized costs used by the clusterer. */
1787 
1788  for (source_clock_domain = 0; source_clock_domain < g_sdc->num_constrained_clocks; source_clock_domain++) {
1789  for (sink_clock_domain = 0; sink_clock_domain < g_sdc->num_constrained_clocks; sink_clock_domain++) {
1790  if (g_sdc->domain_constraint[source_clock_domain][sink_clock_domain] > NEGATIVE_EPSILON) { /* i.e. != DO_NOT_ANALYSE */
1791 
1792  /* Perform the forward and backward traversal for this constraint. */
1793  criticality_denom = do_timing_analysis_for_constraint(source_clock_domain, sink_clock_domain,
1794  is_prepacked, is_final_analysis, &max_critical_input_paths, &max_critical_output_paths);
1795 #ifdef PATH_COUNTING
1796  /* Weight the importance of each net, used in slack calculation. */
1797  do_path_counting(criticality_denom);
1798 #endif
1799 
1800  /* Update the slack and criticality for each edge of each net which was
1801  analysed on the most recent traversal and has a lower (slack) or
1802  higher (criticality) value than before. */
1803  update_slacks(slacks, source_clock_domain, sink_clock_domain, criticality_denom, update_slack);
1804 
1805 #ifndef PATH_COUNTING
1806  /* Update the normalized costs used by the clusterer. */
1807  if (is_prepacked) {
1808  update_normalized_costs(criticality_denom, max_critical_input_paths, max_critical_output_paths);
1809  }
1810 #endif
1811 
1812 #if SLACK_DEFINITION == 'S'
1813  /* Set criticality_denom_global to the max of criticality_denom over all traversals. */
1814  criticality_denom_global = std::max(criticality_denom_global, criticality_denom);
1815 #endif
1816  }
1817  }
1818  }
1819 
1820 #ifdef PATH_COUNTING
1821  /* Normalize path criticalities by the largest value in the
1822  circuit. Otherwise, path criticalities would be unbounded. */
1823 
1824  for (inet = 0; inet < num_timing_nets; inet++) {
1825  num_edges = timing_nets[inet].num_sinks;
1826  for (iedge = 0; iedge < num_edges; iedge++) {
1827  max_path_criticality = std::max(max_path_criticality, slacks->path_criticality[inet][iedge + 1]);
1828  }
1829  }
1830 
1831  for (inet = 0; inet < num_timing_nets; inet++) {
1832  num_edges = timing_nets[inet].num_sinks;
1833  for (iedge = 0; iedge < num_edges; iedge++) {
1834  slacks->path_criticality[inet][iedge + 1] /= max_path_criticality;
1835  }
1836  }
1837 
1838 #endif
1839 
1840 #if SLACK_DEFINITION == 'S'
1841  if (!is_final_analysis) {
1842 
1843  /* Find the smallest slack in the design. */
1844  for (i = 0; i < g_sdc->num_constrained_clocks; i++) {
1845  for (j = 0; j < g_sdc->num_constrained_clocks; j++) {
1846  smallest_slack_in_design = std::min(smallest_slack_in_design, f_timing_stats->least_slack[i][j]);
1847  }
1848  }
1849 
1850  /* Increase all slacks by the value of the smallest slack in the design, if it's negative. */
1851  if (smallest_slack_in_design < 0) {
1852  for (inet = 0; inet < num_timing_nets; inet++) {
1853  num_edges = timing_nets[inet].num_sinks;
1854  for (iedge = 0; iedge < num_edges; iedge++) {
1855  slacks->slack[inet][iedge + 1] -= smallest_slack_in_design;
1856  /* Remember, smallest_slack_in_design is negative, so we're INCREASING all the slacks. */
1857  /* Note that if slack was equal to HUGE_POSITIVE_FLOAT, it will still be equal to more than this,
1858  so it will still be ignored when we calculate criticalities. */
1859  }
1860  }
1861  }
1862  }
1863 
1864  /* We can now calculate criticalities, only after we normalize slacks. */
1865  for (inet = 0; inet < num_timing_nets; inet++) {
1866  num_edges = timing_nets[inet].num_sinks;
1867  for (iedge = 0; iedge < num_edges; iedge++) {
1868  if (slacks->slack[inet][iedge + 1] < HUGE_POSITIVE_FLOAT - 1) { /* if the slack is valid */
1869  slacks->timing_criticality[inet][iedge + 1] = 1 - slacks->slack[inet][iedge + 1]/criticality_denom_global;
1870  }
1871  /* otherwise, criticality remains 0, as it was initialized */
1872  }
1873  }
1874 #endif
1875 }
static int num_timing_nets
Definition: path_delay.c:157
int num_tnodes
Definition: path_delay.c:144
boolean
Definition: util.h:11
static void do_lut_rebalancing()
Definition: path_delay.c:1877
float ** least_slack
Definition: vpr_types.h:399
static t_timing_stats * f_timing_stats
Definition: path_delay.c:159
int * lut_pin_remap
Definition: vpr_types.h:197
float ** domain_constraint
Definition: vpr_types.h:431
struct s_pb ** rr_node_to_pb_mapping
Definition: vpr_types.h:189
float ** slack
Definition: vpr_types.h:405
boolean getEchoEnabled(void)
Definition: ReadOptions.c:67
t_prepacked_tnode_data * prepacked_data
Definition: vpr_types.h:361
#define min(a, b)
Definition: graphics.c:174
float ** cpd
Definition: vpr_types.h:398
static float do_timing_analysis_for_constraint(int source_clock_domain, int sink_clock_domain, boolean is_prepacked, boolean is_final_analysis, long *max_critical_input_paths_ptr, long *max_critical_output_paths_ptr)
Definition: path_delay.c:1926
int block
Definition: vpr_types.h:346
#define HUGE_POSITIVE_FLOAT
Definition: vpr_types.h:79
float normalized_total_critical_paths
Definition: vpr_types.h:328
t_tnode * tnode
Definition: path_delay.c:143
#define max(a, b)
Definition: graphics.c:171
struct s_block * block
Definition: globals.c:31
static void update_slacks(t_slack *slacks, int source_clock_domain, int sink_clock_domain, float criticality_denom, boolean update_slack)
Definition: path_delay.c:2344
t_pb_graph_pin * pb_graph_pin
Definition: vpr_types.h:358
struct s_pb_type * pb_type
static struct s_net * timing_nets
Definition: path_delay.c:155
static void update_normalized_costs(float T_arr_max_this_domain, long max_critical_input_paths, long max_critical_output_paths)
Definition: path_delay.c:2677
float ** timing_criticality
Definition: vpr_types.h:406
Definition: slre.c:50
t_pb * pb
Definition: vpr_types.h:567
t_timing_constraints * g_sdc
Definition: read_sdc.c:65
int num_output_pins
#define NEGATIVE_EPSILON
Definition: vpr_types.h:84
t_pb_graph_node * pb_graph_node
Definition: vpr_types.h:180
#define HUGE_NEGATIVE_FLOAT
Definition: vpr_types.h:80
int num_sinks
Definition: vpr_types.h:506
int num_clock_pins

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void free_timing_graph ( t_slack slack)

Definition at line 390 of file path_delay.c.

390  {
391 
392  int inode;
393 
394  if (tedge_ch.chunk_ptr_head == NULL) {
395  vpr_printf(TIO_MESSAGE_ERROR, "in free_timing_graph: No timing graph to free.\n");
396  exit(1);
397  }
398 
400 
401  if (tnode[0].prepacked_data) {
402  /* If we allocated prepacked_data for the first node,
403  it must be allocated for all other nodes too. */
404  for (inode = 0; inode < num_tnodes; inode++) {
405  free(tnode[inode].prepacked_data);
406  }
407  }
408  free(tnode);
409  free(f_net_to_driver_tnode);
411 
412  free(slacks->slack);
413  free(slacks->timing_criticality);
414 #ifdef PATH_COUNTING
415  free(slacks->path_criticality);
416 #endif
417  free(slacks);
418 
419  tnode = NULL;
420  num_tnodes = 0;
421  f_net_to_driver_tnode = NULL;
422  tnodes_at_level = NULL;
423  num_tnode_levels = 0;
424  slacks = NULL;
425 }
struct s_ivec * tnodes_at_level
Definition: path_delay2.c:12
static t_chunk tedge_ch
Definition: path_delay.c:153
int num_tnodes
Definition: path_delay.c:144
struct s_linked_vptr * chunk_ptr_head
Definition: util.h:58
int num_tnode_levels
Definition: path_delay2.c:10
t_tnode * tnode
Definition: path_delay.c:143
void free_ivec_vector(struct s_ivec *ivec_vector, int nrmin, int nrmax)
Definition: util.c:498
static int * f_net_to_driver_tnode
Definition: path_delay.c:161
void free_chunk_memory(t_chunk *chunk_info)
Definition: util.c:270
messagelogger vpr_printf
Definition: util.c:17

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void free_timing_stats ( void  )

Definition at line 427 of file path_delay.c.

427  {
428  int i;
429  if(f_timing_stats != NULL) {
430  for (i = 0; i < g_sdc->num_constrained_clocks; i++) {
431  free(f_timing_stats->cpd[i]);
432  free(f_timing_stats->least_slack[i]);
433  }
434  free(f_timing_stats->cpd);
436  free(f_timing_stats);
437  }
438  f_timing_stats = NULL;
439 }
float ** least_slack
Definition: vpr_types.h:399
static t_timing_stats * f_timing_stats
Definition: path_delay.c:159
float ** cpd
Definition: vpr_types.h:398
t_timing_constraints * g_sdc
Definition: read_sdc.c:65

+ Here is the caller graph for this function:

float get_critical_path_delay ( void  )

Definition at line 3060 of file path_delay.c.

3060  {
3061  /* Finds the critical path delay, which is the minimum clock period required to meet the constraint
3062  corresponding to the pair of source and sink clock domains with the least slack in the design. */
3063 
3064  int source_clock_domain, sink_clock_domain;
3065  float least_slack_in_design = HUGE_POSITIVE_FLOAT, critical_path_delay = UNDEFINED;
3066 
3067  if (!g_sdc) return UNDEFINED; /* If timing analysis is off, for instance. */
3068 
3069  for (source_clock_domain = 0; source_clock_domain < g_sdc->num_constrained_clocks; source_clock_domain++) {
3070  for (sink_clock_domain = 0; sink_clock_domain < g_sdc->num_constrained_clocks; sink_clock_domain++) {
3071  if (least_slack_in_design > f_timing_stats->least_slack[source_clock_domain][sink_clock_domain]) {
3072  least_slack_in_design = f_timing_stats->least_slack[source_clock_domain][sink_clock_domain];
3073  critical_path_delay = f_timing_stats->cpd[source_clock_domain][sink_clock_domain];
3074  }
3075  }
3076  }
3077 
3078  return critical_path_delay * 1e9; /* Convert to nanoseconds */
3079 }
float ** least_slack
Definition: vpr_types.h:399
static t_timing_stats * f_timing_stats
Definition: path_delay.c:159
#define UNDEFINED
Definition: vpr_types.h:103
float ** cpd
Definition: vpr_types.h:398
#define HUGE_POSITIVE_FLOAT
Definition: vpr_types.h:79
t_timing_constraints * g_sdc
Definition: read_sdc.c:65

+ Here is the caller graph for this function:

void get_tnode_block_and_output_net ( int  inode,
int *  iblk_ptr,
int *  inet_ptr 
)

Definition at line 2611 of file path_delay.c.

2611  {
2612 
2613  /* Returns the index of the block that this tnode is part of. If the tnode *
2614  * is a TN_CB_OPIN or TN_INPAD_OPIN (i.e. if it drives a net), the net index is *
2615  * returned via inet_ptr. Otherwise inet_ptr points at OPEN. */
2616 
2617  int inet, ipin, iblk;
2618  e_tnode_type tnode_type;
2619 
2620  iblk = tnode[inode].block;
2621  tnode_type = tnode[inode].type;
2622 
2623  if (tnode_type == TN_CB_OPIN) {
2624  ipin = tnode[inode].pb_graph_pin->pin_count_in_cluster;
2625  inet = block[iblk].pb->rr_graph[ipin].net_num;
2626  assert(inet != OPEN);
2627  inet = vpack_to_clb_net_mapping[inet];
2628  } else {
2629  inet = OPEN;
2630  }
2631 
2632  *iblk_ptr = iblk;
2633  *inet_ptr = inet;
2634 }
int net_num
Definition: vpr_types.h:917
struct s_rr_node * rr_graph
Definition: vpr_types.h:188
e_tnode_type
Definition: vpr_types.h:300
int block
Definition: vpr_types.h:346
t_tnode * tnode
Definition: path_delay.c:143
int * vpack_to_clb_net_mapping
Definition: globals.c:34
struct s_block * block
Definition: globals.c:31
t_pb_graph_pin * pb_graph_pin
Definition: vpr_types.h:358
Definition: slre.c:50
t_pb * pb
Definition: vpr_types.h:567
e_tnode_type type
Definition: vpr_types.h:335

+ Here is the caller graph for this function:

boolean has_valid_normalized_T_arr ( int  inode)

Definition at line 3054 of file path_delay.c.

3054  {
3055  /* Has this tnode's normalized_T_arr been changed from its original value of HUGE_NEGATIVE_FLOAT? */
3056  return (boolean) (tnode[inode].prepacked_data->normalized_T_arr > HUGE_NEGATIVE_FLOAT + 1);
3057 }
t_prepacked_tnode_data * prepacked_data
Definition: vpr_types.h:361
t_tnode * tnode
Definition: path_delay.c:143
#define HUGE_NEGATIVE_FLOAT
Definition: vpr_types.h:80

+ Here is the caller graph for this function:

void load_timing_graph_net_delays ( float **  net_delay)

Definition at line 368 of file path_delay.c.

368  {
369 
370  /* Sets the delays of the inter-CLB nets to the values specified by *
371  * net_delay[0..num_nets-1][1..num_pins-1]. These net delays should have *
372  * been allocated and loaded with the net_delay routines. This routine *
373  * marks the corresponding edges in the timing graph with the proper delay. */
374 
375  int inet, ipin, inode;
376  t_tedge *tedge;
377 
378  for (inet = 0; inet < num_timing_nets; inet++) {
379  inode = f_net_to_driver_tnode[inet];
380  tedge = tnode[inode].out_edges;
381 
382  /* Note that the edges of a tnode corresponding to a CLB or INPAD opin must *
383  * be in the same order as the pins of the net driven by the tnode. */
384 
385  for (ipin = 1; ipin < (timing_nets[inet].num_sinks + 1); ipin++)
386  tedge[ipin - 1].Tdel = net_delay[inet][ipin];
387  }
388 }
static int num_timing_nets
Definition: path_delay.c:157
static float ** net_delay
t_tnode * tnode
Definition: path_delay.c:143
static int * f_net_to_driver_tnode
Definition: path_delay.c:161
t_tedge * out_edges
Definition: vpr_types.h:336
static struct s_net * timing_nets
Definition: path_delay.c:155
int num_sinks
Definition: vpr_types.h:506

+ Here is the caller graph for this function:

void print_clustering_timing_info ( const char *  fname)

Definition at line 696 of file path_delay.c.

696  {
697  /* Print information from tnodes which is used by the clusterer. */
698  int inode;
699  FILE *fp;
700 
701  fp = my_fopen(fname, "w", 0);
702 
703  fprintf(fp, "inode ");
704  if (g_sdc->num_constrained_clocks <= 1) {
705  /* These values are from the last constraint analysed,
706  so they're not meaningful unless there was only one constraint. */
707  fprintf(fp, "Critical input paths Critical output paths ");
708  }
709  fprintf(fp, "Normalized slack Normalized Tarr Normalized total crit paths\n");
710  for (inode = 0; inode < num_tnodes; inode++) {
711  fprintf(fp, "%d\t", inode);
712  /* Only print normalized values for tnodes which have valid normalized values. (If normalized_T_arr is valid, the others will be too.) */
713  if (has_valid_normalized_T_arr(inode)) {
714  if (g_sdc->num_constrained_clocks <= 1) {
715  fprintf(fp, "%ld\t\t\t%ld\t\t\t", tnode[inode].prepacked_data->num_critical_input_paths, tnode[inode].prepacked_data->num_critical_output_paths);
716  }
717  fprintf(fp, "%f\t%f\t%f\n", tnode[inode].prepacked_data->normalized_slack, tnode[inode].prepacked_data->normalized_T_arr, tnode[inode].prepacked_data->normalized_total_critical_paths);
718  } else {
719  if (g_sdc->num_constrained_clocks <= 1) {
720  fprintf(fp, "--\t\t\t--\t\t\t");
721  }
722  fprintf(fp, "--\t\t--\t\t--\n");
723  }
724  }
725 
726  fclose(fp);
727 }
FILE * my_fopen(const char *fname, const char *flag, int prompt)
Definition: util.c:54
int num_tnodes
Definition: path_delay.c:144
t_prepacked_tnode_data * prepacked_data
Definition: vpr_types.h:361
float normalized_total_critical_paths
Definition: vpr_types.h:328
t_tnode * tnode
Definition: path_delay.c:143
boolean has_valid_normalized_T_arr(int inode)
Definition: path_delay.c:3054
t_timing_constraints * g_sdc
Definition: read_sdc.c:65

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void print_critical_path ( const char *  fname)

Definition at line 2458 of file path_delay.c.

2458  {
2459 
2460  /* Prints the critical path to a file. */
2461 
2462  t_linked_int *critical_path_head, *critical_path_node;
2463  FILE *fp;
2464  int non_global_nets_on_crit_path, global_nets_on_crit_path;
2465  int tnodes_on_crit_path, inode, iblk, inet;
2466  e_tnode_type type;
2467  float total_net_delay, total_logic_delay, Tdel;
2468 
2469  critical_path_head = allocate_and_load_critical_path();
2470  critical_path_node = critical_path_head;
2471 
2472  fp = my_fopen(fname, "w", 0);
2473 
2474  non_global_nets_on_crit_path = 0;
2475  global_nets_on_crit_path = 0;
2476  tnodes_on_crit_path = 0;
2477  total_net_delay = 0.;
2478  total_logic_delay = 0.;
2479 
2480  while (critical_path_node != NULL) {
2481  Tdel = print_critical_path_node(fp, critical_path_node);
2482  inode = critical_path_node->data;
2483  type = tnode[inode].type;
2484  tnodes_on_crit_path++;
2485 
2486  if (type == TN_CB_OPIN) {
2487  get_tnode_block_and_output_net(inode, &iblk, &inet);
2488 
2489  if (!timing_nets[inet].is_global)
2490  non_global_nets_on_crit_path++;
2491  else
2492  global_nets_on_crit_path++;
2493 
2494  total_net_delay += Tdel;
2495  } else {
2496  total_logic_delay += Tdel;
2497  }
2498 
2499  critical_path_node = critical_path_node->next;
2500  }
2501 
2502  fprintf(fp, "\nTnodes on critical path: %d Non-global nets on critical path: %d."
2503  "\n", tnodes_on_crit_path, non_global_nets_on_crit_path);
2504  fprintf(fp, "Global nets on critical path: %d.\n", global_nets_on_crit_path);
2505  fprintf(fp, "Total logic delay: %g (s) Total net delay: %g (s)\n",
2506  total_logic_delay, total_net_delay);
2507 
2508  vpr_printf(TIO_MESSAGE_INFO, "Nets on critical path: %d normal, %d global.\n",
2509  non_global_nets_on_crit_path, global_nets_on_crit_path);
2510 
2511  vpr_printf(TIO_MESSAGE_INFO, "Total logic delay: %g (s), total net delay: %g (s)\n",
2512  total_logic_delay, total_net_delay);
2513 
2514  /* Make sure total_logic_delay and total_net_delay add
2515  up to critical path delay,within 5 decimal places. */
2516  assert(total_logic_delay + total_net_delay - get_critical_path_delay()/1e9 < 1e-5);
2517 
2518  fclose(fp);
2519  free_int_list(&critical_path_head);
2520 }
FILE * my_fopen(const char *fname, const char *flag, int prompt)
Definition: util.c:54
int data
Definition: util.h:40
float get_critical_path_delay(void)
Definition: path_delay.c:3060
void get_tnode_block_and_output_net(int inode, int *iblk_ptr, int *inet_ptr)
Definition: path_delay.c:2611
e_tnode_type
Definition: vpr_types.h:300
t_linked_int * allocate_and_load_critical_path(void)
Definition: path_delay.c:2522
boolean * is_global
t_tnode * tnode
Definition: path_delay.c:143
void free_int_list(t_linked_int **int_list_head_ptr)
Definition: util.c:341
static struct s_net * timing_nets
Definition: path_delay.c:155
struct s_linked_int * next
Definition: util.h:41
float print_critical_path_node(FILE *fp, t_linked_int *critical_path_node)
Definition: path_delay2.c:199
e_tnode_type type
Definition: vpr_types.h:335
messagelogger vpr_printf
Definition: util.c:17

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void print_criticality ( t_slack slacks,
boolean  criticality_is_normalized,
const char *  fname 
)

Definition at line 559 of file path_delay.c.

559  {
560 
561  /* Prints timing criticalities (and path criticalities if enabled) into a file. */
562 
563  int inet, iedge, driver_tnode, num_edges;
564  t_tedge * tedge;
565  FILE *fp;
566 
567  fp = my_fopen(fname, "w", 0);
568 
569  if (criticality_is_normalized) {
570  fprintf(fp, "Timing criticalities have been normalized to be non-negative by "
571  "relaxing the required times to the maximum arrival time.\n\n");
572  }
573 
574  print_global_criticality_stats(fp, slacks->timing_criticality, "timing criticality", "Timing criticalities");
575 #ifdef PATH_COUNTING
576  print_global_criticality_stats(fp, slacks->path_criticality, "path criticality", "Path criticalities");
577 #endif
578 
579  /* Finally, print all the criticalities, organized by net. */
580  fprintf(fp, "\n\nNet #\tDriver_tnode\t to_node\tTiming criticality"
581 #ifdef PATH_COUNTING
582  "\tPath criticality"
583 #endif
584  "\n");
585 
586  for (inet = 0; inet < num_timing_nets; inet++) {
587  driver_tnode = f_net_to_driver_tnode[inet];
588  num_edges = tnode[driver_tnode].num_edges;
589  tedge = tnode[driver_tnode].out_edges;
590 
591  fprintf(fp, "\n%5d\t%5d\t\t%5d\t\t%.6f", inet, driver_tnode, tedge[0].to_node, slacks->timing_criticality[inet][1]);
592 #ifdef PATH_COUNTING
593  fprintf(fp, "\t\t%g", slacks->path_criticality[inet][1]);
594 #endif
595  for (iedge = 1; iedge < num_edges; iedge++) { /* newline and indent subsequent edges after the first */
596  fprintf(fp, "\n\t\t\t%5d\t\t%.6f", tedge[iedge].to_node, slacks->timing_criticality[inet][iedge+1]);
597 #ifdef PATH_COUNTING
598  fprintf(fp, "\t\t%g", slacks->path_criticality[inet][iedge+1]);
599 #endif
600  }
601  }
602 
603  fclose(fp);
604 }
FILE * my_fopen(const char *fname, const char *flag, int prompt)
Definition: util.c:54
static int num_timing_nets
Definition: path_delay.c:157
int num_edges
Definition: vpr_types.h:342
t_tnode * tnode
Definition: path_delay.c:143
static int * f_net_to_driver_tnode
Definition: path_delay.c:161
t_tedge * out_edges
Definition: vpr_types.h:336
static void print_global_criticality_stats(FILE *fp, float **criticality, const char *singular_name, const char *capitalized_plural_name)
Definition: path_delay.c:606
float ** timing_criticality
Definition: vpr_types.h:406

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void print_lut_remapping ( const char *  fname)

Definition at line 2430 of file path_delay.c.

2430  {
2431  FILE *fp;
2432  int inode, i;
2433  t_pb *pb;
2434 
2435 
2436  fp = my_fopen(fname, "w", 0);
2437  fprintf(fp, "# LUT_Name\tinput_pin_mapping\n");
2438 
2439  for (inode = 0; inode < num_tnodes; inode++) {
2440  /* Print LUT input rebalancing */
2441  if (tnode[inode].type == TN_PRIMITIVE_OPIN && tnode[inode].pb_graph_pin != NULL) {
2443  if (pb != NULL && pb->lut_pin_remap != NULL) {
2444  assert(pb->pb_graph_node->pb_type->num_output_pins == 1 && pb->pb_graph_node->pb_type->num_clock_pins == 0); /* ensure LUT properties are valid */
2445  assert(pb->pb_graph_node->num_input_ports == 1);
2446  fprintf(fp, "%s", pb->name);
2447  for (i = 0; i < pb->pb_graph_node->num_input_pins[0]; i++) {
2448  fprintf(fp, "\t%d", pb->lut_pin_remap[i]);
2449  }
2450  fprintf(fp, "\n");
2451  }
2452  }
2453  }
2454 
2455  fclose(fp);
2456 }
char * name
Definition: vpr_types.h:179
FILE * my_fopen(const char *fname, const char *flag, int prompt)
Definition: util.c:54
int num_tnodes
Definition: path_delay.c:144
int * lut_pin_remap
Definition: vpr_types.h:197
struct s_pb ** rr_node_to_pb_mapping
Definition: vpr_types.h:189
int block
Definition: vpr_types.h:346
t_tnode * tnode
Definition: path_delay.c:143
struct s_block * block
Definition: globals.c:31
t_pb_graph_pin * pb_graph_pin
Definition: vpr_types.h:358
struct s_pb_type * pb_type
t_pb * pb
Definition: vpr_types.h:567
int num_output_pins
t_pb_graph_node * pb_graph_node
Definition: vpr_types.h:180
int num_clock_pins

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void print_net_delay ( float **  net_delay,
const char *  fname 
)

Definition at line 670 of file path_delay.c.

670  {
671 
672  /* Prints the net delays into a file. */
673 
674  int inet, iedge, driver_tnode, num_edges;
675  t_tedge * tedge;
676  FILE *fp;
677 
678  fp = my_fopen(fname, "w", 0);
679 
680  fprintf(fp, "Net #\tDriver_tnode\tto_node\tDelay\n\n");
681 
682  for (inet = 0; inet < num_timing_nets; inet++) {
683  driver_tnode = f_net_to_driver_tnode[inet];
684  num_edges = tnode[driver_tnode].num_edges;
685  tedge = tnode[driver_tnode].out_edges;
686  fprintf(fp, "%5d\t%5d\t\t%5d\t%g\n", inet, driver_tnode, tedge[0].to_node, net_delay[inet][1]);
687  for (iedge = 1; iedge < num_edges; iedge++) { /* newline and indent subsequent edges after the first */
688  fprintf(fp, "\t\t\t%5d\t%g\n", tedge[iedge].to_node, net_delay[inet][iedge+1]);
689  }
690  }
691 
692  fclose(fp);
693 }
FILE * my_fopen(const char *fname, const char *flag, int prompt)
Definition: util.c:54
static int num_timing_nets
Definition: path_delay.c:157
static float ** net_delay
int num_edges
Definition: vpr_types.h:342
t_tnode * tnode
Definition: path_delay.c:143
static int * f_net_to_driver_tnode
Definition: path_delay.c:161
t_tedge * out_edges
Definition: vpr_types.h:336

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void print_slack ( float **  slack,
boolean  slack_is_normalized,
const char *  fname 
)

Definition at line 441 of file path_delay.c.

441  {
442 
443  /* Prints slacks into a file. */
444 
445  int inet, iedge, ibucket, driver_tnode, num_edges, num_unused_slacks = 0;
446  t_tedge * tedge;
447  FILE *fp;
448  float max_slack = HUGE_NEGATIVE_FLOAT, min_slack = HUGE_POSITIVE_FLOAT,
449  total_slack = 0, total_negative_slack = 0, bucket_size, slk;
450  int slacks_in_bucket[NUM_BUCKETS];
451 
452  fp = my_fopen(fname, "w", 0);
453 
454  if (slack_is_normalized) {
455  fprintf(fp, "The following slacks have been normalized to be non-negative by "
456  "relaxing the required times to the maximum arrival time.\n\n");
457  }
458 
459  /* Go through slack once to get the largest and smallest slack, both for reporting and
460  so that we can delimit the buckets. Also calculate the total negative slack in the design. */
461  for (inet = 0; inet < num_timing_nets; inet++) {
462  num_edges = timing_nets[inet].num_sinks;
463  for (iedge = 0; iedge < num_edges; iedge++) {
464  slk = slack[inet][iedge + 1];
465  if (slk < HUGE_POSITIVE_FLOAT - 1) { /* if slack was analysed */
466  max_slack = std::max(max_slack, slk);
467  min_slack = std::min(min_slack, slk);
468  total_slack += slk;
469  if (slk < NEGATIVE_EPSILON) {
470  total_negative_slack -= slk; /* By convention, we'll have total_negative_slack be a positive number. */
471  }
472  } else { /* slack was never analysed */
473  num_unused_slacks++;
474  }
475  }
476  }
477 
478  if (max_slack > HUGE_NEGATIVE_FLOAT + 1) {
479  fprintf(fp, "Largest slack in design: %g\n", max_slack);
480  } else {
481  fprintf(fp, "Largest slack in design: --\n");
482  }
483 
484  if (min_slack < HUGE_POSITIVE_FLOAT - 1) {
485  fprintf(fp, "Smallest slack in design: %g\n", min_slack);
486  } else {
487  fprintf(fp, "Smallest slack in design: --\n");
488  }
489 
490  fprintf(fp, "Total slack in design: %g\n", total_slack);
491  fprintf(fp, "Total negative slack: %g\n", total_negative_slack);
492 
493  if (max_slack - min_slack > EPSILON) { /* Only sort the slacks into buckets if not all slacks are the same (if they are identical, no need to sort). */
494  /* Initialize slacks_in_bucket, an array counting how many slacks are within certain linearly-spaced ranges (buckets). */
495  for (ibucket = 0; ibucket < NUM_BUCKETS; ibucket++) {
496  slacks_in_bucket[ibucket] = 0;
497  }
498 
499  /* The size of each bucket is the range of slacks, divided by the number of buckets. */
500  bucket_size = (max_slack - min_slack)/NUM_BUCKETS;
501 
502  /* Now, pass through again, incrementing the number of slacks in the nth bucket
503  for each slack between (min_slack + n*bucket_size) and (min_slack + (n+1)*bucket_size). */
504 
505  for (inet = 0; inet < num_timing_nets; inet++) {
506  num_edges = timing_nets[inet].num_sinks;
507  for (iedge = 0; iedge < num_edges; iedge++) {
508  slk = slack[inet][iedge + 1];
509  if (slk < HUGE_POSITIVE_FLOAT - 1) {
510  /* We have to watch out for the special case where slack = max_slack, in which case ibucket = NUM_BUCKETS and we go out of bounds of the array. */
511  ibucket = std::min(NUM_BUCKETS - 1, (int) ((slk - min_slack)/bucket_size));
512  assert(ibucket >= 0 && ibucket < NUM_BUCKETS);
513  slacks_in_bucket[ibucket]++;
514  }
515  }
516  }
517 
518  /* Now print how many slacks are in each bucket. */
519  fprintf(fp, "\n\nRange\t\t");
520  for (ibucket = 0; ibucket < NUM_BUCKETS; ibucket++) {
521  fprintf(fp, "%.1e to ", min_slack);
522  min_slack += bucket_size;
523  fprintf(fp, "%.1e\t", min_slack);
524  }
525  fprintf(fp, "Not analysed");
526  fprintf(fp, "\nSlacks in range\t\t");
527  for (ibucket = 0; ibucket < NUM_BUCKETS; ibucket++) {
528  fprintf(fp, "%d\t\t\t", slacks_in_bucket[ibucket]);
529  }
530  fprintf(fp, "%d", num_unused_slacks);
531  }
532 
533  /* Finally, print all the slacks, organized by net. */
534  fprintf(fp, "\n\nNet #\tDriver_tnode\tto_node\tSlack\n\n");
535 
536  for (inet = 0; inet < num_timing_nets; inet++) {
537  driver_tnode = f_net_to_driver_tnode[inet];
538  num_edges = tnode[driver_tnode].num_edges;
539  tedge = tnode[driver_tnode].out_edges;
540  slk = slack[inet][1];
541  if (slk < HUGE_POSITIVE_FLOAT - 1) {
542  fprintf(fp, "%5d\t%5d\t\t%5d\t%g\n", inet, driver_tnode, tedge[0].to_node, slk);
543  } else { /* Slack is meaningless, so replace with --. */
544  fprintf(fp, "%5d\t%5d\t\t%5d\t--\n", inet, driver_tnode, tedge[0].to_node);
545  }
546  for (iedge = 1; iedge < num_edges; iedge++) { /* newline and indent subsequent edges after the first */
547  slk = slack[inet][iedge+1];
548  if (slk < HUGE_POSITIVE_FLOAT - 1) {
549  fprintf(fp, "\t\t\t%5d\t%g\n", tedge[iedge].to_node, slk);
550  } else { /* Slack is meaningless, so replace with --. */
551  fprintf(fp, "\t\t\t%5d\t--\n", tedge[iedge].to_node);
552  }
553  }
554  }
555 
556  fclose(fp);
557 }
FILE * my_fopen(const char *fname, const char *flag, int prompt)
Definition: util.c:54
#define NUM_BUCKETS
Definition: path_delay.c:148
static int num_timing_nets
Definition: path_delay.c:157
int num_edges
Definition: vpr_types.h:342
#define min(a, b)
Definition: graphics.c:174
#define HUGE_POSITIVE_FLOAT
Definition: vpr_types.h:79
t_tnode * tnode
Definition: path_delay.c:143
#define max(a, b)
Definition: graphics.c:171
static int * f_net_to_driver_tnode
Definition: path_delay.c:161
#define EPSILON
Definition: vpr_types.h:83
t_tedge * out_edges
Definition: vpr_types.h:336
static struct s_net * timing_nets
Definition: path_delay.c:155
#define NEGATIVE_EPSILON
Definition: vpr_types.h:84
#define HUGE_NEGATIVE_FLOAT
Definition: vpr_types.h:80
int num_sinks
Definition: vpr_types.h:506

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void print_timing_graph ( const char *  fname)

Definition at line 1388 of file path_delay.c.

1388  {
1389 
1390  /* Prints the timing graph into a file. */
1391 
1392  FILE *fp;
1393  int inode, iedge, ilevel, i;
1394  t_tedge *tedge;
1395  e_tnode_type itype;
1396  const char *tnode_type_names[] = { "TN_INPAD_SOURCE", "TN_INPAD_OPIN", "TN_OUTPAD_IPIN",
1397 
1398  "TN_OUTPAD_SINK", "TN_CB_IPIN", "TN_CB_OPIN", "TN_INTERMEDIATE_NODE",
1399  "TN_PRIMITIVE_IPIN", "TN_PRIMITIVE_OPIN", "TN_FF_IPIN", "TN_FF_OPIN", "TN_FF_SINK",
1400  "TN_FF_SOURCE", "TN_FF_CLOCK", "TN_CONSTANT_GEN_SOURCE" };
1401 
1402  fp = my_fopen(fname, "w", 0);
1403 
1404  fprintf(fp, "num_tnodes: %d\n", num_tnodes);
1405  fprintf(fp, "Node #\tType\t\tipin\tiblk\tDomain\tSkew\tI/O Delay\t# edges\t"
1406  "to_node Tdel\n\n");
1407 
1408  for (inode = 0; inode < num_tnodes; inode++) {
1409  fprintf(fp, "%d\t", inode);
1410 
1411  itype = tnode[inode].type;
1412  fprintf(fp, "%-15.15s\t", tnode_type_names[itype]);
1413 
1414  if (tnode[inode].pb_graph_pin != NULL) {
1415  fprintf(fp, "%d\t%d\t",
1416  tnode[inode].pb_graph_pin->pin_count_in_cluster,
1417  tnode[inode].block);
1418  } else {
1419  fprintf(fp, "\t%d\t", tnode[inode].block);
1420  }
1421 
1422  if (itype == TN_FF_CLOCK || itype == TN_FF_SOURCE || itype == TN_FF_SINK) {
1423  fprintf(fp, "%d\t%.3e\t\t", tnode[inode].clock_domain, tnode[inode].clock_delay);
1424  } else if (itype == TN_INPAD_SOURCE) {
1425  fprintf(fp, "%d\t\t%.3e\t", tnode[inode].clock_domain, tnode[inode].out_edges[0].Tdel);
1426  } else if (itype == TN_OUTPAD_SINK) {
1427  assert(tnode[inode-1].type == TN_OUTPAD_IPIN); /* Outpad ipins should be one prior in the tnode array */
1428  fprintf(fp, "%d\t\t%.3e\t", tnode[inode].clock_domain, tnode[inode-1].out_edges[0].Tdel);
1429  } else {
1430  fprintf(fp, "\t\t\t\t");
1431  }
1432 
1433  fprintf(fp, "%d", tnode[inode].num_edges);
1434 
1435  /* Print all edges after edge 0 on separate lines */
1436  tedge = tnode[inode].out_edges;
1437  if (tnode[inode].num_edges > 0) {
1438  fprintf(fp, "\t%4d\t%7.3g", tedge[0].to_node, tedge[0].Tdel);
1439  for (iedge = 1; iedge < tnode[inode].num_edges; iedge++) {
1440  fprintf(fp, "\n\t\t\t\t\t\t\t\t\t\t%4d\t%7.3g", tedge[iedge].to_node, tedge[iedge].Tdel);
1441  }
1442  }
1443  fprintf(fp, "\n");
1444  }
1445 
1446  fprintf(fp, "\n\nnum_tnode_levels: %d\n", num_tnode_levels);
1447 
1448  for (ilevel = 0; ilevel < num_tnode_levels; ilevel++) {
1449  fprintf(fp, "\n\nLevel: %d Num_nodes: %d\nNodes:", ilevel,
1450  tnodes_at_level[ilevel].nelem);
1451  for (i = 0; i < tnodes_at_level[ilevel].nelem; i++)
1452  fprintf(fp, "\t%d", tnodes_at_level[ilevel].list[i]);
1453  }
1454 
1455  fprintf(fp, "\n");
1456  fprintf(fp, "\n\nNet #\tNet_to_driver_tnode\n");
1457 
1458  for (i = 0; i < num_nets; i++)
1459  fprintf(fp, "%4d\t%6d\n", i, f_net_to_driver_tnode[i]);
1460 
1461  if (g_sdc->num_constrained_clocks == 1) {
1462  /* Arrival and required times, and forward and backward weights, will be meaningless for multiclock
1463  designs, since the values currently on the graph will only correspond to the most recent traversal. */
1464  fprintf(fp, "\n\nNode #\t\tT_arr\t\tT_req"
1465 #ifdef PATH_COUNTING
1466  "\tForward weight\tBackward weight"
1467 #endif
1468  "\n\n");
1469 
1470  for (inode = 0; inode < num_tnodes; inode++) {
1471  if (tnode[inode].T_arr > HUGE_NEGATIVE_FLOAT + 1) {
1472  fprintf(fp, "%d\t%12g", inode, tnode[inode].T_arr);
1473  } else {
1474  fprintf(fp, "%d\t\t -", inode);
1475  }
1476  if (tnode[inode].T_req < HUGE_POSITIVE_FLOAT - 1) {
1477  fprintf(fp, "\t%12g", tnode[inode].T_req);
1478  } else {
1479  fprintf(fp, "\t\t -");
1480  }
1481 #ifdef PATH_COUNTING
1482  fprintf(fp, "\t%12g\t%12g\n", tnode[inode].forward_weight, tnode[inode].backward_weight);
1483 #endif
1484  }
1485  }
1486 
1487  fclose(fp);
1488 }
struct s_ivec * tnodes_at_level
Definition: path_delay2.c:12
FILE * my_fopen(const char *fname, const char *flag, int prompt)
Definition: util.c:54
int num_tnodes
Definition: path_delay.c:144
e_tnode_type
Definition: vpr_types.h:300
int num_nets
Definition: globals.c:27
int num_edges
Definition: vpr_types.h:342
int num_tnode_levels
Definition: path_delay2.c:10
int block
Definition: vpr_types.h:346
#define HUGE_POSITIVE_FLOAT
Definition: vpr_types.h:79
t_tnode * tnode
Definition: path_delay.c:143
struct s_block * block
Definition: globals.c:31
int nelem
Definition: util.h:48
static int * f_net_to_driver_tnode
Definition: path_delay.c:161
t_tedge * out_edges
Definition: vpr_types.h:336
e_tnode_type type
Definition: vpr_types.h:335
t_timing_constraints * g_sdc
Definition: read_sdc.c:65
#define HUGE_NEGATIVE_FLOAT
Definition: vpr_types.h:80

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void print_timing_graph_as_blif ( const char *  fname,
t_model models 
)

Definition at line 3360 of file path_delay.c.

3360  {
3361  struct s_model_ports *port;
3362  struct s_linked_vptr *p_io_removed;
3363  /* Prints out the critical path to a file. */
3364 
3365  FILE *fp;
3366  int i, j;
3367 
3368  fp = my_fopen(fname, "w", 0);
3369 
3370  fprintf(fp, ".model %s\n", blif_circuit_name);
3371 
3372  fprintf(fp, ".inputs ");
3373  for (i = 0; i < num_logical_blocks; i++) {
3374  if (logical_block[i].type == VPACK_INPAD) {
3375  fprintf(fp, "\\\n%s ", logical_block[i].name);
3376  }
3377  }
3378  p_io_removed = circuit_p_io_removed;
3379  while (p_io_removed) {
3380  fprintf(fp, "\\\n%s ", (char *) p_io_removed->data_vptr);
3381  p_io_removed = p_io_removed->next;
3382  }
3383 
3384  fprintf(fp, "\n");
3385 
3386  fprintf(fp, ".outputs ");
3387  for (i = 0; i < num_logical_blocks; i++) {
3388  if (logical_block[i].type == VPACK_OUTPAD) {
3389  /* Outputs have a "out:" prepended to them, must remove */
3390  fprintf(fp, "\\\n%s ", &logical_block[i].name[4]);
3391  }
3392  }
3393  fprintf(fp, "\n");
3394  fprintf(fp, ".names unconn\n");
3395  fprintf(fp, " 0\n\n");
3396 
3397  /* Print out primitives */
3398  for (i = 0; i < num_logical_blocks; i++) {
3399  print_primitive_as_blif (fp, i);
3400  }
3401 
3402  /* Print out tnode connections */
3403  for (i = 0; i < num_tnodes; i++) {
3404  if (tnode[i].type != TN_PRIMITIVE_IPIN && tnode[i].type != TN_FF_SOURCE
3405  && tnode[i].type != TN_INPAD_SOURCE
3406  && tnode[i].type != TN_OUTPAD_IPIN) {
3407  for (j = 0; j < tnode[i].num_edges; j++) {
3408  fprintf(fp, ".names tnode_%d tnode_%d\n", i,
3409  tnode[i].out_edges[j].to_node);
3410  fprintf(fp, "1 1\n\n");
3411  }
3412  }
3413  }
3414 
3415  fprintf(fp, ".end\n\n");
3416 
3417  /* Print out .subckt models */
3418  while (models) {
3419  fprintf(fp, ".model %s\n", models->name);
3420  fprintf(fp, ".inputs ");
3421  port = models->inputs;
3422  while (port) {
3423  if (port->size > 1) {
3424  for (j = 0; j < port->size; j++) {
3425  fprintf(fp, "%s[%d] ", port->name, j);
3426  }
3427  } else {
3428  fprintf(fp, "%s ", port->name);
3429  }
3430  port = port->next;
3431  }
3432  fprintf(fp, "\n");
3433  fprintf(fp, ".outputs ");
3434  port = models->outputs;
3435  while (port) {
3436  if (port->size > 1) {
3437  for (j = 0; j < port->size; j++) {
3438  fprintf(fp, "%s[%d] ", port->name, j);
3439  }
3440  } else {
3441  fprintf(fp, "%s ", port->name);
3442  }
3443  port = port->next;
3444  }
3445  fprintf(fp, "\n.blackbox\n.end\n\n");
3446  fprintf(fp, "\n\n");
3447  models = models->next;
3448  }
3449  fclose(fp);
3450 }
FILE * my_fopen(const char *fname, const char *flag, int prompt)
Definition: util.c:54
struct s_linked_vptr * circuit_p_io_removed
Definition: globals.c:90
int num_tnodes
Definition: path_delay.c:144
static void print_primitive_as_blif(FILE *fpout, int iblk)
Definition: path_delay.c:3452
struct s_model_ports * next
Definition: logic_types.h:28
char * blif_circuit_name
Definition: globals.c:21
int num_edges
Definition: vpr_types.h:342
t_tnode * tnode
Definition: path_delay.c:143
struct s_model * next
Definition: logic_types.h:40
t_model_ports * inputs
Definition: logic_types.h:35
t_model_ports * outputs
Definition: logic_types.h:36
struct s_linked_vptr * next
Definition: util.h:36
void * data_vptr
Definition: util.h:35
char * name
Definition: logic_types.h:34
int num_logical_blocks
Definition: globals.c:17
struct s_logical_block * logical_block
Definition: globals.c:20

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void print_timing_stats ( void  )

Definition at line 3081 of file path_delay.c.

3081  {
3082 
3083  /* Prints critical path delay/fmax, least slack in design, and, for multiple-clock designs,
3084  minimum required clock period to meet each constraint, least slack per constraint,
3085  geometric average clock frequency, and fanout-weighted geometric average clock frequency. */
3086 
3087  int source_clock_domain, sink_clock_domain, clock_domain, fanout, total_fanout = 0,
3088  num_netlist_clocks_with_intra_domain_paths = 0;
3089  float geomean_period = 1., least_slack_in_design = HUGE_POSITIVE_FLOAT, critical_path_delay = UNDEFINED;
3090  double fanout_weighted_geomean_period = 1.;
3091  boolean found;
3092 
3093  /* Find critical path delay. If the pb_max_internal_delay is greater than this, it becomes
3094  the limiting factor on critical path delay, so print that instead, with a special message. */
3095 
3096  for (source_clock_domain = 0; source_clock_domain < g_sdc->num_constrained_clocks; source_clock_domain++) {
3097  for (sink_clock_domain = 0; sink_clock_domain < g_sdc->num_constrained_clocks; sink_clock_domain++) {
3098  if (least_slack_in_design > f_timing_stats->least_slack[source_clock_domain][sink_clock_domain]) {
3099  least_slack_in_design = f_timing_stats->least_slack[source_clock_domain][sink_clock_domain];
3100  critical_path_delay = f_timing_stats->cpd[source_clock_domain][sink_clock_domain];
3101  }
3102  }
3103  }
3104 
3105  if (pb_max_internal_delay != UNDEFINED && pb_max_internal_delay > critical_path_delay) {
3106  critical_path_delay = pb_max_internal_delay;
3107  vpr_printf(TIO_MESSAGE_INFO, "Final critical path: %g ns\n", 1e9 * critical_path_delay);
3108  vpr_printf(TIO_MESSAGE_INFO, "\t(capped by fmax of block type %s)\n", pbtype_max_internal_delay->name);
3109 
3110  } else {
3111  vpr_printf(TIO_MESSAGE_INFO, "Final critical path: %g ns\n", 1e9 * critical_path_delay);
3112  }
3113 
3114  if (g_sdc->num_constrained_clocks <= 1) {
3115  /* Although critical path delay is always well-defined, it doesn't make sense to talk about fmax for multi-clock circuits */
3116  vpr_printf(TIO_MESSAGE_INFO, "f_max: %g MHz\n", 1e-6 / critical_path_delay);
3117  }
3118 
3119  /* Also print the least slack in the design */
3120  vpr_printf(TIO_MESSAGE_INFO, "\n");
3121  vpr_printf(TIO_MESSAGE_INFO, "Least slack in design: %g ns\n", 1e9 * least_slack_in_design);
3122  vpr_printf(TIO_MESSAGE_INFO, "\n");
3123 
3124  if (g_sdc->num_constrained_clocks > 1) { /* Multiple-clock design */
3125 
3126  /* Print minimum possible clock period to meet each constraint. Convert to nanoseconds. */
3127 
3128  vpr_printf(TIO_MESSAGE_INFO, "Minimum possible clock period to meet each constraint (including skew effects):\n");
3129  for (source_clock_domain = 0; source_clock_domain < g_sdc->num_constrained_clocks; source_clock_domain++) {
3130  /* Print the intra-domain constraint if it was analysed. */
3131  if (g_sdc->domain_constraint[source_clock_domain][source_clock_domain] > NEGATIVE_EPSILON) {
3132  vpr_printf(TIO_MESSAGE_INFO, "%s to %s: %g ns (%g MHz)\n",
3133  g_sdc->constrained_clocks[source_clock_domain].name,
3134  g_sdc->constrained_clocks[source_clock_domain].name,
3135  1e9 * f_timing_stats->cpd[source_clock_domain][source_clock_domain],
3136  1e-6 / f_timing_stats->cpd[source_clock_domain][source_clock_domain]);
3137  } else {
3138  vpr_printf(TIO_MESSAGE_INFO, "%s to %s: --\n",
3139  g_sdc->constrained_clocks[source_clock_domain].name,
3140  g_sdc->constrained_clocks[source_clock_domain].name);
3141  }
3142  /* Then, print all other constraints on separate lines, indented. We re-print
3143  the source clock domain's name so there's no ambiguity when parsing. */
3144  for (sink_clock_domain = 0; sink_clock_domain < g_sdc->num_constrained_clocks; sink_clock_domain++) {
3145  if (source_clock_domain == sink_clock_domain) continue; /* already done that */
3146  if (g_sdc->domain_constraint[source_clock_domain][sink_clock_domain] > NEGATIVE_EPSILON) {
3147  /* If this domain pair was analysed */
3148  vpr_printf(TIO_MESSAGE_INFO, "\t%s to %s: %g ns (%g MHz)\n",
3149  g_sdc->constrained_clocks[source_clock_domain].name,
3150  g_sdc->constrained_clocks[sink_clock_domain].name,
3151  1e9 * f_timing_stats->cpd[source_clock_domain][sink_clock_domain],
3152  1e-6 / f_timing_stats->cpd[source_clock_domain][sink_clock_domain]);
3153  } else {
3154  vpr_printf(TIO_MESSAGE_INFO, "\t%s to %s: --\n",
3155  g_sdc->constrained_clocks[source_clock_domain].name,
3156  g_sdc->constrained_clocks[sink_clock_domain].name);
3157  }
3158  }
3159  }
3160 
3161  /* Print least slack per constraint. */
3162 
3163  vpr_printf(TIO_MESSAGE_INFO, "\n");
3164  vpr_printf(TIO_MESSAGE_INFO, "Least slack per constraint:\n");
3165  for (source_clock_domain = 0; source_clock_domain < g_sdc->num_constrained_clocks; source_clock_domain++) {
3166  /* Print the intra-domain slack if valid. */
3167  if (f_timing_stats->least_slack[source_clock_domain][source_clock_domain] < HUGE_POSITIVE_FLOAT - 1) {
3168  vpr_printf(TIO_MESSAGE_INFO, "%s to %s: %g ns\n",
3169  g_sdc->constrained_clocks[source_clock_domain].name,
3170  g_sdc->constrained_clocks[source_clock_domain].name,
3171  1e9 * f_timing_stats->least_slack[source_clock_domain][source_clock_domain]);
3172  } else {
3173  vpr_printf(TIO_MESSAGE_INFO, "%s to %s: --\n",
3174  g_sdc->constrained_clocks[source_clock_domain].name,
3175  g_sdc->constrained_clocks[source_clock_domain].name);
3176  }
3177  /* Then, print all other slacks on separate lines. */
3178  for (sink_clock_domain = 0; sink_clock_domain < g_sdc->num_constrained_clocks; sink_clock_domain++) {
3179  if (source_clock_domain == sink_clock_domain) continue; /* already done that */
3180  if (f_timing_stats->least_slack[source_clock_domain][sink_clock_domain] < HUGE_POSITIVE_FLOAT - 1) {
3181  /* If this domain pair was analysed and has a valid slack */
3182  vpr_printf(TIO_MESSAGE_INFO, "\t%s to %s: %g ns\n",
3183  g_sdc->constrained_clocks[source_clock_domain].name,
3184  g_sdc->constrained_clocks[sink_clock_domain].name,
3185  1e9 * f_timing_stats->least_slack[source_clock_domain][sink_clock_domain]);
3186  } else {
3187  vpr_printf(TIO_MESSAGE_INFO, "\t%s to %s: --\n",
3188  g_sdc->constrained_clocks[source_clock_domain].name,
3189  g_sdc->constrained_clocks[sink_clock_domain].name);
3190  }
3191  }
3192  }
3193 
3194  /* Calculate geometric mean f_max (fanout-weighted and unweighted) from the diagonal (intra-domain) entries of critical_path_delay,
3195  excluding domains without intra-domain paths (for which the timing constraint is DO_NOT_ANALYSE) and virtual clocks. */
3196  found = FALSE;
3197  for (clock_domain = 0; clock_domain < g_sdc->num_constrained_clocks; clock_domain++) {
3198  if (g_sdc->domain_constraint[clock_domain][clock_domain] > NEGATIVE_EPSILON && g_sdc->constrained_clocks[clock_domain].is_netlist_clock) {
3199  geomean_period *= f_timing_stats->cpd[clock_domain][clock_domain];
3200  fanout = g_sdc->constrained_clocks[clock_domain].fanout;
3201  fanout_weighted_geomean_period *= pow((double) f_timing_stats->cpd[clock_domain][clock_domain], fanout);
3202  total_fanout += fanout;
3203  num_netlist_clocks_with_intra_domain_paths++;
3204  found = TRUE;
3205  }
3206  }
3207  if (found) { /* Only print these if we found at least one clock domain with intra-domain paths. */
3208  geomean_period = pow(geomean_period, (float) 1/num_netlist_clocks_with_intra_domain_paths);
3209  fanout_weighted_geomean_period = pow(fanout_weighted_geomean_period, (double) 1/total_fanout);
3210  /* Convert to MHz */
3211  vpr_printf(TIO_MESSAGE_INFO, "\n");
3212  vpr_printf(TIO_MESSAGE_INFO, "Geometric mean intra-domain period: %g ns (%g MHz)\n",
3213  1e9 * geomean_period, 1e-6 / geomean_period);
3214  vpr_printf(TIO_MESSAGE_INFO, "Fanout-weighted geomean intra-domain period: %g ns (%g MHz)\n",
3215  1e9 * fanout_weighted_geomean_period, 1e-6 / fanout_weighted_geomean_period);
3216  }
3217 
3218  vpr_printf(TIO_MESSAGE_INFO, "\n");
3219  }
3220 }
float pb_max_internal_delay
Definition: globals.c:93
float ** least_slack
Definition: vpr_types.h:399
boolean is_netlist_clock
Definition: vpr_types.h:370
static t_timing_stats * f_timing_stats
Definition: path_delay.c:159
const t_pb_type * pbtype_max_internal_delay
Definition: globals.c:94
float ** domain_constraint
Definition: vpr_types.h:431
#define UNDEFINED
Definition: vpr_types.h:103
Definition: util.h:12
float ** cpd
Definition: vpr_types.h:398
#define HUGE_POSITIVE_FLOAT
Definition: vpr_types.h:79
int fanout
Definition: vpr_types.h:371
char * name
Definition: vpr_types.h:369
t_clock * constrained_clocks
Definition: vpr_types.h:429
t_timing_constraints * g_sdc
Definition: read_sdc.c:65
#define NEGATIVE_EPSILON
Definition: vpr_types.h:84
messagelogger vpr_printf
Definition: util.c:17
Definition: util.h:12

+ Here is the caller graph for this function:

Variable Documentation

int num_tnodes

Definition at line 144 of file path_delay.c.

t_tnode* tnode

Definition at line 143 of file path_delay.c.