VPR-7.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
output_blif.c
Go to the documentation of this file.
1 /*
2  Jason Luu 2008
3  Print blif representation of circuit
4  Assumptions: Assumes first valid rr input to node is the correct rr input
5  Assumes clocks are routed globally
6  */
7 
8 #include <assert.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include "util.h"
13 #include "vpr_types.h"
14 #include "globals.h"
15 #include "output_blif.h"
16 #include "ReadOptions.h"
17 
18 #define LINELENGTH 1024
19 #define TABLENGTH 1
20 
21 /****************** Subroutines local to this module ************************/
22 
23 /**************** Subroutine definitions ************************************/
24 
25 static void print_string(const char *str_ptr, int *column, FILE * fpout) {
26 
27  /* Prints string without making any lines longer than LINELENGTH. Column *
28  * points to the column in which the next character will go (both used and *
29  * updated), and fpout points to the output file. */
30 
31  int len;
32 
33  len = strlen(str_ptr);
34  if (len + 3 > LINELENGTH) {
35  vpr_printf(TIO_MESSAGE_ERROR, "in print_string: String %s is too long for desired maximum line length.\n", str_ptr);
36  exit(1);
37  }
38 
39  if (*column + len + 2 > LINELENGTH) {
40  fprintf(fpout, "\\ \n");
41  *column = TABLENGTH;
42  }
43 
44  fprintf(fpout, "%s ", str_ptr);
45  *column += len + 1;
46 }
47 
48 static void print_net_name(int inet, int *column, FILE * fpout) {
49 
50  /* This routine prints out the vpack_net name (or open) and limits the *
51  * length of a line to LINELENGTH characters by using \ to continue *
52  * lines. net_num is the index of the vpack_net to be printed, while *
53  * column points to the current printing column (column is both *
54  * used and updated by this routine). fpout is the output file *
55  * pointer. */
56 
57  const char *str_ptr;
58 
59  if (inet == OPEN)
60  str_ptr = "open";
61  else
62  str_ptr = vpack_net[inet].name;
63 
64  print_string(str_ptr, column, fpout);
65 }
66 
67 static int find_fanin_rr_node(t_pb *cur_pb, enum PORTS type, int rr_node_index) {
68  /* finds first fanin rr_node */
69  t_pb *parent, *sibling, *child;
70  int net_num, irr_node;
71  int i, j, k, ichild_type, ichild_inst;
72  int hack_empty_route_through;
73  t_pb_graph_node *hack_empty_pb_graph_node;
74 
75  hack_empty_route_through = OPEN;
76 
77  net_num = rr_node[rr_node_index].net_num;
78 
79  parent = cur_pb->parent_pb;
80 
81  if (net_num == OPEN) {
82  return OPEN;
83  }
84 
85  if (type == IN_PORT) {
86  /* check parent inputs for valid connection */
87  for (i = 0; i < parent->pb_graph_node->num_input_ports; i++) {
88  for (j = 0; j < parent->pb_graph_node->num_input_pins[i]; j++) {
89  irr_node =
91  if (rr_node[irr_node].net_num == net_num) {
92  if (cur_pb->pb_graph_node->pb_type->model
93  && strcmp(
94  cur_pb->pb_graph_node->pb_type->model->name,
95  MODEL_LATCH) == 0) {
96  /* HACK: latches are special becuase LUTs can be set to route-through mode for them
97  I will assume that the input to a LATCH can always come from a parent input pin
98  this only works for hierarchical soft logic structures that follow LUT -> LATCH design
99  must do it better later
100  */
101  return irr_node;
102  }
103  hack_empty_route_through = irr_node;
104  for (k = 0; k < rr_node[irr_node].num_edges; k++) {
105  if (rr_node[irr_node].edges[k] == rr_node_index) {
106  return irr_node;
107  }
108  }
109  }
110  }
111  }
112  /* check parent clocks for valid connection */
113  for (i = 0; i < parent->pb_graph_node->num_clock_ports; i++) {
114  for (j = 0; j < parent->pb_graph_node->num_clock_pins[i]; j++) {
115  irr_node =
117  if (rr_node[irr_node].net_num == net_num) {
118  for (k = 0; k < rr_node[irr_node].num_edges; k++) {
119  if (rr_node[irr_node].edges[k] == rr_node_index) {
120  return irr_node;
121  }
122  }
123  }
124  }
125  }
126  /* check siblings for connection */
127  if (parent) {
128  for (ichild_type = 0;
129  ichild_type
130  < parent->pb_graph_node->pb_type->modes[parent->mode].num_pb_type_children;
131  ichild_type++) {
132  for (ichild_inst = 0;
133  ichild_inst
134  < parent->pb_graph_node->pb_type->modes[parent->mode].pb_type_children[ichild_type].num_pb;
135  ichild_inst++) {
136  if (parent->child_pbs[ichild_type]
137  && parent->child_pbs[ichild_type][ichild_inst].name
138  != NULL) {
139  sibling = &parent->child_pbs[ichild_type][ichild_inst];
140  for (i = 0;
141  i < sibling->pb_graph_node->num_output_ports;
142  i++) {
143  for (j = 0;
144  j
145  < sibling->pb_graph_node->num_output_pins[i];
146  j++) {
147  irr_node =
149  if (rr_node[irr_node].net_num == net_num) {
150  for (k = 0; k < rr_node[irr_node].num_edges;
151  k++) {
152  if (rr_node[irr_node].edges[k]
153  == rr_node_index) {
154  return irr_node;
155  }
156  }
157  }
158  }
159  }
160  } else {
161  /* hack just in case routing is down through an empty cluster */
162  hack_empty_pb_graph_node =
163  &parent->pb_graph_node->child_pb_graph_nodes[ichild_type][0][ichild_inst];
164  for (i = 0;
165  i < hack_empty_pb_graph_node->num_output_ports;
166  i++) {
167  for (j = 0;
168  j
169  < hack_empty_pb_graph_node->num_output_pins[i];
170  j++) {
171  irr_node =
172  hack_empty_pb_graph_node->output_pins[i][j].pin_count_in_cluster;
173  if (rr_node[irr_node].net_num == net_num) {
174  for (k = 0; k < rr_node[irr_node].num_edges;
175  k++) {
176  if (rr_node[irr_node].edges[k]
177  == rr_node_index) {
178  return irr_node;
179  }
180  }
181  }
182  }
183  }
184  }
185  }
186  }
187  }
188  } else {
189  assert(type == OUT_PORT);
190 
191  /* check children for connection */
192  for (ichild_type = 0;
193  ichild_type
194  < cur_pb->pb_graph_node->pb_type->modes[cur_pb->mode].num_pb_type_children;
195  ichild_type++) {
196  for (ichild_inst = 0;
197  ichild_inst
198  < cur_pb->pb_graph_node->pb_type->modes[cur_pb->mode].pb_type_children[ichild_type].num_pb;
199  ichild_inst++) {
200  if (cur_pb->child_pbs[ichild_type]
201  && cur_pb->child_pbs[ichild_type][ichild_inst].name
202  != NULL) {
203  child = &cur_pb->child_pbs[ichild_type][ichild_inst];
204  for (i = 0; i < child->pb_graph_node->num_output_ports;
205  i++) {
206  for (j = 0;
207  j < child->pb_graph_node->num_output_pins[i];
208  j++) {
209  irr_node =
211  if (rr_node[irr_node].net_num == net_num) {
212  for (k = 0; k < rr_node[irr_node].num_edges;
213  k++) {
214  if (rr_node[irr_node].edges[k]
215  == rr_node_index) {
216  return irr_node;
217  }
218  }
219  hack_empty_route_through = irr_node;
220  }
221  }
222  }
223  }
224  }
225  }
226 
227  /* If not in children, check current pb inputs for valid connection */
228  for (i = 0; i < cur_pb->pb_graph_node->num_input_ports; i++) {
229  for (j = 0; j < cur_pb->pb_graph_node->num_input_pins[i]; j++) {
230  irr_node =
232  if (rr_node[irr_node].net_num == net_num) {
233  hack_empty_route_through = irr_node;
234  for (k = 0; k < rr_node[irr_node].num_edges; k++) {
235  if (rr_node[irr_node].edges[k] == rr_node_index) {
236  return irr_node;
237  }
238  }
239  }
240  }
241  }
242  }
243 
244  /* TODO: Once I find a way to output routing in empty blocks then code should never reach here, for now, return OPEN */
245  vpr_printf(TIO_MESSAGE_INFO, "Use hack in blif dumper (do properly later): connecting net %s #%d for pb %s type %s\n",
246  vpack_net[net_num].name, net_num, cur_pb->name,
247  cur_pb->pb_graph_node->pb_type->name);
248 
249  assert(hack_empty_route_through != OPEN);
250  return hack_empty_route_through;
251 }
252 
253 static void print_primitive(FILE *fpout, int iblk) {
254  t_pb *pb;
255  int clb_index;
256  int i, j, k, node_index;
257  int in_port_index, out_port_index, clock_port_index;
258  struct s_linked_vptr *truth_table;
259  const t_pb_type *pb_type;
260 
261  pb = logical_block[iblk].pb;
262  pb_type = pb->pb_graph_node->pb_type;
263  clb_index = logical_block[iblk].clb_index;
264 
265  if (logical_block[iblk].type == VPACK_INPAD
266  || logical_block[iblk].type == VPACK_OUTPAD) {
267  /* do nothing */
268  } else if (logical_block[iblk].type == VPACK_LATCH) {
269  fprintf(fpout, ".latch ");
270 
271  in_port_index = 0;
272  out_port_index = 0;
273  clock_port_index = 0;
274  for (i = 0; i < pb_type->num_ports; i++) {
275  if (pb_type->ports[i].type == IN_PORT
276  && pb_type->ports[i].is_clock == FALSE) {
277  assert(pb_type->ports[i].num_pins == 1);
278  assert(logical_block[iblk].input_nets[i][0] != OPEN);
279  node_index =
280  pb->pb_graph_node->input_pins[in_port_index][0].pin_count_in_cluster;
281  fprintf(fpout, "clb_%d_rr_node_%d ", clb_index,
282  find_fanin_rr_node(pb, pb_type->ports[i].type,
283  node_index));
284  in_port_index++;
285  }
286  }
287  for (i = 0; i < pb_type->num_ports; i++) {
288  if (pb_type->ports[i].type == OUT_PORT) {
289  assert(pb_type->ports[i].num_pins == 1 && out_port_index == 0);
290  node_index =
291  pb->pb_graph_node->output_pins[out_port_index][0].pin_count_in_cluster;
292  fprintf(fpout, "clb_%d_rr_node_%d re ", clb_index, node_index);
293  out_port_index++;
294  }
295  }
296  for (i = 0; i < pb_type->num_ports; i++) {
297  if (pb_type->ports[i].type == IN_PORT
298  && pb_type->ports[i].is_clock == TRUE) {
299  assert(logical_block[iblk].clock_net != OPEN);
300  node_index =
301  pb->pb_graph_node->clock_pins[clock_port_index][0].pin_count_in_cluster;
302  fprintf(fpout, "clb_%d_rr_node_%d 2", clb_index,
303  find_fanin_rr_node(pb, pb_type->ports[i].type,
304  node_index));
305  clock_port_index++;
306  }
307  }
308  fprintf(fpout, "\n");
309  } else if (logical_block[iblk].type == VPACK_COMB) {
310  if (strcmp(logical_block[iblk].model->name, "names") == 0) {
311  fprintf(fpout, ".names ");
312  in_port_index = 0;
313  out_port_index = 0;
314  for (i = 0; i < pb_type->num_ports; i++) {
315  if (pb_type->ports[i].type == IN_PORT
316  && pb_type->ports[i].is_clock == FALSE) {
317  /* This is a LUT
318  LUTs receive special handling because a LUT has logically equivalent inputs.
319  The intra-logic block router may have taken advantage of logical equivalence so we need to unscramble the inputs when we output the LUT logic.
320  */
321  for (j = 0; j < pb_type->ports[i].num_pins; j++) {
322  if (logical_block[iblk].input_nets[in_port_index][j] != OPEN) {
323  for (k = 0; k < pb_type->ports[i].num_pins; k++) {
324  node_index = pb->pb_graph_node->input_pins[in_port_index][k].pin_count_in_cluster;
325  if(rr_node[node_index].net_num != OPEN) {
326  if(rr_node[node_index].net_num == logical_block[iblk].input_nets[in_port_index][j]) {
327  fprintf(fpout, "clb_%d_rr_node_%d ", clb_index,
329  pb_type->ports[i].type,
330  node_index));
331  break;
332  }
333  }
334  }
335  if(k == pb_type->ports[i].num_pins) {
336  /* Failed to find LUT input, a netlist error has occurred */
337  vpr_printf(TIO_MESSAGE_ERROR, "LUT %s missing input %s post packing. This is a VPR internal error, report to vpr@eecg.utoronto.ca\n",
338  logical_block[iblk].name, vpack_net[logical_block[iblk].input_nets[in_port_index][j]].name);
339  exit(1);
340  }
341  }
342  }
343  in_port_index++;
344  }
345  }
346  for (i = 0; i < pb_type->num_ports; i++) {
347  if (pb_type->ports[i].type == OUT_PORT) {
348  for (j = 0; j < pb_type->ports[i].num_pins; j++) {
349  node_index =
350  pb->pb_graph_node->output_pins[out_port_index][j].pin_count_in_cluster;
351  fprintf(fpout, "clb_%d_rr_node_%d\n", clb_index,
352  node_index);
353  }
354  out_port_index++;
355  }
356  }
357  truth_table = logical_block[iblk].truth_table;
358  while (truth_table) {
359  fprintf(fpout, "%s\n", (char *) truth_table->data_vptr);
360  truth_table = truth_table->next;
361  }
362  } else {
363  vpr_printf(TIO_MESSAGE_WARNING, "TODO: Implement blif dumper for subckt %s model %s", logical_block[iblk].name, logical_block[iblk].model->name);
364  }
365  }
366 }
367 
368 static void print_pb(FILE *fpout, t_pb * pb, int clb_index) {
369 
370  int column;
371  int i, j, k;
372  const t_pb_type *pb_type;
373  t_mode *mode;
374  int in_port_index, out_port_index, node_index;
375 
376  pb_type = pb->pb_graph_node->pb_type;
377  mode = &pb_type->modes[pb->mode];
378  column = 0;
379  if (pb_type->num_modes == 0) {
380  print_primitive(fpout, pb->logical_block);
381  } else {
382  in_port_index = 0;
383  out_port_index = 0;
384  for (i = 0; i < pb_type->num_ports; i++) {
385  if (!pb_type->ports[i].is_clock) {
386  for (j = 0; j < pb_type->ports[i].num_pins; j++) {
387  /* print .blif buffer to represent routing */
388  column = 0;
389  if (pb_type->ports[i].type == OUT_PORT) {
390  node_index =
391  pb->pb_graph_node->output_pins[out_port_index][j].pin_count_in_cluster;
392  if (rr_node[node_index].net_num != OPEN) {
393  fprintf(fpout, ".names clb_%d_rr_node_%d ",
394  clb_index,
396  pb_type->ports[i].type,
397  node_index));
398  if (pb->parent_pb) {
399  fprintf(fpout, "clb_%d_rr_node_%d ", clb_index,
400  node_index);
401  } else {
402  print_net_name(rr_node[node_index].net_num,
403  &column, fpout);
404  }
405  fprintf(fpout, "\n1 1\n");
406  if (pb->parent_pb == NULL) {
407  for (k = 1;
408  k
409  <= vpack_net[rr_node[node_index].net_num].num_sinks;
410  k++) {
411  /* output pads pre-pended with "out:", must remove */
412  if (logical_block[vpack_net[rr_node[node_index].net_num].node_block[k]].type
413  == VPACK_OUTPAD
414  && strcmp(
415  logical_block[vpack_net[rr_node[node_index].net_num].node_block[k]].name
416  + 4,
417  vpack_net[rr_node[node_index].net_num].name)
418  != 0) {
419  fprintf(fpout,
420  ".names clb_%d_rr_node_%d %s",
421  clb_index,
423  pb_type->ports[i].type,
424  node_index),
426  + 4);
427  fprintf(fpout, "\n1 1\n");
428  }
429  }
430  }
431  }
432 
433  } else {
434  node_index =
435  pb->pb_graph_node->input_pins[in_port_index][j].pin_count_in_cluster;
436  if (rr_node[node_index].net_num != OPEN) {
437 
438  fprintf(fpout, ".names ");
439  if (pb->parent_pb) {
440  fprintf(fpout, "clb_%d_rr_node_%d ", clb_index,
442  pb_type->ports[i].type,
443  node_index));
444  } else {
445  print_net_name(rr_node[node_index].net_num,
446  &column, fpout);
447  }
448  fprintf(fpout, "clb_%d_rr_node_%d", clb_index,
449  node_index);
450  fprintf(fpout, "\n1 1\n");
451  }
452  }
453  }
454  }
455  if (pb_type->ports[i].type == OUT_PORT) {
456  out_port_index++;
457  } else {
458  in_port_index++;
459  }
460  }
461  for (i = 0; i < mode->num_pb_type_children; i++) {
462  for (j = 0; j < mode->pb_type_children[i].num_pb; j++) {
463  /* If child pb is not used but routing is used, I must print things differently */
464  if ((pb->child_pbs[i] != NULL)
465  && (pb->child_pbs[i][j].name != NULL)) {
466  print_pb(fpout, &pb->child_pbs[i][j], clb_index);
467  } else {
468  /* do nothing for now, we'll print something later if needed */
469  }
470  }
471  }
472  }
473 }
474 
475 static void print_clusters(t_block *clb, int num_clusters, FILE * fpout) {
476 
477  /* Prints out one cluster (clb). Both the external pins and the *
478  * internal connections are printed out. */
479 
480  int icluster;
481 
482  for (icluster = 0; icluster < num_clusters; icluster++) {
483  rr_node = clb[icluster].pb->rr_graph;
484  if (clb[icluster].type != IO_TYPE)
485  print_pb(fpout, clb[icluster].pb, icluster);
486  }
487 }
488 
489 void output_blif (t_block *clb, int num_clusters, boolean global_clocks,
490  boolean * is_clock, const char *out_fname, boolean skip_clustering) {
491 
492  /*
493  * This routine dumps out the output netlist in a format suitable for *
494  * input to vpr. This routine also dumps out the internal structure of *
495  * the cluster, in essentially a graph based format. */
496 
497  FILE *fpout;
498  int bnum, column;
499  struct s_linked_vptr *p_io_removed;
500  int i;
501 
502  fpout = my_fopen(out_fname, "w", 0);
503 
504  column = 0;
505  fprintf(fpout, ".model %s\n", blif_circuit_name);
506 
507  /* Print out all input and output pads. */
508  fprintf(fpout, "\n.inputs ");
509  for (bnum = 0; bnum < num_logical_blocks; bnum++) {
510  if (logical_block[bnum].type == VPACK_INPAD) {
511  print_string(logical_block[bnum].name, &column, fpout);
512  }
513  }
514  p_io_removed = circuit_p_io_removed;
515  while (p_io_removed) {
516  print_string((char*) p_io_removed->data_vptr, &column, fpout);
517  p_io_removed = p_io_removed->next;
518  }
519 
520  column = 0;
521  fprintf(fpout, "\n.outputs ");
522  for (bnum = 0; bnum < num_logical_blocks; bnum++) {
523  if (logical_block[bnum].type == VPACK_OUTPAD) {
524  /* remove output prefix "out:" */
525  print_string(logical_block[bnum].name + 4, &column, fpout);
526  }
527  }
528 
529  column = 0;
530 
531  fprintf(fpout, "\n\n");
532 
533  /* print logic of clusters */
534  print_clusters(clb, num_clusters, fpout);
535 
536  /* handle special case: input goes straight to output without going through any logic */
537  for (bnum = 0; bnum < num_logical_blocks; bnum++) {
538  if (logical_block[bnum].type == VPACK_INPAD) {
539  for (i = 1;
540  i
542  i++) {
543  if (logical_block[vpack_net[logical_block[bnum].output_nets[0][0]].node_block[i]].type
544  == VPACK_OUTPAD) {
545  fprintf(fpout, ".names ");
546  print_string(logical_block[bnum].name, &column, fpout);
547  print_string(
548  logical_block[vpack_net[logical_block[bnum].output_nets[0][0]].node_block[i]].name
549  + 4, &column, fpout);
550  fprintf(fpout, "\n1 1\n");
551  }
552  }
553  }
554  }
555 
556  fprintf(fpout, "\n.end\n");
557 
558  fclose(fpout);
559 }
boolean is_clock
PORTS
Definition: logic_types.h:18
short num_edges
Definition: vpr_types.h:901
char * name
Definition: vpr_types.h:179
t_pb_graph_pin ** clock_pins
FILE * my_fopen(const char *fname, const char *flag, int prompt)
Definition: util.c:54
struct s_pb * parent_pb
Definition: vpr_types.h:186
struct s_pb ** child_pbs
Definition: vpr_types.h:185
int num_pins
struct s_pb_type * pb_type_children
struct s_linked_vptr * circuit_p_io_removed
Definition: globals.c:90
t_rr_node * rr_node
Definition: globals.c:70
int net_num
Definition: vpr_types.h:917
struct s_rr_node * rr_graph
Definition: vpr_types.h:188
t_mode * modes
#define LINELENGTH
Definition: output_blif.c:18
enum PORTS type
int * node_block
Definition: vpr_types.h:507
struct s_linked_vptr * truth_table
Definition: vpr_types.h:227
char * name
Definition: vpr_types.h:505
t_pb_graph_pin ** output_pins
t_model * model
void output_blif(t_block *clb, int num_clusters, boolean global_clocks, boolean *is_clock, const char *out_fname, boolean skip_clustering)
Definition: output_blif.c:489
char * blif_circuit_name
Definition: globals.c:21
Definition: util.h:12
#define TABLENGTH
Definition: output_blif.c:19
static void print_net_name(int inet, int *column, FILE *fpout)
Definition: output_blif.c:48
#define MODEL_LATCH
Definition: vpr_types.h:275
int logical_block
Definition: vpr_types.h:181
static void print_pb(FILE *fpout, t_pb *pb, int clb_index)
Definition: output_blif.c:368
static void print_clusters(t_block *clb, int num_clusters, FILE *fpout)
Definition: output_blif.c:475
static void print_string(const char *str_ptr, int *column, FILE *fpout)
Definition: output_blif.c:25
struct s_pb_graph_node *** child_pb_graph_nodes
struct s_linked_vptr * next
Definition: util.h:36
int num_pb_type_children
static char * model
Definition: read_blif.c:45
void * data_vptr
Definition: util.h:35
struct s_pb_type * pb_type
char * name
Definition: logic_types.h:34
t_type_ptr IO_TYPE
Definition: globals.c:40
t_port * ports
int num_logical_blocks
Definition: globals.c:17
Definition: slre.c:50
t_pb * pb
Definition: vpr_types.h:567
struct s_net * vpack_net
Definition: globals.c:19
static void print_primitive(FILE *fpout, int iblk)
Definition: output_blif.c:253
static int find_fanin_rr_node(t_pb *cur_pb, enum PORTS type, int rr_node_index)
Definition: output_blif.c:67
int mode
Definition: vpr_types.h:183
int ** output_nets
Definition: vpr_types.h:212
messagelogger vpr_printf
Definition: util.c:17
t_pb_graph_node * pb_graph_node
Definition: vpr_types.h:180
int num_sinks
Definition: vpr_types.h:506
t_pb_graph_pin ** input_pins
struct s_logical_block * logical_block
Definition: globals.c:20
Definition: util.h:12