VPR-7.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
check_rr_graph.c
Go to the documentation of this file.
1 #include "util.h"
2 #include "vpr_types.h"
3 #include "globals.h"
4 #include "rr_graph.h"
5 #include "check_rr_graph.h"
6 
7 /********************** Local defines and types *****************************/
8 
9 #define BUF_FLAG 1
10 #define PTRANS_FLAG 2
11 #define BUF_AND_PTRANS_FLAG 3
12 
13 /*********************** Subroutines local to this module *******************/
14 
15 static boolean rr_node_is_global_clb_ipin(int inode);
16 
17 static void check_pass_transistors(int from_node);
18 
19 /************************ Subroutine definitions ****************************/
20 
21 void check_rr_graph(INP t_graph_type graph_type, INP t_type_ptr types,
22  INP int L_nx, INP int L_ny, INP int nodes_per_chan, INP int Fs,
23  INP int num_seg_types, INP int num_switches,
24  INP t_segment_inf * segment_inf, INP int global_route_switch,
25  INP int delayless_switch, INP int wire_to_ipin_switch,
26  t_seg_details * seg_details, int **Fc_in, int **Fc_out,
27  int *****opin_to_track_map, int *****ipin_to_track_map,
28  t_ivec **** track_to_ipin_lookup, t_ivec *** switch_block_conn,
29  boolean * perturb_ipins) {
30 
31  int *num_edges_from_current_to_node; /* [0..num_rr_nodes-1] */
32  int *total_edges_to_node; /* [0..num_rr_nodes-1] */
33  char *switch_types_from_current_to_node; /* [0..num_rr_nodes-1] */
34  int inode, iedge, to_node, num_edges;
35  short switch_type;
36  t_rr_type rr_type, to_rr_type;
37  enum e_route_type route_type;
38  boolean is_fringe_warning_sent;
39  t_type_ptr type;
40 
41  route_type = DETAILED;
42  if (graph_type == GRAPH_GLOBAL) {
43  route_type = GLOBAL;
44  }
45 
46  total_edges_to_node = (int *) my_calloc(num_rr_nodes, sizeof(int));
47  num_edges_from_current_to_node = (int *) my_calloc(num_rr_nodes,
48  sizeof(int));
49  switch_types_from_current_to_node = (char *) my_calloc(num_rr_nodes,
50  sizeof(char));
51 
52  for (inode = 0; inode < num_rr_nodes; inode++) {
53  rr_type = rr_node[inode].type;
54  num_edges = rr_node[inode].num_edges;
55 
56  check_node(inode, route_type);
57 
58  /* Check all the connectivity (edges, etc.) information. */
59 
60  for (iedge = 0; iedge < num_edges; iedge++) {
61  to_node = rr_node[inode].edges[iedge];
62 
63  if (to_node < 0 || to_node >= num_rr_nodes) {
64  vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d has an edge %d.\n", inode, to_node);
65  vpr_printf(TIO_MESSAGE_ERROR, "\tEdge is out of range.\n");
66  exit(1);
67  }
68 
69  num_edges_from_current_to_node[to_node]++;
70  total_edges_to_node[to_node]++;
71 
72  switch_type = rr_node[inode].switches[iedge];
73 
74  if (switch_type < 0 || switch_type >= num_switches) {
75  vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d has a switch type %d.\n", inode, switch_type);
76  vpr_printf(TIO_MESSAGE_ERROR, "\tSwitch type is out of range.\n");
77  exit(1);
78  }
79 
80  if (switch_inf[switch_type].buffered)
81  switch_types_from_current_to_node[to_node] |= BUF_FLAG;
82  else
83  switch_types_from_current_to_node[to_node] |= PTRANS_FLAG;
84 
85  } /* End for all edges of node. */
86 
87  for (iedge = 0; iedge < num_edges; iedge++) {
88  to_node = rr_node[inode].edges[iedge];
89 
90  if (num_edges_from_current_to_node[to_node] > 1) {
91  to_rr_type = rr_node[to_node].type;
92 
93  if ((to_rr_type != CHANX && to_rr_type != CHANY)
94  || (rr_type != CHANX && rr_type != CHANY)) {
95  vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d connects to node %d %d times.\n",
96  inode, to_node, num_edges_from_current_to_node[to_node]);
97  exit(1);
98  }
99 
100  /* Between two wire segments. Two connections are legal only if *
101  * one connection is a buffer and the other is a pass transistor. */
102 
103  else if (num_edges_from_current_to_node[to_node] != 2
104  || switch_types_from_current_to_node[to_node] != BUF_AND_PTRANS_FLAG) {
105  vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d connects to node %d %d times.\n",
106  inode, to_node, num_edges_from_current_to_node[to_node]);
107  exit(1);
108  }
109  }
110 
111  num_edges_from_current_to_node[to_node] = 0;
112  switch_types_from_current_to_node[to_node] = 0;
113  }
114 
115  /* Slow test below. Leave commented out most of the time. */
116 
117 #ifdef DEBUG
118  check_pass_transistors(inode);
119 #endif
120 
121  } /* End for all rr_nodes */
122 
123  /* I built a list of how many edges went to everything in the code above -- *
124  * now I check that everything is reachable. */
125  is_fringe_warning_sent = FALSE;
126 
127  for (inode = 0; inode < num_rr_nodes; inode++) {
128  rr_type = rr_node[inode].type;
129 
130  if (rr_type != SOURCE) {
131  if (total_edges_to_node[inode] < 1
132  && !rr_node_is_global_clb_ipin(inode)) {
133  boolean is_fringe;
134  boolean is_wire;
135  boolean is_chain = FALSE;
136 
137  /* A global CLB input pin will not have any edges, and neither will *
138  * a SOURCE or the start of a carry-chain. Anything else is an error.
139  * For simplicity, carry-chain input pin are entirely ignored in this test
140  */
141 
142  if(rr_type == IPIN) {
143  type = grid[rr_node[inode].xlow][rr_node[inode].ylow].type;
144  if(Fc_in[type->index][rr_node[inode].ptc_num] == 0) {
145  is_chain = TRUE;
146  }
147  }
148 
149  is_fringe = (boolean)((rr_node[inode].xlow == 1)
150  || (rr_node[inode].ylow == 1)
151  || (rr_node[inode].xhigh == L_nx)
152  || (rr_node[inode].yhigh == L_ny));
153  is_wire = (boolean)(rr_node[inode].type == CHANX
154  || rr_node[inode].type == CHANY);
155 
156  if (!is_chain && !is_fringe && !is_wire) {
157  vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d has no fanin.\n", inode);
158  exit(1);
159  } else if (!is_chain && !is_fringe_warning_sent) {
160  vpr_printf(TIO_MESSAGE_WARNING, "in check_rr_graph: fringe node %d has no fanin.\n", inode);
161  vpr_printf(TIO_MESSAGE_WARNING, "\tThis is possible on the fringe for low Fc_out, N, and certain Lengths\n");
162  is_fringe_warning_sent = TRUE;
163  }
164  }
165  }
166 
167  else { /* SOURCE. No fanin for now; change if feedthroughs allowed. */
168  if (total_edges_to_node[inode] != 0) {
169  vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: SOURCE node %d has a fanin of %d, expected 0.\n",
170  inode, total_edges_to_node[inode]);
171  exit(1);
172  }
173  }
174  }
175 
176  free(num_edges_from_current_to_node);
177  free(total_edges_to_node);
178  free(switch_types_from_current_to_node);
179 }
180 
181 static boolean rr_node_is_global_clb_ipin(int inode) {
182 
183  /* Returns TRUE if inode refers to a global CLB input pin node. */
184 
185  int ipin;
186  t_type_ptr type;
187 
188  type = grid[rr_node[inode].xlow][rr_node[inode].ylow].type;
189 
190  if (rr_node[inode].type != IPIN)
191  return (FALSE);
192 
193  ipin = rr_node[inode].ptc_num;
194 
195  return (type->is_global_pin[ipin]);
196 }
197 
198 void check_node(int inode, enum e_route_type route_type) {
199 
200  /* This routine checks that the rr_node is inside the grid and has a valid
201  * pin number, etc.
202  */
203 
204  int xlow, ylow, xhigh, yhigh, ptc_num, capacity;
205  t_rr_type rr_type;
206  t_type_ptr type;
207  int nodes_per_chan, tracks_per_node, num_edges, cost_index;
208  float C, R;
209 
210  rr_type = rr_node[inode].type;
211  xlow = rr_node[inode].xlow;
212  xhigh = rr_node[inode].xhigh;
213  ylow = rr_node[inode].ylow;
214  yhigh = rr_node[inode].yhigh;
215  ptc_num = rr_node[inode].ptc_num;
216  capacity = rr_node[inode].capacity;
217  type = NULL;
218 
219  if (xlow > xhigh || ylow > yhigh) {
220  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: rr endpoints are (%d,%d) and (%d,%d).\n",
221  xlow, ylow, xhigh, yhigh);
222  exit(1);
223  }
224 
225  if (xlow < 0 || xhigh > nx + 1 || ylow < 0 || yhigh > ny + 1) {
226  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: rr endpoints (%d,%d) and (%d,%d) are out of range.\n",
227  xlow, ylow, xhigh, yhigh);
228  exit(1);
229  }
230 
231  if (ptc_num < 0) {
232  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n",
233  inode, rr_type, ptc_num);
234  exit(1);
235  }
236 
237  /* Check that the segment is within the array and such. */
238 
239  switch (rr_type) {
240 
241  case SOURCE:
242  case SINK:
243  case IPIN:
244  case OPIN:
245  /* This is used later as well */
246  type = grid[xlow][ylow].type;
247 
248  if (type == NULL) {
249  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d (type %d) is at an illegal clb location (%d, %d).\n",
250  inode, rr_type, xlow, ylow);
251  exit(1);
252  }
253  if (xlow != xhigh || ylow != (yhigh - type->height + 1)) {
254  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d (type %d) has endpoints (%d,%d) and (%d,%d)\n",
255  inode, rr_type, xlow, ylow, xhigh, yhigh);
256  exit(1);
257  }
258  break;
259 
260  case CHANX:
261  if (xlow < 1 || xhigh > nx || yhigh > ny || yhigh != ylow) {
262  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: CHANX out of range for endpoints (%d,%d) and (%d,%d)\n",
263  xlow, ylow, xhigh, yhigh);
264  exit(1);
265  }
266  if (route_type == GLOBAL && xlow != xhigh) {
267  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d spans multiple channel segments (not allowed for global routing).\n",
268  inode);
269  exit(1);
270  }
271  break;
272 
273  case CHANY:
274  if (xhigh > nx || ylow < 1 || yhigh > ny || xlow != xhigh) {
275  vpr_printf(TIO_MESSAGE_ERROR, "Error in check_node: CHANY out of range for endpoints (%d,%d) and (%d,%d)\n",
276  xlow, ylow, xhigh, yhigh);
277  exit(1);
278  }
279  if (route_type == GLOBAL && ylow != yhigh) {
280  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d spans multiple channel segments (not allowed for global routing).\n",
281  inode);
282  exit(1);
283  }
284  break;
285 
286  default:
287  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: Unexpected segment type: %d\n", rr_type);
288  exit(1);
289  }
290 
291  /* Check that it's capacities and such make sense. */
292 
293  switch (rr_type) {
294 
295  case SOURCE:
296 
297  if (ptc_num >= type->num_class
298  || type->class_inf[ptc_num].type != DRIVER) {
299  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n",
300  inode, rr_type, ptc_num);
301  exit(1);
302  }
303  if (type->class_inf[ptc_num].num_pins != capacity) {
304  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a capacity of %d.\n",
305  inode, rr_type, capacity);
306  exit(1);
307  }
308 
309  break;
310 
311  case SINK:
312 
313  if (ptc_num >= type->num_class
314  || type->class_inf[ptc_num].type != RECEIVER) {
315  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n",
316  inode, rr_type, ptc_num);
317  exit(1);
318  }
319  if (type->class_inf[ptc_num].num_pins != capacity) {
320  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n",
321  inode, rr_type, capacity);
322  exit(1);
323  }
324  break;
325 
326  case OPIN:
327 
328  if (ptc_num >= type->num_pins
329  || type->class_inf[type->pin_class[ptc_num]].type != DRIVER) {
330  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n",
331  inode, rr_type, ptc_num);
332  exit(1);
333  }
334 
335  if (capacity != 1) {
336  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n",
337  inode, rr_type, capacity);
338  exit(1);
339  }
340  break;
341 
342  case IPIN:
343  if (ptc_num >= type->num_pins
344  || type->class_inf[type->pin_class[ptc_num]].type != RECEIVER) {
345  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n",
346  inode, rr_type, ptc_num);
347  exit(1);
348  }
349  if (capacity != 1) {
350  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n",
351  inode, rr_type, capacity);
352  exit(1);
353  }
354  break;
355 
356  case CHANX:
357  if (route_type == DETAILED) {
358  nodes_per_chan = chan_width_x[ylow];
359  tracks_per_node = 1;
360  } else {
361  nodes_per_chan = 1;
362  tracks_per_node = chan_width_x[ylow];
363  }
364 
365  if (ptc_num >= nodes_per_chan) {
366  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a ptc_num of %d.\n",
367  inode, rr_type, ptc_num);
368  exit(1);
369  }
370 
371  if (capacity != tracks_per_node) {
372  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n",
373  inode, rr_type, capacity);
374  exit(1);
375  }
376  break;
377 
378  case CHANY:
379  if (route_type == DETAILED) {
380  nodes_per_chan = chan_width_y[xlow];
381  tracks_per_node = 1;
382  } else {
383  nodes_per_chan = 1;
384  tracks_per_node = chan_width_y[xlow];
385  }
386 
387  if (ptc_num >= nodes_per_chan) {
388  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a ptc_num of %d.\n",
389  inode, rr_type, ptc_num);
390  exit(1);
391  }
392 
393  if (capacity != tracks_per_node) {
394  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n",
395  inode, rr_type, capacity);
396  exit(1);
397  }
398  break;
399 
400  default:
401  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: Unexpected segment type: %d\n", rr_type);
402  exit(1);
403 
404  }
405 
406  /* Check that the number of (out) edges is reasonable. */
407  num_edges = rr_node[inode].num_edges;
408 
409  if (rr_type != SINK && rr_type != IPIN) {
410  if (num_edges <= 0) {
411  /* Just a warning, since a very poorly routable rr-graph could have nodes with no edges. *
412  * If such a node was ever used in a final routing (not just in an rr_graph), other *
413  * error checks in check_routing will catch it. */
414  vpr_printf(TIO_MESSAGE_WARNING, "in check_node: node %d has no edges.\n", inode);
415  }
416  }
417 
418  else if (rr_type == SINK) { /* SINK -- remove this check if feedthroughs allowed */
419  if (num_edges != 0) {
420  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d is a sink, but has %d edges.\n",
421  inode, num_edges);
422  exit(1);
423  }
424  }
425 
426  /* Check that the capacitance, resistance and cost_index are reasonable. */
427 
428  C = rr_node[inode].C;
429  R = rr_node[inode].R;
430 
431  if (rr_type == CHANX || rr_type == CHANY) {
432  if (C < 0. || R < 0.) {
433  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d of type %d has R = %g and C = %g.\n",
434  inode, rr_type, R, C);
435  exit(1);
436  }
437  }
438 
439  else {
440  if (C != 0. || R != 0.) {
441  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d of type %d has R = %g and C = %g.\n",
442  inode, rr_type, R, C);
443  exit(1);
444  }
445  }
446 
447  cost_index = rr_node[inode].cost_index;
448  if (cost_index < 0 || cost_index >= num_rr_indexed_data) {
449  vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d cost index (%d) is out of range.\n",
450  inode, cost_index);
451  exit(1);
452  }
453 }
454 
455 static void check_pass_transistors(int from_node) {
456 
457  /* This routine checks that all pass transistors in the routing truly are *
458  * bidirectional. It may be a slow check, so don't use it all the time. */
459 
460  int from_edge, to_node, to_edge, from_num_edges, to_num_edges;
461  t_rr_type from_rr_type, to_rr_type;
462  short from_switch_type;
463  boolean trans_matched;
464 
465  from_rr_type = rr_node[from_node].type;
466  if (from_rr_type != CHANX && from_rr_type != CHANY)
467  return;
468 
469  from_num_edges = rr_node[from_node].num_edges;
470 
471  for (from_edge = 0; from_edge < from_num_edges; from_edge++) {
472  to_node = rr_node[from_node].edges[from_edge];
473  to_rr_type = rr_node[to_node].type;
474 
475  if (to_rr_type != CHANX && to_rr_type != CHANY)
476  continue;
477 
478  from_switch_type = rr_node[from_node].switches[from_edge];
479 
480  if (switch_inf[from_switch_type].buffered)
481  continue;
482 
483  /* We know that we have a pass transitor from from_node to to_node. Now *
484  * check that there is a corresponding edge from to_node back to *
485  * from_node. */
486 
487  to_num_edges = rr_node[to_node].num_edges;
488  trans_matched = FALSE;
489 
490  for (to_edge = 0; to_edge < to_num_edges; to_edge++) {
491  if (rr_node[to_node].edges[to_edge] == from_node
492  && rr_node[to_node].switches[to_edge] == from_switch_type) {
493  trans_matched = TRUE;
494  break;
495  }
496  }
497 
498  if (trans_matched == FALSE) {
499  vpr_printf(TIO_MESSAGE_ERROR, "in check_pass_transistors:\n");
500  vpr_printf(TIO_MESSAGE_ERROR, "connection from node %d to node %d uses a pass transistor (switch type %d)\n",
501  from_node, to_node, from_switch_type);
502  vpr_printf(TIO_MESSAGE_ERROR, "but there is no corresponding pass transistor edge in the other direction.\n");
503  exit(1);
504  }
505 
506  } /* End for all from_node edges */
507 }
t_type_ptr type
Definition: vpr_types.h:522
static void check_pass_transistors(int from_node)
short xhigh
Definition: vpr_types.h:891
short num_edges
Definition: vpr_types.h:901
float R
Definition: vpr_types.h:906
short cost_index
Definition: vpr_types.h:897
int * edges
Definition: vpr_types.h:903
#define PTRANS_FLAG
t_rr_node * rr_node
Definition: globals.c:70
short ptc_num
Definition: vpr_types.h:895
struct s_class * class_inf
boolean
Definition: util.h:11
short ylow
Definition: vpr_types.h:892
float C
Definition: vpr_types.h:907
enum e_graph_type t_graph_type
Definition: rr_graph.h:11
int num_rr_indexed_data
Definition: globals.c:73
int * chan_width_x
Definition: globals.c:56
void check_rr_graph(INP t_graph_type graph_type, INP t_type_ptr types, INP int L_nx, INP int L_ny, INP int nodes_per_chan, INP int Fs, INP int num_seg_types, INP int num_switches, INP t_segment_inf *segment_inf, INP int global_route_switch, INP int delayless_switch, INP int wire_to_ipin_switch, t_seg_details *seg_details, int **Fc_in, int **Fc_out, int *****opin_to_track_map, int *****ipin_to_track_map, t_ivec ****track_to_ipin_lookup, t_ivec ***switch_block_conn, boolean *perturb_ipins)
void * my_calloc(size_t nelem, size_t size)
Definition: util.c:132
void check_node(int inode, enum e_route_type route_type)
int * chan_width_y
Definition: globals.c:57
Definition: util.h:12
#define INP
Definition: util.h:19
int num_rr_nodes
Definition: globals.c:69
int nx
Definition: globals.c:46
struct s_switch_inf * switch_inf
Definition: globals.c:83
short capacity
Definition: vpr_types.h:899
struct s_grid_tile ** grid
Definition: globals.c:59
Definition: util.h:47
short yhigh
Definition: vpr_types.h:893
enum e_rr_type t_rr_type
short * switches
Definition: vpr_types.h:904
#define BUF_FLAG
Definition: check_rr_graph.c:9
short xlow
Definition: vpr_types.h:890
enum e_pin_type type
e_route_type
Definition: vpr_types.h:682
boolean * is_global_pin
int ny
Definition: globals.c:47
messagelogger vpr_printf
Definition: util.c:17
#define BUF_AND_PTRANS_FLAG
t_rr_type type
Definition: vpr_types.h:902
Definition: util.h:12
static boolean rr_node_is_global_clb_ipin(int inode)