VPR-7.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
rr_graph_timing_params.c
Go to the documentation of this file.
1 #include <assert.h>
2 #include "util.h"
3 #include "vpr_types.h"
4 #include "globals.h"
5 #include "rr_graph.h"
6 #include "rr_graph_util.h"
7 #include "rr_graph2.h"
9 
10 /****************** Subroutine definitions *********************************/
11 
12 void add_rr_graph_C_from_switches(float C_ipin_cblock) {
13 
14  /* This routine finishes loading the C elements of the rr_graph. It assumes *
15  * that when you call it the CHANX and CHANY nodes have had their C set to *
16  * their metal capacitance, and everything else has C set to 0. The graph *
17  * connectivity (edges, switch types etc.) must all be loaded too. This *
18  * routine will add in the capacitance on the CHANX and CHANY nodes due to: *
19  * *
20  * 1) The output capacitance of the switches coming from OPINs; *
21  * 2) The input and output capacitance of the switches between the various *
22  * wiring (CHANX and CHANY) segments; and *
23  * 3) The input capacitance of the buffers separating routing tracks from *
24  * the connection block inputs. */
25 
26  int inode, iedge, switch_index, to_node, maxlen;
27  int icblock, isblock, iseg_low, iseg_high;
28  float Cin, Cout;
29  t_rr_type from_rr_type, to_rr_type;
30  boolean * cblock_counted; /* [0..max(nx,ny)] -- 0th element unused. */
31  float *buffer_Cin; /* [0..max(nx,ny)] */
32  boolean buffered;
33  float *Couts_to_add; /* UDSD */
34 
35  maxlen = std::max(nx, ny) + 1;
36  cblock_counted = (boolean *) my_calloc(maxlen, sizeof(boolean));
37  buffer_Cin = (float *) my_calloc(maxlen, sizeof(float));
38 
39  for (inode = 0; inode < num_rr_nodes; inode++) {
40 
41  from_rr_type = rr_node[inode].type;
42 
43  if (from_rr_type == CHANX || from_rr_type == CHANY) {
44 
45  for (iedge = 0; iedge < rr_node[inode].num_edges; iedge++) {
46 
47  to_node = rr_node[inode].edges[iedge];
48  to_rr_type = rr_node[to_node].type;
49 
50  if (to_rr_type == CHANX || to_rr_type == CHANY) {
51 
52  switch_index = rr_node[inode].switches[iedge];
53  Cin = switch_inf[switch_index].Cin;
54  Cout = switch_inf[switch_index].Cout;
55  buffered = switch_inf[switch_index].buffered;
56 
57  /* If both the switch from inode to to_node and the switch from *
58  * to_node back to inode use bidirectional switches (i.e. pass *
59  * transistors), there will only be one physical switch for *
60  * both edges. Hence, I only want to count the capacitance of *
61  * that switch for one of the two edges. (Note: if there is *
62  * a pass transistor edge from x to y, I always build the graph *
63  * so that there is a corresponding edge using the same switch *
64  * type from y to x.) So, I arbitrarily choose to add in the *
65  * capacitance in that case of a pass transistor only when *
66  * processing the the lower inode number. *
67  * If an edge uses a buffer I always have to add in the output *
68  * capacitance. I assume that buffers are shared at the same *
69  * (i,j) location, so only one input capacitance needs to be *
70  * added for all the buffered switches at that location. If *
71  * the buffers at that location have different sizes, I use the *
72  * input capacitance of the largest one. */
73 
74  if (!buffered && inode < to_node) { /* Pass transistor. */
75  rr_node[inode].C += Cin;
76  rr_node[to_node].C += Cout;
77  }
78 
79  else if (buffered) {
80  /* Prevent double counting of capacitance for UDSD */
81  if (rr_node[to_node].drivers != SINGLE) {
82  /* For multiple-driver architectures the output capacitance can
83  * be added now since each edge is actually a driver */
84  rr_node[to_node].C += Cout;
85  }
86  isblock = seg_index_of_sblock(inode, to_node);
87  buffer_Cin[isblock] = std::max(buffer_Cin[isblock], Cin);
88  }
89 
90  }
91  /* End edge to CHANX or CHANY node. */
92  else if (to_rr_type == IPIN) {
93 
94  /* Code below implements sharing of the track to connection *
95  * box buffer. I assume there is one such buffer at every *
96  * segment of the wire at which at least one logic block input *
97  * connects. */
98 
99  icblock = seg_index_of_cblock(from_rr_type, to_node);
100  if (cblock_counted[icblock] == FALSE) {
101  rr_node[inode].C += C_ipin_cblock;
102  cblock_counted[icblock] = TRUE;
103  }
104  }
105  } /* End loop over all edges of a node. */
106 
107  /* Reset the cblock_counted and buffer_Cin arrays, and add buf Cin. */
108 
109  /* Method below would be faster for very unpopulated segments, but I *
110  * think it would be slower overall for most FPGAs, so commented out. */
111 
112  /* for (iedge=0;iedge<rr_node[inode].num_edges;iedge++) {
113  * to_node = rr_node[inode].edges[iedge];
114  * if (rr_node[to_node].type == IPIN) {
115  * icblock = seg_index_of_cblock (from_rr_type, to_node);
116  * cblock_counted[icblock] = FALSE;
117  * }
118  * } */
119 
120  if (from_rr_type == CHANX) {
121  iseg_low = rr_node[inode].xlow;
122  iseg_high = rr_node[inode].xhigh;
123  } else { /* CHANY */
124  iseg_low = rr_node[inode].ylow;
125  iseg_high = rr_node[inode].yhigh;
126  }
127 
128  for (icblock = iseg_low; icblock <= iseg_high; icblock++) {
129  cblock_counted[icblock] = FALSE;
130  }
131 
132  for (isblock = iseg_low - 1; isblock <= iseg_high; isblock++) {
133  rr_node[inode].C += buffer_Cin[isblock]; /* Biggest buf Cin at loc */
134  buffer_Cin[isblock] = 0.;
135  }
136 
137  }
138  /* End node is CHANX or CHANY */
139  else if (from_rr_type == OPIN) {
140 
141  for (iedge = 0; iedge < rr_node[inode].num_edges; iedge++) {
142  switch_index = rr_node[inode].switches[iedge];
143  /* UDSD by ICK Start */
144  to_node = rr_node[inode].edges[iedge];
145  to_rr_type = rr_node[to_node].type;
146  assert(to_rr_type == CHANX || to_rr_type == CHANY || to_rr_type == IPIN);
147  if (rr_node[to_node].drivers != SINGLE) {
148  Cout = switch_inf[switch_index].Cout;
149  to_node = rr_node[inode].edges[iedge]; /* Will be CHANX or CHANY or IPIN */
150  rr_node[to_node].C += Cout;
151  }
152  }
153  }
154  /* End node is OPIN. */
155  } /* End for all nodes. */
156 
157  /* Now we need to add any cout loads for nets that we previously didn't process
158  * Current structures only keep switch information from a node to the next node and
159  * not the reverse. Therefore I need to go through all the possible edges to figure
160  * out what the Cout's should be */
161  Couts_to_add = (float *) my_calloc(num_rr_nodes, sizeof(float));
162  for (inode = 0; inode < num_rr_nodes; inode++) {
163  for (iedge = 0; iedge < rr_node[inode].num_edges; iedge++) {
164  switch_index = rr_node[inode].switches[iedge];
165  to_node = rr_node[inode].edges[iedge];
166  to_rr_type = rr_node[to_node].type;
167  if (to_rr_type == CHANX || to_rr_type == CHANY) {
168  if (rr_node[to_node].drivers == SINGLE) {
169  /* Cout was not added in these cases */
170  if (Couts_to_add[to_node] != 0) {
171  /* We've already found a Cout to add to this node
172  * We could take the max of all possibilities but
173  * instead I will fail if there are conflicting Couts */
174  if (Couts_to_add[to_node]
175  != switch_inf[switch_index].Cout) {
176  vpr_printf(TIO_MESSAGE_ERROR, "A single driver resource (%i) is driven by different Cout's (%e!=%e)\n",
177  to_node, Couts_to_add[to_node],
178  switch_inf[switch_index].Cout);
179  exit(1);
180  }
181  }
182  Couts_to_add[to_node] = switch_inf[switch_index].Cout;
183 
184  }
185  }
186  }
187  }
188  for (inode = 0; inode < num_rr_nodes; inode++) {
189  rr_node[inode].C += Couts_to_add[inode];
190  }
191  free(Couts_to_add);
192  free(cblock_counted);
193  free(buffer_Cin);
194 }
short xhigh
Definition: vpr_types.h:891
short num_edges
Definition: vpr_types.h:901
int seg_index_of_cblock(t_rr_type from_rr_type, int to_node)
Definition: rr_graph_util.c:40
int * edges
Definition: vpr_types.h:903
t_rr_node * rr_node
Definition: globals.c:70
short ylow
Definition: vpr_types.h:892
float C
Definition: vpr_types.h:907
void * my_calloc(size_t nelem, size_t size)
Definition: util.c:132
Definition: util.h:12
int seg_index_of_sblock(int from_node, int to_node)
Definition: rr_graph_util.c:52
#define max(a, b)
Definition: graphics.c:171
int num_rr_nodes
Definition: globals.c:69
int nx
Definition: globals.c:46
struct s_switch_inf * switch_inf
Definition: globals.c:83
void add_rr_graph_C_from_switches(float C_ipin_cblock)
short yhigh
Definition: vpr_types.h:893
enum e_rr_type t_rr_type
short * switches
Definition: vpr_types.h:904
short xlow
Definition: vpr_types.h:890
boolean buffered
int ny
Definition: globals.c:47
messagelogger vpr_printf
Definition: util.c:17
t_rr_type type
Definition: vpr_types.h:902
Definition: util.h:12