VPR-7.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
route_tree_timing.c File Reference
#include <stdio.h>
#include "util.h"
#include "vpr_types.h"
#include "globals.h"
#include "route_common.h"
#include "route_tree_timing.h"
+ Include dependency graph for route_tree_timing.c:

Go to the source code of this file.

Macros

#define NO_ROUTE_THROUGHS   1 /* Can't route through unused CLB outputs */
 

Functions

static t_rt_nodealloc_rt_node (void)
 
static void free_rt_node (t_rt_node *rt_node)
 
static t_linked_rt_edgealloc_linked_rt_edge (void)
 
static void free_linked_rt_edge (t_linked_rt_edge *rt_edge)
 
static t_rt_nodeadd_path_to_route_tree (struct s_heap *hptr, t_rt_node **sink_rt_node_ptr)
 
static void load_new_path_R_upstream (t_rt_node *start_of_new_path_rt_node)
 
static t_rt_nodeupdate_unbuffered_ancestors_C_downstream (t_rt_node *start_of_new_path_rt_node)
 
static void load_rt_subtree_Tdel (t_rt_node *subtree_rt_root, float Tarrival)
 
void alloc_route_tree_timing_structs (void)
 
void free_route_tree_timing_structs (void)
 
t_rt_nodeinit_route_tree_to_source (int inet)
 
t_rt_nodeupdate_route_tree (struct s_heap *hptr)
 
void free_route_tree (t_rt_node *rt_node)
 
void update_net_delays_from_route_tree (float *net_delay, t_rt_node **rt_node_of_sink, int inet)
 

Variables

static t_rt_node ** rr_node_to_rt_node = NULL
 
static t_rt_nodert_node_free_list = NULL
 
static t_linked_rt_edgert_edge_free_list = NULL
 

Macro Definition Documentation

#define NO_ROUTE_THROUGHS   1 /* Can't route through unused CLB outputs */

Function Documentation

static t_rt_node * add_path_to_route_tree ( struct s_heap hptr,
t_rt_node **  sink_rt_node_ptr 
)
static

Definition at line 216 of file route_tree_timing.c.

216  {
217 
218  /* Adds the most recent wire segment, ending at the SINK indicated by hptr, *
219  * to the routing tree. It returns the first (most upstream) new rt_node, *
220  * and (via a pointer) the rt_node of the new SINK. */
221 
222  int inode, remaining_connections_to_sink, no_route_throughs;
223  short iedge, iswitch;
224  float C_downstream;
225  t_rt_node *rt_node, *downstream_rt_node, *sink_rt_node;
226  t_linked_rt_edge *linked_rt_edge;
227 
228  inode = hptr->index;
229 
230 #ifdef DEBUG
231  if (rr_node[inode].type != SINK) {
232  vpr_printf(TIO_MESSAGE_ERROR, "in add_path_to_route_tree. Expected type = SINK (%d).\n", SINK);
233  vpr_printf(TIO_MESSAGE_INFO, "Got type = %d.", rr_node[inode].type);
234  exit(1);
235  }
236 #endif
237 
238  remaining_connections_to_sink = rr_node_route_inf[inode].target_flag;
239  sink_rt_node = alloc_rt_node();
240  sink_rt_node->u.child_list = NULL;
241  sink_rt_node->inode = inode;
242  C_downstream = rr_node[inode].C;
243  sink_rt_node->C_downstream = C_downstream;
244  rr_node_to_rt_node[inode] = sink_rt_node;
245 
246  /* In the code below I'm marking SINKs and IPINs as not to be re-expanded. *
247  * Undefine NO_ROUTE_THROUGHS if you want route-throughs or ipin doglegs. *
248  * It makes the code more efficient (though not vastly) to prune this way *
249  * when there aren't route-throughs or ipin doglegs. */
250 
251 #define NO_ROUTE_THROUGHS 1 /* Can't route through unused CLB outputs */
252  no_route_throughs = 1;
253  if (no_route_throughs == 1)
254  sink_rt_node->re_expand = FALSE;
255  else {
256  if (remaining_connections_to_sink == 0) { /* Usual case */
257  sink_rt_node->re_expand = TRUE;
258  }
259 
260  /* Weird case. This net connects several times to the same SINK. Thus I *
261  * can't re_expand this node as part of the partial routing for subsequent *
262  * connections, since I need to reach it again via another path. */
263 
264  else {
265  sink_rt_node->re_expand = FALSE;
266  }
267  }
268 
269  /* Now do it's predecessor. */
270 
271  downstream_rt_node = sink_rt_node;
272  inode = hptr->u.prev_node;
273  iedge = hptr->prev_edge;
274  iswitch = rr_node[inode].switches[iedge];
275 
276  /* For all "new" nodes in the path */
277 
278  while (rr_node_route_inf[inode].prev_node != NO_PREVIOUS) {
279  linked_rt_edge = alloc_linked_rt_edge();
280  linked_rt_edge->child = downstream_rt_node;
281  linked_rt_edge->iswitch = iswitch;
282  linked_rt_edge->next = NULL;
283 
284  rt_node = alloc_rt_node();
285  downstream_rt_node->parent_node = rt_node;
286  downstream_rt_node->parent_switch = iswitch;
287 
288  rt_node->u.child_list = linked_rt_edge;
289  rt_node->inode = inode;
290 
291  if (switch_inf[iswitch].buffered == FALSE)
292  C_downstream += rr_node[inode].C;
293  else
294  C_downstream = rr_node[inode].C;
295 
296  rt_node->C_downstream = C_downstream;
297  rr_node_to_rt_node[inode] = rt_node;
298 
299  if (no_route_throughs == 1)
300  if (rr_node[inode].type == IPIN)
301  rt_node->re_expand = FALSE;
302  else
303  rt_node->re_expand = TRUE;
304 
305  else {
306  if (remaining_connections_to_sink == 0) { /* Normal case */
307  rt_node->re_expand = TRUE;
308  } else { /* This is the IPIN before a multiply-connected SINK */
309  rt_node->re_expand = FALSE;
310 
311  /* Reset flag so wire segments get reused */
312 
313  remaining_connections_to_sink = 0;
314  }
315  }
316 
317  downstream_rt_node = rt_node;
318  iedge = rr_node_route_inf[inode].prev_edge;
319  inode = rr_node_route_inf[inode].prev_node;
320  iswitch = rr_node[inode].switches[iedge];
321  }
322 
323  /* Inode is the join point to the old routing */
324 
325  rt_node = rr_node_to_rt_node[inode];
326 
327  linked_rt_edge = alloc_linked_rt_edge();
328  linked_rt_edge->child = downstream_rt_node;
329  linked_rt_edge->iswitch = iswitch;
330  linked_rt_edge->next = rt_node->u.child_list;
331  rt_node->u.child_list = linked_rt_edge;
332 
333  downstream_rt_node->parent_node = rt_node;
334  downstream_rt_node->parent_switch = iswitch;
335 
336  *sink_rt_node_ptr = sink_rt_node;
337  return (downstream_rt_node);
338 }
int index
Definition: route_common.h:4
float C_downstream
t_rr_node * rr_node
Definition: globals.c:70
int prev_node
Definition: route_common.h:7
struct s_rt_node * parent_node
t_rr_node_route_inf * rr_node_route_inf
Definition: route_common.c:21
short iswitch
Definition: vpr_types.h:867
#define NO_PREVIOUS
Definition: vpr_types.h:887
float C
Definition: vpr_types.h:907
struct s_linked_rt_edge * next
short parent_switch
Definition: util.h:12
union s_heap::@0 u
int prev_edge
Definition: route_common.h:10
union s_rt_node::@1 u
struct s_switch_inf * switch_inf
Definition: globals.c:83
static t_rt_node ** rr_node_to_rt_node
static t_rt_node * alloc_rt_node(void)
t_linked_rt_edge * child_list
short * switches
Definition: vpr_types.h:904
static t_linked_rt_edge * alloc_linked_rt_edge(void)
struct s_rt_node * child
messagelogger vpr_printf
Definition: util.c:17
Definition: util.h:12

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static t_linked_rt_edge * alloc_linked_rt_edge ( void  )
static

Definition at line 127 of file route_tree_timing.c.

127  {
128 
129  /* Allocates a new linked_rt_edge, from the free list if possible, from the *
130  * free store otherwise. */
131 
132  t_linked_rt_edge *linked_rt_edge;
133 
134  linked_rt_edge = rt_edge_free_list;
135 
136  if (linked_rt_edge != NULL) {
137  rt_edge_free_list = linked_rt_edge->next;
138  } else {
139  linked_rt_edge = (t_linked_rt_edge *) my_malloc(
140  sizeof(t_linked_rt_edge));
141  }
142 
143  return (linked_rt_edge);
144 }
static t_linked_rt_edge * rt_edge_free_list
struct s_linked_rt_edge * next
static void * my_malloc(int ibytes)
Definition: graphics.c:499

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void alloc_route_tree_timing_structs ( void  )

Definition at line 53 of file route_tree_timing.c.

53  {
54 
55  /* Allocates any structures needed to build the routing trees. */
56 
57  if (rr_node_to_rt_node != NULL || rt_node_free_list != NULL
58  || rt_node_free_list != NULL) {
59  vpr_printf(TIO_MESSAGE_ERROR, "in alloc_route_tree_timing_structs: old structures already exist.\n");
60  exit(1);
61  }
62 
64  num_rr_nodes * sizeof(t_rt_node *));
65 }
static t_rt_node * rt_node_free_list
static void * my_malloc(int ibytes)
Definition: graphics.c:499
int num_rr_nodes
Definition: globals.c:69
static t_rt_node ** rr_node_to_rt_node
messagelogger vpr_printf
Definition: util.c:17

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static t_rt_node * alloc_rt_node ( void  )
static

Definition at line 100 of file route_tree_timing.c.

100  {
101 
102  /* Allocates a new rt_node, from the free list if possible, from the free *
103  * store otherwise. */
104 
105  t_rt_node *rt_node;
106 
107  rt_node = rt_node_free_list;
108 
109  if (rt_node != NULL) {
110  rt_node_free_list = rt_node->u.next;
111  } else {
112  rt_node = (t_rt_node *) my_malloc(sizeof(t_rt_node));
113  }
114 
115  return (rt_node);
116 }
static t_rt_node * rt_node_free_list
static void * my_malloc(int ibytes)
Definition: graphics.c:499
union s_rt_node::@1 u
struct s_rt_node * next

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void free_linked_rt_edge ( t_linked_rt_edge rt_edge)
static

Definition at line 146 of file route_tree_timing.c.

146  {
147 
148  /* Adds the rt_edge to the rt_edge free list. */
149 
150  rt_edge->next = rt_edge_free_list;
151  rt_edge_free_list = rt_edge;
152 }
static t_linked_rt_edge * rt_edge_free_list
struct s_linked_rt_edge * next

+ Here is the caller graph for this function:

void free_route_tree ( t_rt_node rt_node)

Definition at line 458 of file route_tree_timing.c.

458  {
459 
460  /* Puts the rt_nodes and edges in the tree rooted at rt_node back on the *
461  * free lists. Recursive, depth-first post-order traversal. */
462 
463  t_rt_node *child_node;
464  t_linked_rt_edge *rt_edge, *next_edge;
465 
466  rt_edge = rt_node->u.child_list;
467 
468  while (rt_edge != NULL) { /* For all children */
469  child_node = rt_edge->child;
470  free_route_tree(child_node);
471  next_edge = rt_edge->next;
472  free_linked_rt_edge(rt_edge);
473  rt_edge = next_edge;
474  }
475 
476  free_rt_node(rt_node);
477 }
struct s_linked_rt_edge * next
static void free_linked_rt_edge(t_linked_rt_edge *rt_edge)
void free_route_tree(t_rt_node *rt_node)
static void free_rt_node(t_rt_node *rt_node)
union s_rt_node::@1 u
t_linked_rt_edge * child_list
struct s_rt_node * child

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void free_route_tree_timing_structs ( void  )

Definition at line 67 of file route_tree_timing.c.

67  {
68 
69  /* Frees the structures needed to build routing trees, and really frees *
70  * (i.e. calls free) all the data on the free lists. */
71 
72  t_rt_node *rt_node, *next_node;
73  t_linked_rt_edge *rt_edge, *next_edge;
74 
75  free(rr_node_to_rt_node);
76  rr_node_to_rt_node = NULL;
77 
78  rt_node = rt_node_free_list;
79 
80  while (rt_node != NULL) {
81  next_node = rt_node->u.next;
82  free(rt_node);
83  rt_node = next_node;
84  }
85 
86  rt_node_free_list = NULL;
87 
88  rt_edge = rt_edge_free_list;
89 
90  while (rt_edge != NULL) {
91  next_edge = rt_edge->next;
92  free(rt_edge);
93  rt_edge = next_edge;
94  }
95 
96  rt_edge_free_list = NULL;
97 }
static t_rt_node * rt_node_free_list
static t_linked_rt_edge * rt_edge_free_list
struct s_linked_rt_edge * next
union s_rt_node::@1 u
static t_rt_node ** rr_node_to_rt_node
struct s_rt_node * next

+ Here is the caller graph for this function:

static void free_rt_node ( t_rt_node rt_node)
static

Definition at line 118 of file route_tree_timing.c.

118  {
119 
120  /* Adds rt_node to the proper free list. */
121 
122  rt_node->u.next = rt_node_free_list;
123  rt_node_free_list = rt_node;
124 }
static t_rt_node * rt_node_free_list
union s_rt_node::@1 u
struct s_rt_node * next

+ Here is the caller graph for this function:

t_rt_node* init_route_tree_to_source ( int  inet)

Definition at line 155 of file route_tree_timing.c.

155  {
156 
157  /* Initializes the routing tree to just the net source, and returns the root *
158  * node of the rt_tree (which is just the net source). */
159 
160  t_rt_node *rt_root;
161  int inode;
162 
163  rt_root = alloc_rt_node();
164  rt_root->u.child_list = NULL;
165  rt_root->parent_node = NULL;
166  rt_root->parent_switch = OPEN;
167  rt_root->re_expand = TRUE;
168 
169  inode = net_rr_terminals[inet][0]; /* Net source */
170 
171  rt_root->inode = inode;
172  rt_root->C_downstream = rr_node[inode].C;
173  rt_root->R_upstream = rr_node[inode].R;
174  rt_root->Tdel = 0.5 * rr_node[inode].R * rr_node[inode].C;
175  rr_node_to_rt_node[inode] = rt_root;
176 
177  return (rt_root);
178 }
float R
Definition: vpr_types.h:906
float C_downstream
t_rr_node * rr_node
Definition: globals.c:70
struct s_rt_node * parent_node
float C
Definition: vpr_types.h:907
short parent_switch
union s_rt_node::@1 u
static t_rt_node ** rr_node_to_rt_node
static t_rt_node * alloc_rt_node(void)
t_linked_rt_edge * child_list
Definition: slre.c:50
int ** net_rr_terminals
Definition: globals.c:78
Definition: util.h:12

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void load_new_path_R_upstream ( t_rt_node start_of_new_path_rt_node)
static

Definition at line 340 of file route_tree_timing.c.

340  {
341 
342  /* Sets the R_upstream values of all the nodes in the new path to the *
343  * correct value. */
344 
345  float R_upstream;
346  int inode;
347  short iswitch;
348  t_rt_node *rt_node, *parent_rt_node;
349  t_linked_rt_edge *linked_rt_edge;
350 
351  rt_node = start_of_new_path_rt_node;
352  iswitch = rt_node->parent_switch;
353  inode = rt_node->inode;
354  parent_rt_node = rt_node->parent_node;
355 
356  R_upstream = switch_inf[iswitch].R + rr_node[inode].R;
357 
358  if (switch_inf[iswitch].buffered == FALSE)
359  R_upstream += parent_rt_node->R_upstream;
360 
361  rt_node->R_upstream = R_upstream;
362 
363  /* Note: the traversal below makes use of the fact that this new path *
364  * really is a path (not a tree with branches) to do a traversal without *
365  * recursion, etc. */
366 
367  linked_rt_edge = rt_node->u.child_list;
368 
369  while (linked_rt_edge != NULL) { /* While SINK not reached. */
370 
371 #ifdef DEBUG
372  if (linked_rt_edge->next != NULL) {
373  vpr_printf(TIO_MESSAGE_ERROR, "in load_new_path_R_upstream: new routing addition is a tree (not a path).\n");
374  exit(1);
375  }
376 #endif
377 
378  rt_node = linked_rt_edge->child;
379  iswitch = linked_rt_edge->iswitch;
380  inode = rt_node->inode;
381 
382  if (switch_inf[iswitch].buffered)
383  R_upstream = switch_inf[iswitch].R + rr_node[inode].R;
384  else
385  R_upstream += switch_inf[iswitch].R + rr_node[inode].R;
386 
387  rt_node->R_upstream = R_upstream;
388  linked_rt_edge = rt_node->u.child_list;
389  }
390 }
float R
Definition: vpr_types.h:906
t_rr_node * rr_node
Definition: globals.c:70
struct s_rt_node * parent_node
short iswitch
Definition: vpr_types.h:867
struct s_linked_rt_edge * next
short parent_switch
Definition: util.h:12
union s_rt_node::@1 u
struct s_switch_inf * switch_inf
Definition: globals.c:83
t_linked_rt_edge * child_list
struct s_rt_node * child
messagelogger vpr_printf
Definition: util.c:17

+ Here is the caller graph for this function:

static void load_rt_subtree_Tdel ( t_rt_node subtree_rt_root,
float  Tarrival 
)
static

Definition at line 419 of file route_tree_timing.c.

419  {
420 
421  /* Updates the Tdel values of the subtree rooted at subtree_rt_root by *
422  * by calling itself recursively. The C_downstream values of all the nodes *
423  * must be correct before this routine is called. Tarrival is the time at *
424  * at which the signal arrives at this node's *input*. */
425 
426  int inode;
427  short iswitch;
428  t_rt_node *child_node;
429  t_linked_rt_edge *linked_rt_edge;
430  float Tdel, Tchild;
431 
432  inode = subtree_rt_root->inode;
433 
434  /* Assuming the downstream connections are, on average, connected halfway *
435  * along a wire segment's length. See discussion in net_delay.c if you want *
436  * to change this. */
437 
438  Tdel = Tarrival + 0.5 * subtree_rt_root->C_downstream * rr_node[inode].R;
439  subtree_rt_root->Tdel = Tdel;
440 
441  /* Now expand the children of this node to load their Tdel values (depth- *
442  * first pre-order traversal). */
443 
444  linked_rt_edge = subtree_rt_root->u.child_list;
445 
446  while (linked_rt_edge != NULL) {
447  iswitch = linked_rt_edge->iswitch;
448  child_node = linked_rt_edge->child;
449 
450  Tchild = Tdel + switch_inf[iswitch].R * child_node->C_downstream;
451  Tchild += switch_inf[iswitch].Tdel; /* Intrinsic switch delay. */
452  load_rt_subtree_Tdel(child_node, Tchild);
453 
454  linked_rt_edge = linked_rt_edge->next;
455  }
456 }
float R
Definition: vpr_types.h:906
float C_downstream
t_rr_node * rr_node
Definition: globals.c:70
short iswitch
Definition: vpr_types.h:867
struct s_linked_rt_edge * next
static void load_rt_subtree_Tdel(t_rt_node *subtree_rt_root, float Tarrival)
union s_rt_node::@1 u
struct s_switch_inf * switch_inf
Definition: globals.c:83
t_linked_rt_edge * child_list
struct s_rt_node * child

+ Here is the caller graph for this function:

void update_net_delays_from_route_tree ( float *  net_delay,
t_rt_node **  rt_node_of_sink,
int  inet 
)

Definition at line 479 of file route_tree_timing.c.

480  {
481 
482  /* Goes through all the sinks of this net and copies their delay values from *
483  * the route_tree to the net_delay array. */
484 
485  int isink;
486  t_rt_node *sink_rt_node;
487 
488  for (isink = 1; isink <= clb_net[inet].num_sinks; isink++) {
489  sink_rt_node = rt_node_of_sink[isink];
490  net_delay[isink] = sink_rt_node->Tdel;
491  }
492 }
static float ** net_delay
struct s_net * clb_net
Definition: globals.c:28
int num_sinks
Definition: vpr_types.h:506

+ Here is the caller graph for this function:

t_rt_node* update_route_tree ( struct s_heap hptr)

Definition at line 181 of file route_tree_timing.c.

181  {
182 
183  /* Adds the most recently finished wire segment to the routing tree, and *
184  * updates the Tdel, etc. numbers for the rest of the routing tree. hptr *
185  * is the heap pointer of the SINK that was reached. This routine returns *
186  * a pointer to the rt_node of the SINK that it adds to the routing. */
187 
188  t_rt_node *start_of_new_path_rt_node, *sink_rt_node;
189  t_rt_node *unbuffered_subtree_rt_root, *subtree_parent_rt_node;
190  float Tdel_start;
191  short iswitch;
192 
193  start_of_new_path_rt_node = add_path_to_route_tree(hptr, &sink_rt_node);
194  load_new_path_R_upstream(start_of_new_path_rt_node);
195  unbuffered_subtree_rt_root = update_unbuffered_ancestors_C_downstream(
196  start_of_new_path_rt_node);
197 
198  subtree_parent_rt_node = unbuffered_subtree_rt_root->parent_node;
199 
200  if (subtree_parent_rt_node != NULL) { /* Parent exists. */
201  Tdel_start = subtree_parent_rt_node->Tdel;
202  iswitch = unbuffered_subtree_rt_root->parent_switch;
203  Tdel_start += switch_inf[iswitch].R
204  * unbuffered_subtree_rt_root->C_downstream;
205  Tdel_start += switch_inf[iswitch].Tdel;
206  } else { /* Subtree starts at SOURCE */
207  Tdel_start = 0.;
208  }
209 
210  load_rt_subtree_Tdel(unbuffered_subtree_rt_root, Tdel_start);
211 
212  return (sink_rt_node);
213 }
static t_rt_node * add_path_to_route_tree(struct s_heap *hptr, t_rt_node **sink_rt_node_ptr)
float C_downstream
struct s_rt_node * parent_node
short iswitch
Definition: vpr_types.h:867
static void load_rt_subtree_Tdel(t_rt_node *subtree_rt_root, float Tarrival)
short parent_switch
struct s_switch_inf * switch_inf
Definition: globals.c:83
static t_rt_node * update_unbuffered_ancestors_C_downstream(t_rt_node *start_of_new_path_rt_node)
static void load_new_path_R_upstream(t_rt_node *start_of_new_path_rt_node)

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static t_rt_node * update_unbuffered_ancestors_C_downstream ( t_rt_node start_of_new_path_rt_node)
static

Definition at line 393 of file route_tree_timing.c.

393  {
394 
395  /* Updates the C_downstream values for the ancestors of the new path. Once *
396  * a buffered switch is found amongst the ancestors, no more ancestors are *
397  * affected. Returns the root of the "unbuffered subtree" whose Tdel *
398  * values are affected by the new path's addition. */
399 
400  t_rt_node *rt_node, *parent_rt_node;
401  short iswitch;
402  float C_downstream_addition;
403 
404  rt_node = start_of_new_path_rt_node;
405  C_downstream_addition = rt_node->C_downstream;
406  parent_rt_node = rt_node->parent_node;
407  iswitch = rt_node->parent_switch;
408 
409  while (parent_rt_node != NULL && switch_inf[iswitch].buffered == FALSE) {
410  rt_node = parent_rt_node;
411  rt_node->C_downstream += C_downstream_addition;
412  parent_rt_node = rt_node->parent_node;
413  iswitch = rt_node->parent_switch;
414  }
415 
416  return (rt_node);
417 }
float C_downstream
struct s_rt_node * parent_node
short iswitch
Definition: vpr_types.h:867
short parent_switch
Definition: util.h:12
struct s_switch_inf * switch_inf
Definition: globals.c:83

+ Here is the caller graph for this function:

Variable Documentation

t_rt_node** rr_node_to_rt_node = NULL
static

Definition at line 24 of file route_tree_timing.c.

t_linked_rt_edge* rt_edge_free_list = NULL
static

Definition at line 29 of file route_tree_timing.c.

t_rt_node* rt_node_free_list = NULL
static

Definition at line 28 of file route_tree_timing.c.