VPR-7.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
read_netlist.c
Go to the documentation of this file.
1 /**
2  * Author: Jason Luu
3  * Date: May 2009
4  *
5  * Read a circuit netlist in XML format and populate the netlist data structures for VPR
6  */
7 
8 #include <stdio.h>
9 #include <string.h>
10 #include <assert.h>
11 #include "util.h"
12 #include "hash.h"
13 #include "vpr_types.h"
14 #include "vpr_utils.h"
15 #include "ReadLine.h"
16 #include "globals.h"
17 #include "ezxml.h"
18 #include "read_xml_util.h"
19 #include "read_netlist.h"
20 #include "pb_type_graph.h"
21 #include "cluster_legality.h"
22 #include "token.h"
23 #include "rr_graph.h"
24 
25 static void processPorts(INOUTP ezxml_t Parent, INOUTP t_pb* pb,
26  INOUTP t_rr_node *rr_graph, INOUTP t_pb** rr_node_to_pb_mapping, INP struct s_hash **vpack_net_hash);
27 
28 static void processPb(INOUTP ezxml_t Parent, INOUTP t_pb* pb,
29  INOUTP t_rr_node *rr_graph, INOUTP t_pb **rr_node_to_pb_mapping, INOUTP int *num_primitives,
30  INP struct s_hash **vpack_net_hash, INP struct s_hash **logical_block_hash, INP int cb_index);
31 
32 static void processComplexBlock(INOUTP ezxml_t Parent, INOUTP t_block *cb,
33  INP int index, INOUTP int *num_primitives, INP const t_arch *arch, INP struct s_hash **vpack_net_hash, INP struct s_hash **logical_block_hash);
34 static struct s_net *alloc_and_init_netlist_from_hash(INP int ncount,
35  INOUTP struct s_hash **nhash);
36 
37 static int add_net_to_hash(INOUTP struct s_hash **nhash, INP char *net_name,
38  INOUTP int *ncount);
39 
40 static void load_external_nets_and_cb(INP int L_num_blocks,
41  INP struct s_block block_list[], INP int ncount,
42  INP struct s_net nlist[], OUTP int *ext_ncount,
43  OUTP struct s_net **ext_nets, INP char **circuit_clocks);
44 
45 static void load_internal_cb_nets(INOUTP t_pb *top_level,
46  INP t_pb_graph_node *pb_graph_node, INOUTP t_rr_node *rr_graph,
47  INOUTP int * curr_net);
48 
49 static void alloc_internal_cb_nets(INOUTP t_pb *top_level,
50  INP t_pb_graph_node *pb_graph_node, INOUTP t_rr_node *rr_graph,
51  INP int pass);
52 
53 static void load_internal_cb_rr_graph_net_nums(INP t_rr_node * cur_rr_node,
54  INP t_rr_node * rr_graph, INOUTP struct s_net * nets,
55  INOUTP int * curr_net, INOUTP int * curr_sink);
56 
57 static void mark_constant_generators(INP int L_num_blocks,
58  INP struct s_block block_list[], INP int ncount,
59  INOUTP struct s_net nlist[]);
60 
61 static void mark_constant_generators_rec(INP t_pb *pb, INP t_rr_node *rr_graph,
62  INOUTP struct s_net nlist[]);
63 
64 /**
65  * Initializes the block_list with info from a netlist
66  * net_file - Name of the netlist file to read
67  * num_blocks - number of CLBs in netlist
68  * block_list - array of blocks in netlist [0..num_blocks - 1]
69  * num_nets - number of nets in netlist
70  * net_list - nets in netlist [0..num_nets - 1]
71  */
72 void read_netlist(INP const char *net_file, INP const t_arch *arch,
73  OUTP int *L_num_blocks, OUTP struct s_block *block_list[],
74  OUTP int *L_num_nets, OUTP struct s_net *net_list[]) {
75  ezxml_t Cur, Prev, Top;
76  int i;
77  const char *Prop;
78  int bcount;
79  struct s_block *blist;
80  int ext_ncount;
81  struct s_net *ext_nlist;
82  struct s_hash **vpack_net_hash, **logical_block_hash, *temp_hash;
83  char **circuit_inputs, **circuit_outputs, **circuit_clocks;
84  int Count, Len;
85 
86  int num_primitives = 0;
87 
88  /* Parse the file */
89  vpr_printf(TIO_MESSAGE_INFO, "Begin parsing packed FPGA netlist file.\n");
90  Top = ezxml_parse_file(net_file);
91  if (NULL == Top) {
92  vpr_printf(TIO_MESSAGE_ERROR, "Unable to load netlist file '%s'.\n", net_file);
93  exit(1);
94  }
95  vpr_printf(TIO_MESSAGE_INFO, "Finished parsing packed FPGA netlist file.\n");
96 
97  /* Root node should be block */
98  CheckElement(Top, "block");
99 
100  /* Check top-level netlist attributes */
101  Prop = FindProperty(Top, "name", TRUE);
102  vpr_printf(TIO_MESSAGE_INFO, "Netlist generated from file '%s'.\n", Prop);
103  ezxml_set_attr(Top, "name", NULL);
104 
105  Prop = FindProperty(Top, "instance", TRUE);
106  if (strcmp(Prop, "FPGA_packed_netlist[0]") != 0) {
107  vpr_printf(TIO_MESSAGE_ERROR, "[Line %d] Expected instance to be \"FPGA_packed_netlist[0]\", found %s.",
108  Top->line, Prop);
109  exit(1);
110  }
111  ezxml_set_attr(Top, "instance", NULL);
112 
113  /* Parse top-level netlist I/Os */
114  Cur = FindElement(Top, "inputs", TRUE);
115  circuit_inputs = GetNodeTokens(Cur);
116  FreeNode(Cur);
117  Cur = FindElement(Top, "outputs", TRUE);
118  circuit_outputs = GetNodeTokens(Cur);
119  FreeNode(Cur);
120 
121  Cur = FindElement(Top, "clocks", TRUE);
122  CountTokensInString(Cur->txt, &Count, &Len);
123  if (Count > 0) {
124  circuit_clocks = GetNodeTokens(Cur);
125  } else {
126  circuit_clocks = NULL;
127  }
128  FreeNode(Cur);
129 
130  /* Parse all CLB blocks and all nets*/
131  bcount = CountChildren(Top, "block", 1);
132  blist = (struct s_block *) my_calloc(bcount, sizeof(t_block));
133 
134  /* create quick hash look up for vpack_net and logical_block
135  Also reset logical block data structure for pb
136  */
137  vpack_net_hash = alloc_hash_table();
138  logical_block_hash = alloc_hash_table();
139  for (i = 0; i < num_logical_nets; i++) {
140  temp_hash = insert_in_hash_table(vpack_net_hash, vpack_net[i].name, i);
141  assert(temp_hash->count == 1);
142  }
143  for (i = 0; i < num_logical_blocks; i++) {
144  temp_hash = insert_in_hash_table(logical_block_hash, logical_block[i].name, i);
145  logical_block[i].pb = NULL;
146  assert(temp_hash->count == 1);
147  }
148 
149  /* Prcoess netlist */
150 
151  Cur = Top->child;
152  i = 0;
153  while (Cur) {
154  if (0 == strcmp(Cur->name, "block")) {
155  CheckElement(Cur, "block");
156  processComplexBlock(Cur, blist, i, &num_primitives, arch, vpack_net_hash, logical_block_hash);
157  Prev = Cur;
158  Cur = Cur->next;
159  FreeNode(Prev);
160  i++;
161  } else {
162  Cur = Cur->next;
163  }
164  }
165  assert(i == bcount);
166  assert(num_primitives == num_logical_blocks);
167 
168  /* Error check */
169  for (i = 0; i < num_logical_blocks; i++) {
170  if (logical_block[i].pb == NULL) {
171  vpr_printf(TIO_MESSAGE_ERROR, ".blif file and .net file do not match, .net file missing atom %s.\n",
172  logical_block[i].name);
173  exit(1);
174  }
175  }
176  /* TODO: Add additional check to make sure net connections match */
177 
178 
179  mark_constant_generators(bcount, blist, num_logical_nets, vpack_net);
180  load_external_nets_and_cb(bcount, blist, num_logical_nets, vpack_net, &ext_ncount,
181  &ext_nlist, circuit_clocks);
182 
183  /* TODO: create this function later
184  check_top_IO_matches_IO_blocks(circuit_inputs, circuit_outputs, circuit_clocks, blist, bcount);
185  */
186 
187  FreeTokens(&circuit_inputs);
188  FreeTokens(&circuit_outputs);
189  if (circuit_clocks)
190  FreeTokens(&circuit_clocks);
191  FreeNode(Top);
192 
193  /* load mapping between external nets and all nets */
194  /* jluu TODO: Should use local variables here then assign to globals later, clean up later */
195  clb_to_vpack_net_mapping = (int *) my_malloc(ext_ncount * sizeof(int));
196  vpack_to_clb_net_mapping = (int *) my_malloc(num_logical_nets * sizeof(int));
197  for (i = 0; i < num_logical_nets; i++) {
199  }
200 
201  for (i = 0; i < ext_ncount; i++) {
202  temp_hash = get_hash_entry(vpack_net_hash, ext_nlist[i].name);
203  assert(temp_hash != NULL);
204  clb_to_vpack_net_mapping[i] = temp_hash->index;
205  vpack_to_clb_net_mapping[temp_hash->index] = i;
206  }
207 
208  /* Return blocks and nets */
209  *L_num_blocks = bcount;
210  *block_list = blist;
211  *L_num_nets = ext_ncount;
212  *net_list = ext_nlist;
213 
214  free_hash_table(logical_block_hash);
215  free_hash_table(vpack_net_hash);
216 }
217 
218 /**
219  * XML parser to populate CLB info and to update nets with the nets of this CLB
220  * Parent - XML tag for this CLB
221  * clb - Array of CLBs in the netlist
222  * index - index of the CLB to allocate and load information into
223  * vpack_net_hash - hashtable of all nets in blif netlist
224  * logical_block_hash - hashtable of all atoms in blif netlist
225  */
227  INP int index, INOUTP int *num_primitives, INP const t_arch *arch, INP struct s_hash **vpack_net_hash, INP struct s_hash **logical_block_hash)
228  {
229 
230  const char *Prop;
231  boolean found;
232  int num_tokens = 0;
233  t_token *tokens;
234  int i;
235  const t_pb_type * pb_type = NULL;
236 
237  /* parse cb attributes */
238  cb[index].pb = (t_pb*)my_calloc(1, sizeof(t_pb));
239 
240  Prop = FindProperty(Parent, "name", TRUE);
241  cb[index].name = my_strdup(Prop);
242  cb[index].pb->name = my_strdup(Prop);
243  ezxml_set_attr(Parent, "name", NULL);
244 
245  Prop = FindProperty(Parent, "instance", TRUE);
246  tokens = GetTokensFromString(Prop, &num_tokens);
247  ezxml_set_attr(Parent, "instance", NULL);
248  if (num_tokens != 4 || tokens[0].type != TOKEN_STRING
249  || tokens[1].type != TOKEN_OPEN_SQUARE_BRACKET
250  || tokens[2].type != TOKEN_INT
251  || tokens[3].type != TOKEN_CLOSE_SQUARE_BRACKET) {
252  vpr_printf(TIO_MESSAGE_ERROR, "[Line %d] Unknown syntax for instance %s in %s. Expected pb_type[instance_number].\n",
253  Parent->line, Prop, Parent->name);
254  exit(1);
255  }
256  assert(my_atoi(tokens[2].data) == index);
257  found = FALSE;
258  for (i = 0; i < num_types; i++) {
259  if (strcmp(type_descriptors[i].name, tokens[0].data) == 0) {
260  cb[index].type = &type_descriptors[i];
261  pb_type = cb[index].type->pb_type;
262  found = TRUE;
263  break;
264  }
265  }
266  if (!found) {
267  vpr_printf(TIO_MESSAGE_ERROR, "[Line %d] Unknown cb type %s for cb %s #%d.\n",
268  Parent->line, Prop, cb[index].name, index);
269  exit(1);
270  }
271 
272  /* Parse all pbs and CB internal nets*/
273  cb[index].pb->logical_block = OPEN;
274  cb[index].pb->pb_graph_node = cb[index].type->pb_graph_head;
275  num_rr_nodes = cb[index].pb->pb_graph_node->total_pb_pins;
276  rr_node = (t_rr_node*)my_calloc((num_rr_nodes * 2) + cb[index].type->pb_type->num_input_pins
277  + cb[index].type->pb_type->num_output_pins + cb[index].type->pb_type->num_clock_pins,
278  sizeof(t_rr_node));
280  0);
281  cb[index].pb->rr_node_to_pb_mapping = (t_pb **)my_calloc(cb[index].type->pb_graph_head->total_pb_pins, sizeof(t_pb *));
282  cb[index].pb->rr_graph = rr_node;
283 
284  Prop = FindProperty(Parent, "mode", TRUE);
285  ezxml_set_attr(Parent, "mode", NULL);
286 
287  found = FALSE;
288  for (i = 0; i < pb_type->num_modes; i++) {
289  if (strcmp(Prop, pb_type->modes[i].name) == 0) {
290  cb[index].pb->mode = i;
291  found = TRUE;
292  }
293  }
294  if (!found) {
295  vpr_printf(TIO_MESSAGE_ERROR, "[Line %d] Unknown mode %s for cb %s #%d.\n",
296  Parent->line, Prop, cb[index].name, index);
297  exit(1);
298  }
299 
300  processPb(Parent, cb[index].pb, cb[index].pb->rr_graph, cb[index].pb->rr_node_to_pb_mapping, num_primitives, vpack_net_hash, logical_block_hash, index);
301 
302  cb[index].nets = (int *)my_malloc(cb[index].type->num_pins * sizeof(int));
303  for (i = 0; i < cb[index].type->num_pins; i++) {
304  cb[index].nets[i] = OPEN;
305  }
306  alloc_internal_cb_nets(cb[index].pb, cb[index].pb->pb_graph_node,
307  cb[index].pb->rr_graph, 1);
308  alloc_internal_cb_nets(cb[index].pb, cb[index].pb->pb_graph_node,
309  cb[index].pb->rr_graph, 2);
310  i = 0;
311  load_internal_cb_nets(cb[index].pb, cb[index].pb->pb_graph_node,
312  cb[index].pb->rr_graph, &i);
313  freeTokens(tokens, num_tokens);
314 #if 0
315  /* print local nets */
316  for (i = 0; i < cb[index].pb->num_local_nets; i++) {
317  vpr_printf(TIO_MESSAGE_INFO, "local net %s: ", cb[index].pb->name);
318  for (j = 0; j <= cb[index].pb->local_nets[i].num_sinks; j++) {
319  vpr_printf(TIO_MESSAGE_INFO, "%d ", cb[index].pb->local_nets[i].node_block[j]);
320  }
321  vpr_printf(TIO_MESSAGE_INFO, "\n");
322  }
323 #endif
324 }
325 
326 /**
327  * XML parser to populate pb info and to update internal nets of the parent CLB
328  * Parent - XML tag for this pb_type
329  * pb - physical block to use
330  * vpack_net_hash - hashtable of original blif net names and indices
331  * logical_block_hash - hashtable of original blif atom names and indices
332  */
333 static void processPb(INOUTP ezxml_t Parent, INOUTP t_pb* pb,
334  INOUTP t_rr_node *rr_graph, INOUTP t_pb** rr_node_to_pb_mapping, INOUTP int *num_primitives,
335  INP struct s_hash **vpack_net_hash, INP struct s_hash **logical_block_hash, INP int cb_index) {
336  ezxml_t Cur, Prev, lookahead;
337  const char *Prop;
338  const char *instance_type;
339  int i, j, pb_index;
340  boolean found;
341  const t_pb_type *pb_type;
342  t_token *tokens;
343  int num_tokens;
344  struct s_hash *temp_hash;
345 
346  Cur = FindElement(Parent, "inputs", TRUE);
347  processPorts(Cur, pb, rr_graph, rr_node_to_pb_mapping, vpack_net_hash);
348  FreeNode(Cur);
349  Cur = FindElement(Parent, "outputs", TRUE);
350  processPorts(Cur, pb, rr_graph, rr_node_to_pb_mapping, vpack_net_hash);
351  FreeNode(Cur);
352  Cur = FindElement(Parent, "clocks", TRUE);
353  processPorts(Cur, pb, rr_graph, rr_node_to_pb_mapping, vpack_net_hash);
354  FreeNode(Cur);
355 
356  pb_type = pb->pb_graph_node->pb_type;
357  if (pb_type->num_modes == 0) {
358  /* LUT specific optimizations */
359  if (strcmp(pb_type->blif_model, ".names") == 0) {
360  pb->lut_pin_remap = (int*)my_malloc(pb_type->num_input_pins * sizeof(int));
361  for (i = 0; i < pb_type->num_input_pins; i++) {
362  pb->lut_pin_remap[i] = OPEN;
363  }
364  } else {
365  pb->lut_pin_remap = NULL;
366  }
367  temp_hash = get_hash_entry(logical_block_hash, pb->name);
368  if (temp_hash == NULL) {
369  vpr_printf(TIO_MESSAGE_ERROR, ".net file and .blif file do not match, encountered unknown primitive %s in .net file.\n", pb->name);
370  exit(1);
371  }
372  pb->logical_block = temp_hash->index;
373  assert(logical_block[temp_hash->index].pb == NULL);
374  logical_block[temp_hash->index].pb = pb;
375  logical_block[temp_hash->index].clb_index = cb_index;
376  (*num_primitives)++;
377  } else {
378  /* process children of child if exists */
379 
380  pb->child_pbs = (t_pb **)my_calloc(pb_type->modes[pb->mode].num_pb_type_children,
381  sizeof(t_pb*));
382  for (i = 0; i < pb_type->modes[pb->mode].num_pb_type_children; i++) {
383  pb->child_pbs[i] = (t_pb *)my_calloc(
384  pb_type->modes[pb->mode].pb_type_children[i].num_pb,
385  sizeof(t_pb));
386  for (j = 0; j < pb_type->modes[pb->mode].pb_type_children[i].num_pb; j++) {
387  pb->child_pbs[i][j].logical_block = OPEN;
388  }
389  }
390 
391  /* Populate info for each physical block */
392  Cur = Parent->child;
393  while (Cur) {
394  if (0 == strcmp(Cur->name, "block")) {
395  CheckElement(Cur, "block");
396 
397  instance_type = FindProperty(Cur, "instance", TRUE);
398  tokens = GetTokensFromString(instance_type, &num_tokens);
399  ezxml_set_attr(Cur, "instance", NULL);
400  if (num_tokens != 4 || tokens[0].type != TOKEN_STRING
401  || tokens[1].type != TOKEN_OPEN_SQUARE_BRACKET
402  || tokens[2].type != TOKEN_INT
403  || tokens[3].type != TOKEN_CLOSE_SQUARE_BRACKET) {
404  vpr_printf(TIO_MESSAGE_ERROR, "[Line %d] Unknown syntax for instance %s in %s. Expected pb_type[instance_number].\n",
405  Cur->line, instance_type, Cur->name);
406  exit(1);
407  }
408 
409  found = FALSE;
410  pb_index = OPEN;
411  for (i = 0; i < pb_type->modes[pb->mode].num_pb_type_children;
412  i++) {
413  if (strcmp(
414  pb_type->modes[pb->mode].pb_type_children[i].name,
415  tokens[0].data) == 0) {
416  if (my_atoi(tokens[2].data)
417  >= pb_type->modes[pb->mode].pb_type_children[i].num_pb) {
418  vpr_printf(TIO_MESSAGE_ERROR, "[Line %d] Instance number exceeds # of pb available for instance %s in %s.\n",
419  Cur->line, instance_type, Cur->name);
420  exit(1);
421  }
422  pb_index = my_atoi(tokens[2].data);
423  if (pb->child_pbs[i][pb_index].pb_graph_node != NULL) {
424  vpr_printf(TIO_MESSAGE_ERROR, "[Line %d] node is used by two different blocks %s and %s.\n",
425  Cur->line, instance_type,
426  pb->child_pbs[i][pb_index].name);
427  exit(1);
428  }
429  pb->child_pbs[i][pb_index].pb_graph_node =
430  &pb->pb_graph_node->child_pb_graph_nodes[pb->mode][i][pb_index];
431  found = TRUE;
432  break;
433  }
434  }
435  if (!found) {
436  vpr_printf(TIO_MESSAGE_ERROR, "[Line %d] Unknown pb type %s.\n",
437  Cur->line, instance_type);
438  exit(1);
439  }
440 
441  Prop = FindProperty(Cur, "name", TRUE);
442  ezxml_set_attr(Cur, "name", NULL);
443  if (0 != strcmp(Prop, "open")) {
444  pb->child_pbs[i][pb_index].name = my_strdup(Prop);
445 
446  /* Parse all pbs and CB internal nets*/
447  pb->child_pbs[i][pb_index].logical_block = OPEN;
448 
449  Prop = FindProperty(Cur, "mode", FALSE);
450  if (Prop) {
451  ezxml_set_attr(Cur, "mode", NULL);
452  }
453  pb->child_pbs[i][pb_index].mode = 0;
454  found = FALSE;
455  for (j = 0;
456  j
457  < pb->child_pbs[i][pb_index].pb_graph_node->pb_type->num_modes;
458  j++) {
459  if (strcmp(Prop,
460  pb->child_pbs[i][pb_index].pb_graph_node->pb_type->modes[j].name)
461  == 0) {
462  pb->child_pbs[i][pb_index].mode = j;
463  found = TRUE;
464  }
465  }
466  if (!found
467  && pb->child_pbs[i][pb_index].pb_graph_node->pb_type->num_modes
468  != 0) {
469  vpr_printf(TIO_MESSAGE_ERROR, "[Line %d] Unknown mode %s for cb %s #%d.\n",
470  Cur->line, Prop, pb->child_pbs[i][pb_index].name, pb_index);
471  exit(1);
472  }
473  pb->child_pbs[i][pb_index].parent_pb = pb;
474  pb->child_pbs[i][pb_index].rr_graph = pb->rr_graph;
475 
476  processPb(Cur, &pb->child_pbs[i][pb_index], rr_graph, rr_node_to_pb_mapping, num_primitives, vpack_net_hash, logical_block_hash, cb_index);
477  } else {
478  /* physical block has no used primitives but it may have used routing */
479  pb->child_pbs[i][pb_index].name = NULL;
480  pb->child_pbs[i][pb_index].logical_block = OPEN;
481  lookahead = FindElement(Cur, "outputs", FALSE);
482  if (lookahead != NULL) {
483  lookahead = FindFirstElement(lookahead, "port", TRUE);
484  Prop = FindProperty(Cur, "mode", FALSE);
485  if (Prop) {
486  ezxml_set_attr(Cur, "mode", NULL);
487  }
488  pb->child_pbs[i][pb_index].mode = 0;
489  found = FALSE;
490  for (j = 0;
491  j
492  < pb->child_pbs[i][pb_index].pb_graph_node->pb_type->num_modes;
493  j++) {
494  if (strcmp(Prop,
495  pb->child_pbs[i][pb_index].pb_graph_node->pb_type->modes[j].name)
496  == 0) {
497  pb->child_pbs[i][pb_index].mode = j;
498  found = TRUE;
499  }
500  }
501  if (!found
502  && pb->child_pbs[i][pb_index].pb_graph_node->pb_type->num_modes
503  != 0) {
504  vpr_printf(TIO_MESSAGE_ERROR, "[Line %d] Unknown mode %s for cb %s #%d.\n",
505  Cur->line, Prop, pb->child_pbs[i][pb_index].name, pb_index);
506  exit(1);
507  }
508  pb->child_pbs[i][pb_index].parent_pb = pb;
509  pb->child_pbs[i][pb_index].rr_graph = pb->rr_graph;
510  processPb(Cur, &pb->child_pbs[i][pb_index], rr_graph, rr_node_to_pb_mapping, num_primitives, vpack_net_hash, logical_block_hash, cb_index);
511  }
512  }
513  Prev = Cur;
514  Cur = Cur->next;
515  FreeNode(Prev);
516  freeTokens(tokens, num_tokens);
517  } else {
518  Cur = Cur->next;
519  }
520  }
521  }
522 }
523 
524 /**
525  * Allocates memory for nets and loads the name of the net so that it can be identified and loaded with
526  * more complete information later
527  * ncount - number of nets in the hashtable of nets
528  * nhash - hashtable of nets
529  * returns array of nets stored in hashtable
530  */
531 static struct s_net *alloc_and_init_netlist_from_hash(INP int ncount,
532  INOUTP struct s_hash **nhash) {
533  struct s_net *nlist;
534  struct s_hash_iterator hash_iter;
535  struct s_hash *curr_net;
536  int i;
537 
538  nlist = (struct s_net *)my_calloc(ncount, sizeof(struct s_net));
539 
540  hash_iter = start_hash_table_iterator();
541  curr_net = get_next_hash(nhash, &hash_iter);
542  while (curr_net != NULL) {
543  assert(nlist[curr_net->index].name == NULL);
544  nlist[curr_net->index].name = my_strdup(curr_net->name);
545  nlist[curr_net->index].num_sinks = curr_net->count - 1;
546 
547  nlist[curr_net->index].node_block = (int *)my_malloc(
548  curr_net->count * sizeof(int));
549  nlist[curr_net->index].node_block_pin = (int *)my_malloc(
550  curr_net->count * sizeof(int));
551  nlist[curr_net->index].is_global = FALSE;
552  for (i = 0; i < curr_net->count; i++) {
553  nlist[curr_net->index].node_block[i] = OPEN;
554  nlist[curr_net->index].node_block_pin[i] = OPEN;
555  }
556  curr_net = get_next_hash(nhash, &hash_iter);
557  }
558  return nlist;
559 }
560 
561 /**
562  * Adds net to hashtable of nets. If the net is "open", then this is a keyword so do not add it.
563  * If the net already exists, increase the count on that net
564  */
565 static int add_net_to_hash(INOUTP struct s_hash **nhash, INP char *net_name,
566  INOUTP int *ncount) {
567  struct s_hash *hash_value;
568 
569  if (strcmp(net_name, "open") == 0) {
570  return OPEN;
571  }
572 
573  hash_value = insert_in_hash_table(nhash, net_name, *ncount);
574  if (hash_value->count == 1) {
575  assert(*ncount == hash_value->index);
576  (*ncount)++;
577  }
578  return hash_value->index;
579 }
580 
581 static void processPorts(INOUTP ezxml_t Parent, INOUTP t_pb* pb,
582  t_rr_node *rr_graph, INOUTP t_pb** rr_node_to_pb_mapping, INP struct s_hash **vpack_net_hash) {
583 
584  int i, j, in_port, out_port, clock_port, num_tokens;
585  ezxml_t Cur, Prev;
586  const char *Prop;
587  char **pins;
588  char *port_name, *interconnect_name;
589  int rr_node_index;
590  t_pb_graph_pin *** pin_node;
591  int *num_ptrs, num_sets;
592  struct s_hash *temp_hash;
593  boolean found;
594 
595  Cur = Parent->child;
596  while (Cur) {
597  if (0 == strcmp(Cur->name, "port")) {
598  CheckElement(Cur, "port");
599 
600  Prop = FindProperty(Cur, "name", TRUE);
601  ezxml_set_attr(Cur, "name", NULL);
602 
603  in_port = out_port = clock_port = 0;
604  found = FALSE;
605  for (i = 0; i < pb->pb_graph_node->pb_type->num_ports; i++) {
606  if (0
607  == strcmp(pb->pb_graph_node->pb_type->ports[i].name,
608  Prop)) {
609  found = TRUE;
610  break;
611  }
612  if (pb->pb_graph_node->pb_type->ports[i].is_clock
613  && pb->pb_graph_node->pb_type->ports[i].type
614  == IN_PORT) {
615  clock_port++;
616  } else if (!pb->pb_graph_node->pb_type->ports[i].is_clock
617  && pb->pb_graph_node->pb_type->ports[i].type
618  == IN_PORT) {
619  in_port++;
620  } else {
621  assert(
622  pb->pb_graph_node->pb_type->ports[i].type == OUT_PORT);
623  out_port++;
624  }
625  }
626  if (!found) {
627  vpr_printf(TIO_MESSAGE_ERROR, "[Line %d] Unknown port %s for pb %s[%d].\n",
628  Cur->line, Prop, pb->pb_graph_node->pb_type->name,
629  pb->pb_graph_node->placement_index);
630  exit(1);
631  }
632 
633  pins = GetNodeTokens(Cur);
634  num_tokens = CountTokens(pins);
635  if (0 == strcmp(Parent->name, "inputs")) {
636  if (num_tokens != pb->pb_graph_node->num_input_pins[in_port]) {
637  vpr_printf(TIO_MESSAGE_ERROR, "[Line %d] Incorrect # pins %d found for port %s for pb %s[%d].\n",
638  Cur->line, num_tokens, Prop,
639  pb->pb_graph_node->pb_type->name,
640  pb->pb_graph_node->placement_index);
641  exit(1);
642  }
643  } else if (0 == strcmp(Parent->name, "outputs")) {
644  if (num_tokens
645  != pb->pb_graph_node->num_output_pins[out_port]) {
646  vpr_printf(TIO_MESSAGE_ERROR, "[Line %d] Incorrect # pins %d found for port %s for pb %s[%d].\n",
647  Cur->line, num_tokens, Prop,
648  pb->pb_graph_node->pb_type->name,
649  pb->pb_graph_node->placement_index);
650  exit(1);
651  }
652  } else {
653  if (num_tokens
654  != pb->pb_graph_node->num_clock_pins[clock_port]) {
655  vpr_printf(TIO_MESSAGE_ERROR, "[Line %d] Incorrect # pins %d found for port %s for pb %s[%d].\n",
656  Cur->line, num_tokens, Prop,
657  pb->pb_graph_node->pb_type->name,
658  pb->pb_graph_node->placement_index);
659  exit(1);
660  }
661  }
662  if (0 == strcmp(Parent->name, "inputs")
663  || 0 == strcmp(Parent->name, "clocks")) {
664  if (pb->parent_pb == NULL) {
665  /* top-level, connections are nets to route */
666  for (i = 0; i < num_tokens; i++) {
667  if (0 == strcmp(Parent->name, "inputs"))
668  rr_node_index =
669  pb->pb_graph_node->input_pins[in_port][i].pin_count_in_cluster;
670  else
671  rr_node_index =
672  pb->pb_graph_node->clock_pins[clock_port][i].pin_count_in_cluster;
673  if (strcmp(pins[i], "open") != 0) {
674  temp_hash = get_hash_entry(vpack_net_hash, pins[i]);
675  if (temp_hash == NULL) {
676  vpr_printf(TIO_MESSAGE_ERROR, ".blif and .net do not match, unknown net %s found in .net file.\n.", pins[i]);
677  }
678  rr_graph[rr_node_index].net_num = temp_hash->index;
679  }
680  rr_node_to_pb_mapping[rr_node_index] = pb;
681  }
682  } else {
683  for (i = 0; i < num_tokens; i++) {
684  if (0 == strcmp(pins[i], "open")) {
685  continue;
686  }
687  interconnect_name = strstr(pins[i], "->");
688  *interconnect_name = '\0';
689  interconnect_name += 2;
690  port_name = pins[i];
691  pin_node =
693  pb->pb_graph_node->pb_type->parent_mode->interconnect[0].line_num,
694  pb->pb_graph_node->parent_pb_graph_node,
695  pb->pb_graph_node->parent_pb_graph_node->child_pb_graph_nodes[pb->parent_pb->mode],
696  port_name, &num_ptrs, &num_sets, TRUE,
697  TRUE);
698  assert(num_sets == 1 && num_ptrs[0] == 1);
699  if (0 == strcmp(Parent->name, "inputs"))
700  rr_node_index =
701  pb->pb_graph_node->input_pins[in_port][i].pin_count_in_cluster;
702  else
703  rr_node_index =
704  pb->pb_graph_node->clock_pins[clock_port][i].pin_count_in_cluster;
705  rr_graph[rr_node_index].prev_node =
706  pin_node[0][0]->pin_count_in_cluster;
707  rr_node_to_pb_mapping[rr_node_index] = pb;
708  found = FALSE;
709  for (j = 0; j < pin_node[0][0]->num_output_edges; j++) {
710  if (0
711  == strcmp(interconnect_name,
712  pin_node[0][0]->output_edges[j]->interconnect->name)) {
713  found = TRUE;
714  break;
715  }
716  }
717  for (j = 0; j < num_sets; j++) {
718  free(pin_node[j]);
719  }
720  free(pin_node);
721  free(num_ptrs);
722  if (!found) {
723  vpr_printf(TIO_MESSAGE_ERROR, "[Line %d] Unknown interconnect %s connecting to pin %s.\n",
724  Cur->line, interconnect_name, port_name);
725  exit(1);
726  }
727  }
728  }
729  }
730 
731  if (0 == strcmp(Parent->name, "outputs")) {
732  if (pb->pb_graph_node->pb_type->num_modes == 0) {
733  /* primitives are drivers of nets */
734  for (i = 0; i < num_tokens; i++) {
735  rr_node_index =
736  pb->pb_graph_node->output_pins[out_port][i].pin_count_in_cluster;
737  if (strcmp(pins[i], "open") != 0) {
738  temp_hash = get_hash_entry(vpack_net_hash, pins[i]);
739  if (temp_hash == NULL) {
740  vpr_printf(TIO_MESSAGE_ERROR, ".blif and .net do not match, unknown net %s found in .net file.\n", pins[i]);
741  }
742  rr_graph[rr_node_index].net_num = temp_hash->index;
743  }
744  rr_node_to_pb_mapping[rr_node_index] = pb;
745  }
746  } else {
747  for (i = 0; i < num_tokens; i++) {
748  if (0 == strcmp(pins[i], "open")) {
749  continue;
750  }
751  interconnect_name = strstr(pins[i], "->");
752  *interconnect_name = '\0';
753  interconnect_name += 2;
754  port_name = pins[i];
755  pin_node =
757  pb->pb_graph_node->pb_type->modes[pb->mode].interconnect->line_num,
758  pb->pb_graph_node,
759  pb->pb_graph_node->child_pb_graph_nodes[pb->mode],
760  port_name, &num_ptrs, &num_sets, TRUE,
761  TRUE);
762  assert(num_sets == 1 && num_ptrs[0] == 1);
763  rr_node_index =
764  pb->pb_graph_node->output_pins[out_port][i].pin_count_in_cluster;
765  rr_graph[rr_node_index].prev_node =
766  pin_node[0][0]->pin_count_in_cluster;
767  rr_node_to_pb_mapping[rr_node_index] = pb;
768  found = FALSE;
769  for (j = 0; j < pin_node[0][0]->num_output_edges; j++) {
770  if (0
771  == strcmp(interconnect_name,
772  pin_node[0][0]->output_edges[j]->interconnect->name)) {
773  found = TRUE;
774  break;
775  }
776  }
777  for (j = 0; j < num_sets; j++) {
778  free(pin_node[j]);
779  }
780  free(pin_node);
781  free(num_ptrs);
782  if (!found) {
783  vpr_printf(TIO_MESSAGE_ERROR, "[Line %d] Unknown interconnect %s connecting to pin %s.\n",
784  Cur->line, interconnect_name, port_name);
785  exit(1);
786  }
787  interconnect_name -= 2;
788  *interconnect_name = '-';
789  }
790  }
791  }
792 
793  FreeTokens(&pins);
794 
795  Prev = Cur;
796  Cur = Cur->next;
797  FreeNode(Prev);
798  } else {
799  Cur = Cur->next;
800  }
801  }
802 }
803 
804 /**
805  * This function updates the nets list and the connections between that list and the complex block
806  */
807 static void load_external_nets_and_cb(INP int L_num_blocks,
808  INP struct s_block block_list[], INP int ncount,
809  INP struct s_net nlist[], OUTP int *ext_ncount,
810  OUTP struct s_net **ext_nets, INP char **circuit_clocks) {
811  int i, j, k, ipin;
812  struct s_hash **ext_nhash;
813  t_rr_node *rr_graph;
814  t_pb_graph_pin *pb_graph_pin;
815  int *count;
816  int netnum, num_tokens;
817 
818  *ext_ncount = 0;
819  ext_nhash = alloc_hash_table();
820 
821  /* Assumes that complex block pins are ordered inputs, outputs, globals */
822 
823  /* Determine the external nets of complex block */
824  for (i = 0; i < L_num_blocks; i++) {
825  ipin = 0;
826  if (block_list[i].type->pb_type->num_input_pins
827  + block_list[i].type->pb_type->num_output_pins
828  + block_list[i].type->pb_type->num_clock_pins
829  != block_list[i].type->num_pins
830  / block_list[i].type->capacity) {
831 
832  assert(0);
833  }
834 
835  /* First determine nets external to complex blocks */
836  assert(
837  block_list[i].type->pb_type->num_input_pins + block_list[i].type->pb_type->num_output_pins + block_list[i].type->pb_type->num_clock_pins == block_list[i].type->num_pins / block_list[i].type->capacity);
838 
839  rr_graph = block_list[i].pb->rr_graph;
840  for (j = 0; j < block_list[i].pb->pb_graph_node->num_input_ports; j++) {
841  for (k = 0; k < block_list[i].pb->pb_graph_node->num_input_pins[j];
842  k++) {
843  pb_graph_pin =
844  &block_list[i].pb->pb_graph_node->input_pins[j][k];
845  assert(pb_graph_pin->pin_count_in_cluster == ipin);
846  if (rr_graph[pb_graph_pin->pin_count_in_cluster].net_num
847  != OPEN) {
848  block_list[i].nets[ipin] =
849  add_net_to_hash(ext_nhash,
850  nlist[rr_graph[pb_graph_pin->pin_count_in_cluster].net_num].name,
851  ext_ncount);
852  } else {
853  block_list[i].nets[ipin] = OPEN;
854  }
855  ipin++;
856  }
857  }
858  for (j = 0; j < block_list[i].pb->pb_graph_node->num_output_ports;
859  j++) {
860  for (k = 0; k < block_list[i].pb->pb_graph_node->num_output_pins[j];
861  k++) {
862  pb_graph_pin =
863  &block_list[i].pb->pb_graph_node->output_pins[j][k];
864  assert(pb_graph_pin->pin_count_in_cluster == ipin);
865  if (rr_graph[pb_graph_pin->pin_count_in_cluster].net_num
866  != OPEN) {
867  block_list[i].nets[ipin] =
868  add_net_to_hash(ext_nhash,
869  nlist[rr_graph[pb_graph_pin->pin_count_in_cluster].net_num].name,
870  ext_ncount);
871  } else {
872  block_list[i].nets[ipin] = OPEN;
873  }
874  ipin++;
875  }
876  }
877  for (j = 0; j < block_list[i].pb->pb_graph_node->num_clock_ports; j++) {
878  for (k = 0; k < block_list[i].pb->pb_graph_node->num_clock_pins[j];
879  k++) {
880  pb_graph_pin =
881  &block_list[i].pb->pb_graph_node->clock_pins[j][k];
882  assert(pb_graph_pin->pin_count_in_cluster == ipin);
883  if (rr_graph[pb_graph_pin->pin_count_in_cluster].net_num
884  != OPEN) {
885  block_list[i].nets[ipin] =
886  add_net_to_hash(ext_nhash,
887  nlist[rr_graph[pb_graph_pin->pin_count_in_cluster].net_num].name,
888  ext_ncount);
889  } else {
890  block_list[i].nets[ipin] = OPEN;
891  }
892  ipin++;
893  }
894  }
895  for (j = ipin; j < block_list[i].type->num_pins; j++) {
896  block_list[i].nets[ipin] = OPEN;
897  }
898  }
899 
900  /* alloc and partially load the list of external nets */
901  (*ext_nets) = alloc_and_init_netlist_from_hash(*ext_ncount, ext_nhash);
902  /* Load global nets */
903  num_tokens = CountTokens(circuit_clocks);
904 
905  count = (int *)my_calloc(*ext_ncount, sizeof(int));
906 
907  /* complete load of external nets so that each net points back to the blocks */
908  for (i = 0; i < L_num_blocks; i++) {
909  ipin = 0;
910  rr_graph = block_list[i].pb->rr_graph;
911  for (j = 0; j < block_list[i].type->num_pins; j++) {
912  netnum = block_list[i].nets[j];
913  if (netnum != OPEN) {
914  if (RECEIVER
915  == block_list[i].type->class_inf[block_list[i].type->pin_class[j]].type) {
916  count[netnum]++;
917  if(count[netnum] > (*ext_nets)[netnum].num_sinks) {
918  vpr_printf(TIO_MESSAGE_ERROR, "net %s #%d inconsistency, expected %d terminals but encountered %d terminals, it is likely net terminal is disconnected in netlist file.\n",
919  (*ext_nets)[netnum].name, netnum, count[netnum], (*ext_nets)[netnum].num_sinks);
920  exit(1);
921  }
922 
923  (*ext_nets)[netnum].node_block[count[netnum]] = i;
924  (*ext_nets)[netnum].node_block_pin[count[netnum]] = j;
925 
926  (*ext_nets)[netnum].is_global = block_list[i].type->is_global_pin[j]; /* Error check performed later to ensure no mixing of global and non-global signals */
927  } else {
928  assert(
929  DRIVER == block_list[i].type->class_inf[block_list[i].type->pin_class[j]].type);
930  assert((*ext_nets)[netnum].node_block[0] == OPEN);
931  (*ext_nets)[netnum].node_block[0] = i;
932  (*ext_nets)[netnum].node_block_pin[0] = j;
933  }
934  }
935  }
936  }
937  /* Error check global and non global signals */
938  for (i = 0; i < *ext_ncount; i++) {
939  for (j = 1; j <= (*ext_nets)[i].num_sinks; j++) {
940  if (block_list[(*ext_nets)[i].node_block[j]].type->is_global_pin[(*ext_nets)[i].node_block_pin[j]] != (*ext_nets)[i].is_global) {
941  vpr_printf(TIO_MESSAGE_ERROR, "Netlist attempts to connect net %s to both global and non-global pins.\n",
942  (*ext_nets)[i].name);
943  exit(1);
944  }
945  }
946  for (j = 0; j < num_tokens; j++) {
947  if (strcmp(circuit_clocks[j], (*ext_nets)[i].name) == 0) {
948  assert((*ext_nets)[i].is_global == TRUE); /* above code should have caught this case, if not, then bug in code */
949  }
950  }
951  }
952  free(count);
953  free_hash_table(ext_nhash);
954 }
955 
956 /* Recursive function that fills rr_graph of cb with net numbers starting at the given rr_node */
958  INP t_rr_node * cur_rr_node, INP t_rr_node * rr_graph) {
959  int i;
960  int count = 0;
961 
962  for (i = 0; i < cur_rr_node->num_edges; i++) {
963  if (&rr_graph[rr_graph[cur_rr_node->edges[i]].prev_node]
964  == cur_rr_node) {
965  assert(
966  rr_graph[cur_rr_node->edges[i]].net_num == OPEN || rr_graph[cur_rr_node->edges[i]].net_num == cur_rr_node->net_num);
968  &rr_graph[cur_rr_node->edges[i]], rr_graph);
969  }
970  }
971  if (count == 0) {
972  return 1; /* terminal node */
973  } else {
974  return count;
975  }
976 }
977 
978 /* Recursive function that fills rr_graph of cb with net numbers starting at the given rr_node */
980  INP t_rr_node * rr_graph, INOUTP struct s_net * nets,
981  INOUTP int * curr_net, INOUTP int * curr_sink) {
982  int i;
983 
984  boolean terminal;
985  terminal = TRUE;
986 
987  for (i = 0; i < cur_rr_node->num_edges; i++) {
988  if (&rr_graph[rr_graph[cur_rr_node->edges[i]].prev_node]
989  == cur_rr_node) {
990  /* TODO: If multiple edges to same node (should not happen in reasonable design) this always
991  selects the last edge, need to be smart about it in future (ie. select fastest edge */
992  assert(
993  rr_graph[cur_rr_node->edges[i]].net_num == OPEN || rr_graph[cur_rr_node->edges[i]].net_num == cur_rr_node->net_num);
994  rr_graph[cur_rr_node->edges[i]].net_num = cur_rr_node->net_num;
995  rr_graph[cur_rr_node->edges[i]].prev_edge = i;
996  load_internal_cb_rr_graph_net_nums(&rr_graph[cur_rr_node->edges[i]],
997  rr_graph, nets, curr_net, curr_sink);
998  terminal = FALSE;
999  }
1000  }
1001  if (terminal == TRUE) {
1002  /* Since the routing node index is known, assign that instead of the more obscure node block */
1003  nets[*curr_net].node_block[*curr_sink] =
1004  cur_rr_node->pb_graph_pin->pin_count_in_cluster;
1005  nets[*curr_net].node_block_pin[*curr_sink] = OPEN;
1006  nets[*curr_net].node_block_port[*curr_sink] = OPEN;
1007  (*curr_sink)++;
1008  }
1009 }
1010 
1011 /* Load internal cb nets and fill rr_graph of cb with net numbers */
1012 static void load_internal_cb_nets(INOUTP t_pb *top_level,
1013  INP t_pb_graph_node *pb_graph_node, INOUTP t_rr_node *rr_graph,
1014  INOUTP int * curr_net) {
1015  int i, j, k;
1016  const t_pb_type *pb_type;
1017  int temp, size;
1018  struct s_net * nets;
1019 
1020  pb_type = pb_graph_node->pb_type;
1021 
1022  nets = top_level->local_nets;
1023 
1024  temp = 0;
1025 
1026  if (pb_graph_node->parent_pb_graph_node == NULL) { /* determine nets driven from inputs at top level */
1027  *curr_net = 0;
1028  for (i = 0; i < pb_graph_node->num_input_ports; i++) {
1029  for (j = 0; j < pb_graph_node->num_input_pins[i]; j++) {
1030  if (rr_graph[pb_graph_node->input_pins[i][j].pin_count_in_cluster].net_num
1031  != OPEN) {
1033  &rr_graph[pb_graph_node->input_pins[i][j].pin_count_in_cluster],
1034  rr_graph, nets, curr_net, &temp);
1035  assert(temp == nets[*curr_net].num_sinks);
1036  temp = 0;
1037  size =
1038  strlen(pb_graph_node->pb_type->name)
1039  + pb_graph_node->placement_index / 10
1040  + i / 10 + j / 10
1041  + pb_graph_node->input_pins[i][j].pin_count_in_cluster
1042  / 10 + 26;
1043  nets[*curr_net].name = (char *)my_calloc(size, sizeof(char));
1044  sprintf(nets[*curr_net].name,
1045  "%s[%d].input[%d][%d].pin[%d]",
1046  pb_graph_node->pb_type->name,
1047  pb_graph_node->placement_index, i, j,
1048  pb_graph_node->input_pins[i][j].pin_count_in_cluster);
1049  (*curr_net)++;
1050  }
1051  }
1052  }
1053  for (i = 0; i < pb_graph_node->num_clock_ports; i++) {
1054  for (j = 0; j < pb_graph_node->num_clock_pins[i]; j++) {
1055  if (rr_graph[pb_graph_node->clock_pins[i][j].pin_count_in_cluster].net_num
1056  != OPEN) {
1058  &rr_graph[pb_graph_node->clock_pins[i][j].pin_count_in_cluster],
1059  rr_graph, nets, curr_net, &temp);
1060  assert(temp == nets[*curr_net].num_sinks);
1061  temp = 0;
1062  nets[*curr_net].is_global = TRUE;
1063  size =
1064  strlen(pb_graph_node->pb_type->name)
1065  + pb_graph_node->placement_index / 10
1066  + i / 10 + j / 10
1067  + pb_graph_node->clock_pins[i][j].pin_count_in_cluster
1068  / 10 + 26;
1069  nets[*curr_net].name = (char *)my_calloc(size, sizeof(char));
1070  sprintf(nets[*curr_net].name,
1071  "%s[%d].clock[%d][%d].pin[%d]",
1072  pb_graph_node->pb_type->name,
1073  pb_graph_node->placement_index, i, j,
1074  pb_graph_node->clock_pins[i][j].pin_count_in_cluster);
1075  (*curr_net)++;
1076  }
1077  }
1078  }
1079  }
1080 
1081  if (pb_type->blif_model != NULL) {
1082  /* This is a terminal node so it might drive nets, find and map the rr_graph path for those nets */
1083  for (i = 0; i < pb_graph_node->num_output_ports; i++) {
1084  for (j = 0; j < pb_graph_node->num_output_pins[i]; j++) {
1085  if (rr_graph[pb_graph_node->output_pins[i][j].pin_count_in_cluster].net_num
1086  != OPEN) {
1088  &rr_graph[pb_graph_node->output_pins[i][j].pin_count_in_cluster],
1089  rr_graph, nets, curr_net, &temp);
1090  assert(temp == nets[*curr_net].num_sinks);
1091  temp = 0;
1092  size =
1093  strlen(pb_graph_node->pb_type->name)
1094  + pb_graph_node->placement_index / 10
1095  + i / 10 + j / 10
1096  + pb_graph_node->output_pins[i][j].pin_count_in_cluster
1097  / 10 + 26;
1098  nets[*curr_net].name = (char *)my_calloc(size, sizeof(char));
1099  sprintf(nets[*curr_net].name,
1100  "%s[%d].output[%d][%d].pin[%d]",
1101  pb_graph_node->pb_type->name,
1102  pb_graph_node->placement_index, i, j,
1103  pb_graph_node->output_pins[i][j].pin_count_in_cluster);
1104  (*curr_net)++;
1105  }
1106  }
1107  }
1108  } else {
1109  /* Recurse down to primitives */
1110  for (i = 0; i < pb_type->num_modes; i++) {
1111  for (j = 0; j < pb_type->modes[i].num_pb_type_children; j++) {
1112  for (k = 0; k < pb_type->modes[i].pb_type_children[j].num_pb;
1113  k++) {
1114  load_internal_cb_nets(top_level,
1115  &pb_graph_node->child_pb_graph_nodes[i][j][k],
1116  rr_graph, curr_net);
1117  }
1118  }
1119  }
1120  }
1121 
1122  if (pb_graph_node->parent_pb_graph_node == NULL) { /* at top level */
1123  assert(*curr_net == top_level->num_local_nets);
1124  }
1125 }
1126 
1127 /* allocate space to store nets internal to cb
1128  two pass algorithm, pass 1 count and allocate # nets, pass 2 determine # sinks
1129  */
1130 static void alloc_internal_cb_nets(INOUTP t_pb *top_level,
1131  INP t_pb_graph_node *pb_graph_node, INOUTP t_rr_node *rr_graph,
1132  INP int pass) {
1133  int i, j, k;
1134  const t_pb_type *pb_type;
1135  int num_sinks;
1136 
1137  pb_type = pb_graph_node->pb_type;
1138 
1139  if (pb_graph_node->parent_pb_graph_node == NULL) { /* determine nets driven from inputs at top level */
1140  top_level->num_local_nets = 0;
1141  if (pass == 1)
1142  top_level->local_nets = NULL;
1143  for (i = 0; i < pb_graph_node->num_input_ports; i++) {
1144  for (j = 0; j < pb_graph_node->num_input_pins[i]; j++) {
1145  if (rr_graph[pb_graph_node->input_pins[i][j].pin_count_in_cluster].net_num
1146  != OPEN) {
1147  if (pass == 2) {
1148  num_sinks =
1150  &rr_graph[pb_graph_node->input_pins[i][j].pin_count_in_cluster],
1151  rr_graph);
1152  top_level->local_nets[top_level->num_local_nets].num_sinks =
1153  num_sinks;
1154  top_level->local_nets[top_level->num_local_nets].node_block = (int *)
1155  my_calloc(num_sinks, sizeof(int));
1156  top_level->local_nets[top_level->num_local_nets].node_block_port = (int *)
1157  my_calloc(num_sinks, sizeof(int));
1158  top_level->local_nets[top_level->num_local_nets].node_block_pin = (int *)
1159  my_calloc(num_sinks, sizeof(int));
1160  }
1161  top_level->num_local_nets++;
1162  }
1163  }
1164  }
1165  for (i = 0; i < pb_graph_node->num_clock_ports; i++) {
1166  for (j = 0; j < pb_graph_node->num_clock_pins[i]; j++) {
1167  if (rr_graph[pb_graph_node->clock_pins[i][j].pin_count_in_cluster].net_num
1168  != OPEN) {
1169  if (pass == 2) {
1170  num_sinks =
1172  &rr_graph[pb_graph_node->clock_pins[i][j].pin_count_in_cluster],
1173  rr_graph);
1174  top_level->local_nets[top_level->num_local_nets].num_sinks =
1175  num_sinks;
1176  top_level->local_nets[top_level->num_local_nets].node_block = (int *)
1177  my_calloc(num_sinks, sizeof(int));
1178  top_level->local_nets[top_level->num_local_nets].node_block_port = (int *)
1179  my_calloc(num_sinks, sizeof(int));
1180  top_level->local_nets[top_level->num_local_nets].node_block_pin = (int *)
1181  my_calloc(num_sinks, sizeof(int));
1182  }
1183  top_level->num_local_nets++;
1184  }
1185  }
1186  }
1187  }
1188 
1189  if (pb_type->blif_model != NULL) {
1190  /* This is a terminal node so it might drive nets, find and map the rr_graph path for those nets */
1191  for (i = 0; i < pb_graph_node->num_output_ports; i++) {
1192  for (j = 0; j < pb_graph_node->num_output_pins[i]; j++) {
1193  if (rr_graph[pb_graph_node->output_pins[i][j].pin_count_in_cluster].net_num
1194  != OPEN) {
1195  if (pass == 2) {
1196  num_sinks =
1198  &rr_graph[pb_graph_node->output_pins[i][j].pin_count_in_cluster],
1199  rr_graph);
1200  top_level->local_nets[top_level->num_local_nets].num_sinks =
1201  num_sinks;
1202  top_level->local_nets[top_level->num_local_nets].node_block = (int *)
1203  my_calloc(num_sinks, sizeof(int));
1204  top_level->local_nets[top_level->num_local_nets].node_block_port = (int *)
1205  my_calloc(num_sinks, sizeof(int));
1206  top_level->local_nets[top_level->num_local_nets].node_block_pin = (int *)
1207  my_calloc(num_sinks, sizeof(int));
1208  }
1209  top_level->num_local_nets++;
1210  }
1211  }
1212  }
1213  } else {
1214  /* Recurse down to primitives */
1215  for (i = 0; i < pb_type->num_modes; i++) {
1216  for (j = 0; j < pb_type->modes[i].num_pb_type_children; j++) {
1217  for (k = 0; k < pb_type->modes[i].pb_type_children[j].num_pb;
1218  k++) {
1219  alloc_internal_cb_nets(top_level,
1220  &pb_graph_node->child_pb_graph_nodes[i][j][k],
1221  rr_graph, pass);
1222  }
1223  }
1224  }
1225  }
1226 
1227  if (pb_graph_node->parent_pb_graph_node == NULL) { /* at top level */
1228  if (pass == 1) {
1229  top_level->local_nets = (struct s_net *)my_calloc(top_level->num_local_nets,
1230  sizeof(struct s_net));
1231  }
1232  }
1233 }
1234 
1235 static void mark_constant_generators(INP int L_num_blocks,
1236  INP struct s_block block_list[], INP int ncount,
1237  INOUTP struct s_net nlist[]) {
1238  int i;
1239  for (i = 0; i < L_num_blocks; i++) {
1240  mark_constant_generators_rec(block_list[i].pb,
1241  block_list[i].pb->rr_graph, nlist);
1242  }
1243 }
1244 
1246  INOUTP struct s_net nlist[]) {
1247  int i, j;
1248  t_pb_type *pb_type;
1249  boolean const_gen;
1250  if (pb->pb_graph_node->pb_type->blif_model == NULL) {
1251  for (i = 0;
1252  i
1253  < pb->pb_graph_node->pb_type->modes[pb->mode].num_pb_type_children;
1254  i++) {
1255  pb_type =
1256  &(pb->pb_graph_node->pb_type->modes[pb->mode].pb_type_children[i]);
1257  for (j = 0; j < pb_type->num_pb; j++) {
1258  if (pb->child_pbs[i][j].name != NULL) {
1259  mark_constant_generators_rec(&(pb->child_pbs[i][j]),
1260  rr_graph, nlist);
1261  }
1262  }
1263  }
1264  } else if (strcmp(pb->pb_graph_node->pb_type->name, "inpad") != 0) {
1265  const_gen = TRUE;
1266  for (i = 0; i < pb->pb_graph_node->num_input_ports && const_gen == TRUE;
1267  i++) {
1268  for (j = 0;
1269  j < pb->pb_graph_node->num_input_pins[i]
1270  && const_gen == TRUE; j++) {
1271  if (rr_graph[pb->pb_graph_node->input_pins[i][j].pin_count_in_cluster].net_num
1272  != OPEN) {
1273  const_gen = FALSE;
1274  }
1275  }
1276  }
1277  for (i = 0; i < pb->pb_graph_node->num_clock_ports && const_gen == TRUE;
1278  i++) {
1279  for (j = 0;
1280  j < pb->pb_graph_node->num_clock_pins[i]
1281  && const_gen == TRUE; j++) {
1282  if (rr_graph[pb->pb_graph_node->clock_pins[i][j].pin_count_in_cluster].net_num
1283  != OPEN) {
1284  const_gen = FALSE;
1285  }
1286  }
1287  }
1288  if (const_gen == TRUE) {
1289  vpr_printf(TIO_MESSAGE_INFO, "%s is a constant generator.\n", pb->name);
1290  for (i = 0; i < pb->pb_graph_node->num_output_ports; i++) {
1291  for (j = 0; j < pb->pb_graph_node->num_output_pins[i]; j++) {
1292  if (rr_graph[pb->pb_graph_node->output_pins[i][j].pin_count_in_cluster].net_num
1293  != OPEN) {
1294  nlist[rr_graph[pb->pb_graph_node->output_pins[i][j].pin_count_in_cluster].net_num].is_const_gen =
1295  TRUE;
1296  }
1297  }
1298  }
1299  }
1300  }
1301 }
1302 
1303 
1304 /* Free logical blocks of netlist */
1306  int iblk, i;
1307  t_model_ports *port;
1308  struct s_linked_vptr *tvptr, *next;
1309 
1310  for (iblk = 0; iblk < num_logical_blocks; iblk++) {
1311  port = logical_block[iblk].model->inputs;
1312  i = 0;
1313  while (port) {
1314  if (!port->is_clock) {
1315  free(logical_block[iblk].input_nets[i]);
1316  if (logical_block[iblk].input_net_tnodes) {
1317  if (logical_block[iblk].input_net_tnodes[i])
1318  free(logical_block[iblk].input_net_tnodes[i]);
1319  }
1320  i++;
1321  }
1322  port = port->next;
1323  }
1324  if (logical_block[iblk].input_net_tnodes)
1325  free(logical_block[iblk].input_net_tnodes);
1326 
1327  tvptr = logical_block[iblk].packed_molecules;
1328  while (tvptr != NULL) {
1329  next = tvptr->next;
1330  free(tvptr);
1331  tvptr = next;
1332  }
1333 
1334  free(logical_block[iblk].input_nets);
1335  port = logical_block[iblk].model->outputs;
1336  i = 0;
1337  while (port) {
1338  free(logical_block[iblk].output_nets[i]);
1339  if (logical_block[iblk].output_net_tnodes) {
1340  if (logical_block[iblk].output_net_tnodes[i])
1341  free(logical_block[iblk].output_net_tnodes[i]);
1342  }
1343  i++;
1344  port = port->next;
1345  }
1346  if (logical_block[iblk].output_net_tnodes) {
1347  free(logical_block[iblk].output_net_tnodes);
1348  }
1349  free(logical_block[iblk].output_nets);
1350  free(logical_block[iblk].name);
1351  tvptr = logical_block[iblk].truth_table;
1352  while (tvptr != NULL) {
1353  if (tvptr->data_vptr)
1354  free(tvptr->data_vptr);
1355  next = tvptr->next;
1356  free(tvptr);
1357  tvptr = next;
1358  }
1359  }
1360  free(logical_block);
1361  logical_block = NULL;
1362 }
1363 
1364 /* Free logical blocks of netlist */
1365 void free_logical_nets(void) {
1366  int inet;
1367 
1368  for (inet = 0; inet < num_logical_nets; inet++) {
1369  free(vpack_net[inet].name);
1370  free(vpack_net[inet].node_block);
1371  free(vpack_net[inet].node_block_port);
1372  free(vpack_net[inet].node_block_pin);
1373  }
1374  free(vpack_net);
1375  vpack_net = NULL;
1376 }
1377 
1378 
int * node_block_pin
Definition: vpr_types.h:509
void free_logical_blocks(void)
struct s_hash ** alloc_hash_table(void)
Definition: hash.c:7
struct s_hash_iterator start_hash_table_iterator(void)
Definition: hash.c:38
Definition: ezxml.h:44
static void mark_constant_generators_rec(INP t_pb *pb, INP t_rr_node *rr_graph, INOUTP struct s_net nlist[])
int count
Definition: hash.h:6
char * name
struct s_pb_type * pb_type_children
t_rr_node * rr_node
Definition: globals.c:70
int net_num
Definition: vpr_types.h:917
void FreeTokens(INOUTP char ***TokensPtr)
Definition: ReadLine.c:9
int index
Definition: hash.h:5
struct s_rr_node * rr_graph
Definition: vpr_types.h:188
int * clb_to_vpack_net_mapping
Definition: globals.c:33
char * txt
Definition: ezxml.h:47
t_mode * modes
struct s_hash * get_hash_entry(struct s_hash **hash_table, char *name)
Definition: hash.c:119
int hash_value(char *name)
Definition: hash.c:140
int prev_node
Definition: vpr_types.h:915
void alloc_and_load_rr_graph_for_pb_graph_node(INP t_pb_graph_node *pb_graph_node, INP const t_arch *arch, int mode)
void * my_calloc(size_t nelem, size_t size)
Definition: util.c:132
struct s_model_ports * next
Definition: logic_types.h:28
static void load_internal_cb_nets(INOUTP t_pb *top_level, INP t_pb_graph_node *pb_graph_node, INOUTP t_rr_node *rr_graph, INOUTP int *curr_net)
char * name
Definition: hash.h:4
int * node_block
Definition: vpr_types.h:507
struct s_linked_vptr * packed_molecules
Definition: vpr_types.h:228
struct s_linked_vptr * truth_table
Definition: vpr_types.h:227
int num_logical_nets
Definition: globals.c:17
t_token * GetTokensFromString(INP const char *inString, OUTP int *num_tokens)
Definition: token.c:18
char * blif_model
char * name
Definition: vpr_types.h:505
static void processComplexBlock(INOUTP ezxml_t Parent, INOUTP t_block *cb, INP int index, INOUTP int *num_primitives, INP const t_arch *arch, INP struct s_hash **vpack_net_hash, INP struct s_hash **logical_block_hash)
Definition: read_netlist.c:226
t_type_ptr type
Definition: vpr_types.h:561
boolean is_clock
Definition: logic_types.h:26
#define INOUTP
Definition: util.h:21
static void processPb(INOUTP ezxml_t Parent, INOUTP t_pb *pb, INOUTP t_rr_node *rr_graph, INOUTP t_pb **rr_node_to_pb_mapping, INOUTP int *num_primitives, INP struct s_hash **vpack_net_hash, INP struct s_hash **logical_block_hash, INP int cb_index)
Definition: read_netlist.c:333
char * name
Definition: vpr_types.h:560
Definition: util.h:12
void free_hash_table(struct s_hash **hash_table)
Definition: hash.c:18
ezxml_t next
Definition: ezxml.h:49
ezxml_t ezxml_set_attr(ezxml_t xml, char *name, char *value)
Definition: ezxml.c:1165
int CountTokens(INP char **Tokens)
Definition: ReadLine.c:19
static void * my_malloc(int ibytes)
Definition: graphics.c:499
ezxml_t FindElement(INP ezxml_t Parent, INP const char *Name, INP boolean Required)
Definition: read_xml_util.c:11
boolean * is_global
int * vpack_to_clb_net_mapping
Definition: globals.c:34
char * data
Definition: token.h:24
#define INP
Definition: util.h:19
int num_rr_nodes
Definition: globals.c:69
t_model_ports * inputs
Definition: logic_types.h:35
t_model_ports * outputs
Definition: logic_types.h:36
void FreeNode(INOUTP ezxml_t Node)
Definition: read_xml_util.c:73
static void load_external_nets_and_cb(INP int L_num_blocks, INP struct s_block block_list[], INP int ncount, INP struct s_net nlist[], OUTP int *ext_ncount, OUTP struct s_net **ext_nets, INP char **circuit_clocks)
Definition: read_netlist.c:807
int line
Definition: ezxml.h:56
static void alloc_internal_cb_nets(INOUTP t_pb *top_level, INP t_pb_graph_node *pb_graph_node, INOUTP t_rr_node *rr_graph, INP int pass)
struct s_linked_vptr * next
Definition: util.h:36
int num_pb_type_children
ezxml_t FindFirstElement(INP ezxml_t Parent, INP const char *Name, INP boolean Required)
Definition: read_xml_util.c:38
void CountTokensInString(INP const char *Str, OUTP int *Num, OUTP int *Len)
boolean is_global
Definition: vpr_types.h:510
void * data_vptr
Definition: util.h:35
char ** GetNodeTokens(INP ezxml_t Node)
static void mark_constant_generators(INP int L_num_blocks, INP struct s_block block_list[], INP int ncount, INOUTP struct s_net nlist[])
char * name
Definition: ezxml.h:45
int num_types
Definition: globals.c:37
static int count_sinks_internal_cb_rr_graph_net_nums(INP t_rr_node *cur_rr_node, INP t_rr_node *rr_graph)
Definition: read_netlist.c:957
struct s_hash * get_next_hash(struct s_hash **hash_table, struct s_hash_iterator *hash_iterator)
Definition: hash.c:51
t_pb_graph_pin *** alloc_and_load_port_pin_ptrs_from_string(INP int line_num, INP const t_pb_graph_node *pb_graph_parent_node, INP t_pb_graph_node **pb_graph_children_nodes, INP const char *port_string, OUTP int **num_ptrs, OUTP int *num_sets, INP boolean is_input_to_interc, INP boolean interconnect_error_check)
int num_logical_blocks
Definition: globals.c:17
void read_netlist(INP const char *net_file, INP const t_arch *arch, OUTP int *L_num_blocks, OUTP struct s_block *block_list[], OUTP int *L_num_nets, OUTP struct s_net *net_list[])
Definition: read_netlist.c:72
Definition: slre.c:50
static void processPorts(INOUTP ezxml_t Parent, INOUTP t_pb *pb, INOUTP t_rr_node *rr_graph, INOUTP t_pb **rr_node_to_pb_mapping, INP struct s_hash **vpack_net_hash)
static struct s_net * alloc_and_init_netlist_from_hash(INP int ncount, INOUTP struct s_hash **nhash)
Definition: read_netlist.c:531
ezxml_t ezxml_parse_file(const char *file)
Definition: ezxml.c:846
t_pb * pb
Definition: vpr_types.h:567
static void load_internal_cb_rr_graph_net_nums(INP t_rr_node *cur_rr_node, INP t_rr_node *rr_graph, INOUTP struct s_net *nets, INOUTP int *curr_net, INOUTP int *curr_sink)
Definition: read_netlist.c:979
t_pb_graph_node * pb_graph_head
int CountChildren(INP ezxml_t Node, INP const char *Name, INP int min_count)
struct s_type_descriptor * type_descriptors
Definition: globals.c:38
struct s_net * vpack_net
Definition: globals.c:19
static int add_net_to_hash(INOUTP struct s_hash **nhash, INP char *net_name, INOUTP int *ncount)
Definition: read_netlist.c:565
#define OUTP
Definition: util.h:20
Definition: token.h:22
void freeTokens(INP t_token *tokens, INP int num_tokens)
Definition: token.c:93
t_model * model
Definition: vpr_types.h:209
int my_atoi(const char *str)
Definition: util.c:116
char * my_strdup(const char *str)
Definition: util.c:101
messagelogger vpr_printf
Definition: util.c:17
ezxml_t child
Definition: ezxml.h:52
t_pb_graph_node * pb_graph_node
Definition: vpr_types.h:180
int num_sinks
Definition: vpr_types.h:506
int num_input_pins
struct s_hash * insert_in_hash_table(struct s_hash **hash_table, char *name, int next_free_index)
Definition: hash.c:76
void CheckElement(INP ezxml_t Node, INP const char *Name)
Definition: read_xml_util.c:59
const char * FindProperty(INP ezxml_t Parent, INP const char *Name, INP boolean)
void free_logical_nets(void)
Definition: hash.h:3
struct s_logical_block * logical_block
Definition: globals.c:20
Definition: util.h:12
struct s_rr_node t_rr_node