VPR-7.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
check_netlist.c
Go to the documentation of this file.
1 /* TODO: Consider deleting this file altogether. Many netlist checks now done during parsing. Also, the checks here are too strict. For example, we may actually want to allow mixing of local/global signals */
2 
3 #include <stdio.h>
4 #include <string.h>
5 
6 #include "util.h"
7 #include "vpr_types.h"
8 #include "globals.h"
9 #include "hash.h"
10 #include "vpr_utils.h"
11 #include "check_netlist.h"
12 #include "assert.h"
13 #include "read_xml_arch_file.h"
14 
15 #define ERROR_THRESHOLD 100
16 
17 /**************** Subroutines local to this module **************************/
18 
19 static int check_connections_to_global_clb_pins(int inet);
20 
21 static int check_for_duplicated_names(void);
22 
23 static int check_clb_conn(int iblk, int num_conn);
24 
25 static int check_clb_internal_nets(int iblk);
26 
27 static int check_subblock_internal_nets(int iblk, int isub);
28 
29 static int get_num_conn(int bnum);
30 
31 static int check_subblocks(int iblk);
32 
33 static int check_primitives(int iblk, int isub);
34 
35 /*********************** Subroutine definitions *****************************/
36 
37 void check_netlist() {
38  int i, error, num_conn;
39  struct s_hash **net_hash_table, *h_net_ptr;
40 
41  /* TODO: Remove the following the function calls after these functions have
42  been fleshed and are legitimately used in the code!!! They are called here so that
43  the compiler will not throw an error for an unused function */
44 
45  int unused_var;
46  unused_var = check_subblock_internal_nets(0, 0);
47  unused_var = check_primitives(0, 0);
48  if (unused_var)
49  vpr_printf(TIO_MESSAGE_INFO, "Please go to the check_netlist() function in check_netlist.c and remove the first section as needed.");
50 
51  /* This routine checks that the netlist makes sense */
52 
53  net_hash_table = alloc_hash_table();
54 
55  error = 0;
56 
57  /* Check that nets fanout and have a driver. */
58  for (i = 0; i < num_nets; i++) {
59  h_net_ptr = insert_in_hash_table(net_hash_table, clb_net[i].name, i);
60  if (h_net_ptr->count != 1) {
61  vpr_printf(TIO_MESSAGE_ERROR, "Net %s has multiple drivers.\n", clb_net[i].name);
62  error++;
63  }
65  if (error >= ERROR_THRESHOLD) {
66  vpr_printf(TIO_MESSAGE_ERROR, "Too many errors in netlist, exiting.\n");
67  }
68  }
69  free_hash_table(net_hash_table);
70 
71  /* Check that each block makes sense. */
72  for (i = 0; i < num_blocks; i++) {
73  num_conn = get_num_conn(i);
74  error += check_clb_conn(i, num_conn);
75  error += check_clb_internal_nets(i);
76  error += check_subblocks(i);
77  if (error >= ERROR_THRESHOLD) {
78  vpr_printf(TIO_MESSAGE_ERROR, "Too many errors in netlist, exiting.\n");
79  exit(1);
80  }
81  }
82 
83  error += check_for_duplicated_names();
84 
85  if (error != 0) {
86  vpr_printf(TIO_MESSAGE_ERROR, "Found %d fatal Errors in the input netlist.\n", error);
87  exit(1);
88  }
89 
90  /* HACK: Jason Luu January 17, 2011 Do not route common constants gnd and vcc
91  Todo: Need to make architecture driven.
92  */
93  for (i = 0; i < num_nets; i++) {
94  if (strcmp(clb_net[i].name, "vcc") == 0) {
95  clb_net[i].is_global = TRUE;
96  } else if (strcmp(clb_net[i].name, "gnd") == 0) {
97  clb_net[i].is_global = TRUE;
98  }
99  }
100 }
101 
103 
104  /* Checks that a global net (inet) connects only to global CLB input pins *
105  * and that non-global nets never connects to a global CLB pin. Either *
106  * global or non-global nets are allowed to connect to pads. */
107 
108  int ipin, num_pins, iblk, node_block_pin, error;
109 
110  num_pins = (clb_net[inet].num_sinks + 1);
111  error = 0;
112 
113  /* For now global signals can be driven by an I/O pad or any CLB output *
114  * although a CLB output generates a warning. I could make a global CLB *
115  * output pin type to allow people to make architectures that didn't have *
116  * this warning. */
117 
118  for (ipin = 0; ipin < num_pins; ipin++) {
119  iblk = clb_net[inet].node_block[ipin];
120 
121  node_block_pin = clb_net[inet].node_block_pin[ipin];
122 
123  if (block[iblk].type->is_global_pin[node_block_pin]
124  != clb_net[inet].is_global && block[iblk].type != IO_TYPE) {
125 
126  /* Allow a CLB output pin to drive a global net (warning only). */
127 
128  if (ipin == 0 && clb_net[inet].is_global) {
129  vpr_printf(TIO_MESSAGE_WARNING, "in check_connections_to_global_clb_pins:\n");
130  vpr_printf(TIO_MESSAGE_WARNING, "\tnet #%d (%s) is driven by CLB output pin (#%d) on block #%d (%s).\n",
131  inet, clb_net[inet].name, node_block_pin, iblk, block[iblk].name);
132  } else { /* Otherwise -> Error */
133  vpr_printf(TIO_MESSAGE_ERROR, "in check_connections_to_global_clb_pins:\n");
134  vpr_printf(TIO_MESSAGE_ERROR, "\tpin %d on net #%d (%s) connects to CLB input pin (#%d) on block #%d (%s).\n",
135  ipin, inet, clb_net[inet].name, node_block_pin, iblk, block[iblk].name);
136  error++;
137  }
138 
139  if (clb_net[inet].is_global)
140  vpr_printf(TIO_MESSAGE_INFO, "Net is global, but CLB pin is not.\n");
141  else
142  vpr_printf(TIO_MESSAGE_INFO, "CLB pin is global, but net is not.\n");
143  vpr_printf(TIO_MESSAGE_INFO, "\n");
144  }
145  } /* End for all pins */
146 
147  return (error);
148 }
149 
150 static int check_clb_conn(int iblk, int num_conn) {
151 
152  /* Checks that the connections into and out of the clb make sense. */
153 
154  int iclass, ipin, error;
155  t_type_ptr type;
156 
157  error = 0;
158  type = block[iblk].type;
159 
160  if (type == IO_TYPE) {
161  /*
162  //This triggers incorrectly if other blocks (e.g. I/O buffers) are included in the iopads
163  if (num_conn != 1) {
164  vpr_printf(TIO_MESSAGE_ERROR, "IO blk #%d (%s) has %d pins.\n",
165  iblk, block[iblk].name, num_conn);
166  error++;
167  }
168  */
169  } else if (num_conn < 2) {
170  vpr_printf(TIO_MESSAGE_WARNING, "Logic block #%d (%s) has only %d pin.\n",
171  iblk, block[iblk].name, num_conn);
172 
173  /* Allow the case where we have only one OUTPUT pin connected to continue. *
174  * This is used sometimes as a constant generator for a primary output, *
175  * but I will still warn the user. If the only pin connected is an input, *
176  * abort. */
177 
178  if (num_conn == 1) {
179  for (ipin = 0; ipin < type->num_pins; ipin++) {
180  if (block[iblk].nets[ipin] != OPEN) {
181  iclass = type->pin_class[ipin];
182 
183  if (type->class_inf[iclass].type != DRIVER) {
184  vpr_printf(TIO_MESSAGE_INFO, "Pin is an input -- this whole block is hanging logic that should be swept in logic synthesis.\n");
185  vpr_printf(TIO_MESSAGE_INFO, "\tNon-fatal, but check this.\n");
186  } else {
187  vpr_printf(TIO_MESSAGE_INFO, "Pin is an output -- may be a constant generator.\n");
188  vpr_printf(TIO_MESSAGE_INFO, "\tNon-fatal, but check this.\n");
189  }
190 
191  break;
192  }
193  }
194  }
195  }
196 
197  /* This case should already have been flagged as an error -- this is *
198  * just a redundant double check. */
199 
200  if (num_conn > type->num_pins) {
201  vpr_printf(TIO_MESSAGE_ERROR, "logic block #%d with output %s has %d pins.\n",
202  iblk, block[iblk].name, num_conn);
203  error++;
204  }
205 
206  return (error);
207 }
208 
209 static int check_clb_internal_nets(int iblk) {
210  /** TODO:
211  * Check if the internal CLB nets makes sense and are connected properly
212  * Consists of 3 main loops
213  * 1. a) Check name uniqueness
214  b) Check all net connections are to CLB pins or subblock pins and that they match the net examined
215  * 2. Check all connected CLB pins are connected to valid internal nets
216  * 3. Check all connected subblock pins are connected to valid internal nets and that these match the net indexes
217  */
218  return 0;
219 }
220 
221 static int check_subblock_internal_nets(int iblk, int isub) {
222  /**
223  * TODO
224  * Check if the internal CLB nets makes sense and are connected properly
225  * Consists of 3 main checks
226  * 1. a) Check name uniqueness
227  b) Check all net connections are to CLB pins or subblock pins and that they match the net examined
228  * 2. Check all connected CLB pins are connected to valid internal nets
229  * 3. Check all connected subblock pins are connected to valid internal nets and that these match the net indexes
230  */
231  return 0;
232 }
233 
234 static int check_subblocks(int iblk) {
235  /* TODO */
236  /* This routine checks the subblocks of iblk (which must be a CLB). It *
237  * returns the number of errors found. */
238  return 0;
239 }
240 
241 static int check_primitives(int iblk, int isub) {
242 
243  /* TODO:
244  This routine checks the subblocks of iblk (which must be a CLB). It *
245  * returns the number of errors found. */
246  return 0;
247 
248 }
249 
250 static int check_for_duplicated_names(void) {
251 #if 0
252  int iblk, isub, iprim, error;
253  int clb_count, sub_count, prim_count;
254  struct s_hash **clb_hash_table, *clb_h_ptr;
255  struct s_hash **sub_hash_table, *sub_h_ptr;
256  struct s_hash **prim_hash_table, *prim_h_ptr;
257 
258  clb_hash_table = alloc_hash_table();
259  sub_hash_table = alloc_hash_table();
260  prim_hash_table = alloc_hash_table();
261 
262  error = clb_count = sub_count = prim_count = 0;
263 
264  for (iblk = 0; iblk < num_blocks; iblk++)
265  {
266  clb_h_ptr = insert_in_hash_table(clb_hash_table, block[iblk].name, clb_count);
267  if (clb_h_ptr->count > 1) {
268  vpr_printf(TIO_MESSAGE_ERROR, "Block %s has duplicated name.\n",
269  block[iblk].name);
270  error++;
271  } else {
272  clb_count++;
273  }
274  for (isub = 0; isub < block[iblk].num_subblocks; isub++)
275  {
276  sub_h_ptr = insert_in_hash_table(sub_hash_table, block[iblk].subblocks[isub].name, sub_count);
277  if (sub_h_ptr->count > 1) {
278  vpr_printf(TIO_MESSAGE_ERROR, "Subblock %s has duplicated name.\n",
279  block[iblk].subblocks[isub].name);
280  error++;
281  } else {
282  sub_count++;
283  }
284  for (iprim = 0; iprim < block[iblk].subblocks[isub].num_primitives; iprim++)
285  {
286  prim_h_ptr = insert_in_hash_table(prim_hash_table, block[iblk].subblocks[isub].primitives[iprim].name, prim_count);
287  if (prim_h_ptr->count > 1) {
288  vpr_printf(TIO_MESSAGE_ERROR, "Primitive %s has duplicated name.\n",
289  block[iblk].subblocks[isub].primitives[iprim].name);
290  error++;
291  } else {
292  prim_count++;
293  }
294  }
295  }
296  }
297  return error;
298 #endif
299  return 0;
300 }
301 
302 static int get_num_conn(int bnum) {
303 
304  /* This routine returns the number of connections to a block. */
305 
306  int i, num_conn;
307  t_type_ptr type;
308 
309  type = block[bnum].type;
310 
311  num_conn = 0;
312 
313  for (i = 0; i < type->num_pins; i++) {
314  if (block[bnum].nets[i] != OPEN)
315  num_conn++;
316  }
317 
318  return (num_conn);
319 }
320 
int * node_block_pin
Definition: vpr_types.h:509
struct s_hash ** alloc_hash_table(void)
Definition: hash.c:7
int count
Definition: hash.h:6
struct s_class * class_inf
static int check_subblock_internal_nets(int iblk, int isub)
void check_netlist()
Definition: check_netlist.c:37
char * name
Definition: hash.h:4
int num_nets
Definition: globals.c:27
int * node_block
Definition: vpr_types.h:507
t_type_ptr type
Definition: vpr_types.h:561
int num_blocks
Definition: globals.c:30
#define ERROR_THRESHOLD
Definition: check_netlist.c:15
void free_hash_table(struct s_hash **hash_table)
Definition: hash.c:18
boolean * is_global
struct s_block * block
Definition: globals.c:31
struct s_net * clb_net
Definition: globals.c:28
boolean is_global
Definition: vpr_types.h:510
t_type_ptr IO_TYPE
Definition: globals.c:40
static int check_subblocks(int iblk)
Definition: slre.c:50
static int check_for_duplicated_names(void)
static int check_connections_to_global_clb_pins(int inet)
enum e_pin_type type
static int get_num_conn(int bnum)
static int check_primitives(int iblk, int isub)
messagelogger vpr_printf
Definition: util.c:17
int num_sinks
Definition: vpr_types.h:506
struct s_hash * insert_in_hash_table(struct s_hash **hash_table, char *name, int next_free_index)
Definition: hash.c:76
static int check_clb_internal_nets(int iblk)
Definition: hash.h:3
Definition: util.h:12
static int check_clb_conn(int iblk, int num_conn)