1 //--------------------------------------------------------------
2 // vlog2Spice
3 //
4 // Convert a structural verilog netlist (with power and ground
5 // nets!) into a SPICE netlist.
6 //
7 // Revision 0, 2006-11-11: First release by R. Timothy Edwards.
8 // Revision 1, 2009-07-13: Minor cleanups by Philipp Klaus Krause.
9 // Revision 2, 2013-05-10: Modified to take a library of subcell
10 // definitions to use for determining port order.
11 // Revision 3, 2013-10-09: Changed from BDnet2BSpice to
12 // blif2BSpice
13 // Revision 4, 2018-11-28: Changed from blif2BSpice to vlog2Spice
14 //
15 //--------------------------------------------------------------
16
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <math.h>
22 #include <ctype.h>
23 #include <float.h>
24
25 #include "hash.h"
26 #include "readverilog.h"
27
28 #define LengthOfLine 16384
29
30 #define DO_INCLUDE 0x01
31 #define DO_DELIMITER 0x02
32
33 /* Linked list of names of SPICE libraries to read */
34 typedef struct _linkedstring *LinkedStringPtr;
35
36 typedef struct _linkedstring {
37 char *string;
38 LinkedStringPtr next;
39 } LinkedString;
40
41 /* Function prototypes */
42 int write_output(struct cellrec *, LinkedStringPtr, char *, int);
43 int loc_getline(char s[], int lim, FILE *fp);
44 void helpmessage(FILE *);
45
46 //--------------------------------------------------------
47
main(int argc,char * argv[])48 int main (int argc, char *argv[])
49 {
50 int i, result = 0;
51 int flags = 0;
52 char *eptr;
53
54 char *vloginname = NULL;
55 char *spclibname = NULL;
56 char *spcoutname = NULL;
57
58 LinkedStringPtr spicelibs = NULL, newspicelib;
59
60
61 struct cellrec *topcell = NULL;
62
63 while ((i = getopt(argc, argv, "hHidD:l:s:o:")) != EOF) {
64 switch (i) {
65 case 'l':
66 newspicelib = (LinkedStringPtr)malloc(sizeof(LinkedString));
67 newspicelib->string = strdup(optarg);
68 newspicelib->next = spicelibs;
69 spicelibs = newspicelib;
70 break;
71 case 'o':
72 spcoutname = strdup(optarg);
73 break;
74 case 'i':
75 flags |= DO_INCLUDE;
76 break;
77 case 'd':
78 flags |= DO_DELIMITER;
79 break;
80 case 'h':
81 case 'H':
82 helpmessage(stdout);
83 exit(0);
84 break;
85 case 'D':
86 eptr = strchr(optarg, '=');
87 if (eptr != NULL) {
88 *eptr = '\0';
89 VerilogDefine(optarg, eptr + 1);
90 *eptr = '=';
91 }
92 else
93 VerilogDefine(optarg, "1");
94 break;
95 default:
96 fprintf(stderr, "Unknown switch %c\n", (char)i);
97 helpmessage(stderr);
98 exit(1);
99 break;
100 }
101 }
102
103 if (optind < argc) {
104 vloginname = strdup(argv[optind]);
105 optind++;
106 }
107 else {
108 fprintf(stderr, "Couldn't find a filename as input\n");
109 helpmessage(stderr);
110 exit(1);
111 }
112 optind++;
113
114 topcell = ReadVerilog(vloginname);
115 if (topcell != NULL)
116 result = write_output(topcell, spicelibs, spcoutname, flags);
117 else
118 result = 1; /* Return error code */
119
120 return result;
121 }
122
123 /*--------------------------------------------------------------*/
124 /* Verilog backslash notation, which is the most absurd syntax */
125 /* in the known universe, is fundamentally incompatible with */
126 /* SPICE. The ad-hoc solution used by qflow is to replace */
127 /* the trailing space with another backslash such that the */
128 /* name is SPICE-compatible and the original syntax can be */
129 /* recovered when needed. */
130 /*--------------------------------------------------------------*/
131
backslash_fix(char * netname)132 void backslash_fix(char *netname)
133 {
134 char *sptr;
135
136 if (*netname == '\\')
137 if ((sptr = strchr(netname, ' ')) != NULL)
138 *sptr = '\\';
139 }
140
141 /*--------------------------------------------------------------*/
142 /* write_output --- Write the SPICE netlist output */
143 /* */
144 /* ARGS: */
145 /* RETURNS: 0 on success, 1 on error. */
146 /* SIDE EFFECTS: */
147 /*--------------------------------------------------------------*/
148
write_output(struct cellrec * topcell,LinkedStringPtr spicelibs,char * outname,int flags)149 int write_output(struct cellrec *topcell, LinkedStringPtr spicelibs,
150 char *outname, int flags)
151 {
152 FILE *libfile;
153 FILE *outfile;
154 char *libname;
155 LinkedStringPtr curspicelib;
156
157 struct netrec *net;
158 struct instance *inst;
159 struct portrec *port;
160 struct portrec *newport, *portlist, *lastport;
161
162 int i, j, k, start, end, pcount = 1;
163 int result = 0;
164 int instidx, insti;
165
166 char *lptr;
167 char *sp, *sp2;
168 char line[LengthOfLine];
169
170 struct hashtable Libhash;
171
172 if (outname != NULL) {
173 outfile = fopen(outname, "w");
174 if (outfile == NULL) {
175 fprintf(stderr, "Error: Couldn't open file %s for writing\n", outname);
176 return 1;
177 }
178 }
179 else
180 outfile = stdout;
181
182 /* Initialize SPICE library hash table */
183 InitializeHashTable(&Libhash, SMALLHASHSIZE);
184
185 // Read one or more SPICE libraries of subcircuits and use them to define
186 // the order of pins that were read from LEF (which is not necessarily in
187 // SPICE pin order).
188
189 for (curspicelib = spicelibs; curspicelib; curspicelib = curspicelib->next) {
190 libname = curspicelib->string;
191
192 libfile = fopen(libname, "r");
193 if (libfile == NULL) {
194 fprintf(stderr, "Couldn't open %s for reading\n", libname);
195 continue;
196 }
197
198 /* Read SPICE library of subcircuits, if one is specified. */
199 /* Retain the name and order of ports passed to each */
200 /* subcircuit. */
201
202 j = 0;
203 while (loc_getline(line, sizeof(line), libfile) > 0) {
204 if (!strncasecmp(line, ".subckt", 7)) {
205 char *cellname;
206 lastport = NULL;
207 portlist = NULL;
208
209 /* Read cellname */
210 sp = line + 7;
211 while (isspace(*sp) && (*sp != '\n')) sp++;
212 sp2 = sp;
213 while (!isspace(*sp2) && (*sp2 != '\n')) sp2++;
214 *sp2 = '\0';
215
216 /* Keep a record of the cellname until we generate the */
217 /* hash entry for it */
218 cellname = strdup(sp);
219
220 /* Now fill out the ordered port list */
221 sp = sp2 + 1;
222 while (isspace(*sp) && (*sp != '\n') && (*sp != '\0')) sp++;
223 while (sp) {
224
225 /* Move string pointer to next port name */
226
227 if (*sp == '\n' || *sp == '\0') {
228 loc_getline(line, sizeof(line), libfile);
229 if (*line == '+')
230 sp = line + 1;
231 else
232 break;
233 }
234 while (isspace(*sp) && (*sp != '\n')) sp++;
235
236 /* Terminate port name and advance pointer */
237 sp2 = sp;
238 while (!isspace(*sp2) && (*sp2 != '\n') && (*sp2 != '\0')) sp2++;
239 *sp2 = '\0';
240
241 /* Add port to list (in forward order) */
242
243 newport = (struct portrec *)malloc(sizeof(struct portrec));
244 if (portlist == NULL)
245 portlist = newport;
246 else
247 lastport->next = newport;
248 lastport = newport;
249 newport->name = strdup(sp);
250 newport->net = NULL;
251 newport->direction = 0;
252 newport->next = NULL;
253
254 sp = sp2 + 1;
255 }
256
257 /* Read input to end of subcircuit */
258
259 if (strncasecmp(line, ".ends", 4)) {
260 while (loc_getline(line, sizeof(line), libfile) > 0)
261 if (!strncasecmp(line, ".ends", 4))
262 break;
263 }
264
265 /* Hash the new port record by cellname */
266 HashPtrInstall(cellname, portlist, &Libhash);
267 free(cellname);
268 }
269 }
270 fclose(libfile);
271 }
272
273 /* Write output header */
274 fprintf(outfile, "*SPICE netlist created from verilog structural netlist module "
275 "%s by vlog2Spice (qflow)\n", topcell->name);
276 fprintf(outfile, "*This file may contain array delimiters, not for use in simulation.\n");
277 fprintf(outfile, "\n");
278
279 /* If flags has DO_INCLUDE then dump the contents of the */
280 /* libraries. If 0, then just write a .include line. */
281
282 for (curspicelib = spicelibs; curspicelib; curspicelib = curspicelib->next) {
283 libname = curspicelib->string;
284
285 if (flags & DO_INCLUDE) {
286 libfile = fopen(libname, "r");
287 if (libfile != NULL) {
288 fprintf(outfile, "** Start of included library %s\n", libname);
289 /* Write out the subcircuit library file verbatim */
290 while (loc_getline(line, sizeof(line), libfile) > 0)
291 fputs(line, outfile);
292 fprintf(outfile, "** End of included library %s\n", libname);
293 fclose(libfile);
294 }
295 }
296 else {
297 fprintf(outfile, ".include %s\n", libname);
298 }
299 }
300 fprintf(outfile, "\n");
301
302 /* Generate the subcircuit definition, adding power and ground nets */
303
304 fprintf(outfile, ".subckt %s ", topcell->name);
305
306 for (port = topcell->portlist; port; port = port->next) {
307 if ((net = BusHashLookup(port->name, &topcell->nets)) != NULL) {
308 start = net->start;
309 end = net->end;
310 }
311 else start = end = -1;
312
313 if (start > end) {
314 int tmp;
315 tmp = start;
316 start = end;
317 end = tmp;
318 }
319 if (start == end) {
320 fprintf(outfile, "%s", port->name);
321 if (pcount++ % 8 == 7) {
322 pcount = 0;
323 fprintf(outfile, "\n+");
324 }
325 fprintf(outfile, " ");
326 }
327 else {
328 for (i = start; i <= end; i++) {
329 /* Note that use of brackets is not legal SPICE syntax */
330 /* but suffices for LVS and such. Output should be */
331 /* post-processed before using in simulation. */
332 if (flags & DO_DELIMITER)
333 fprintf(outfile, "%s<%d>", port->name, i);
334 else
335 fprintf(outfile, "%s[%d]", port->name, i);
336
337 if (pcount++ % 8 == 7) {
338 pcount = 0;
339 fprintf(outfile, "\n+");
340 }
341 fprintf(outfile, " ");
342 }
343 }
344 }
345 fprintf(outfile, "\n\n");
346
347 /* Output instances */
348
349 instidx = -1;
350 for (inst = topcell->instlist; inst; ) {
351 int argcnt;
352 struct portrec *libport;
353
354 /* Check if the instance is an array */
355 if (inst->arraystart != -1) {
356 if (instidx == -1) {
357 instidx = inst->arraystart;
358 insti = 0;
359 }
360 else if (inst->arraystart > inst->arrayend) {
361 instidx--;
362 insti++;
363 }
364 else if (inst->arraystart < inst->arrayend) {
365 instidx++;
366 insti++;
367 }
368 }
369
370 if (inst->arraystart == -1)
371 fprintf(outfile, "X%s ", inst->instname);
372 else
373 fprintf(outfile, "X%s[%d] ", inst->instname, instidx);
374 pcount = 1;
375
376 /* Search library records for subcircuit */
377
378 portlist = (struct portrec *)HashLookup(inst->cellname, &Libhash);
379
380 /* If no library entry exists, complain about arbitrary port */
381 /* order, then use the instance's port names to create a port */
382 /* record entry. */
383
384 if (portlist == NULL) {
385 fprintf(stderr, "Warning: No SPICE subcircuit for %s. Pin"
386 " order will be arbitrary.\n", inst->cellname);
387 lastport = portlist = NULL;
388 for (libport = inst->portlist; libport; libport = libport->next) {
389 newport = (struct portrec *)malloc(sizeof(struct portrec));
390 if (portlist == NULL)
391 portlist = newport;
392 else
393 lastport->next = newport;
394 lastport = newport;
395 newport->name = strdup(libport->name);
396 newport->net = NULL;
397 newport->direction = libport->direction;
398 newport->next = NULL;
399 }
400 HashPtrInstall(inst->cellname, portlist, &Libhash);
401 }
402
403 /* Output pin connections in the order of the LEF record, which */
404 /* has been forced to match the port order of the SPICE library */
405 /* If there is no SPICE library record, output in the order of */
406 /* the instance, which may or may not be correct. In such a */
407 /* case, flag a warning. */
408
409 argcnt = 0;
410 for (libport = portlist; ; libport = libport->next) {
411 char *dptr, dsave;
412 int idx = 0, is_array = FALSE, match = FALSE;
413
414 if (portlist != NULL && libport == NULL) break;
415
416 argcnt++;
417 argcnt %= 8;
418 if (argcnt == 7)
419 fprintf(outfile, "\n+ ");
420
421 dptr = NULL;
422 if (libport) {
423 for (dptr = libport->name; *dptr != '\0'; dptr++) {
424 if (*dptr == '[') {
425 is_array = TRUE;
426 dsave = *dptr;
427 *dptr = '\0';
428 sscanf(dptr + 1, "%d", &idx);
429 break;
430 }
431 }
432 }
433
434 /* Treat arrayed instances like a bit-blasted port */
435 if ((is_array == FALSE) && (inst->arraystart != -1)) {
436 is_array = TRUE;
437 idx = insti;
438 }
439
440 for (port = inst->portlist; port; port = port->next) {
441 /* Find the port name in the instance which matches */
442 /* the port name in the macro definition. */
443
444 if (libport) {
445 if (!strcasecmp(libport->name, port->name)) {
446 match = TRUE;
447 break;
448 }
449 }
450 else {
451 match = TRUE;
452 break;
453 }
454 }
455 if (!match) {
456 char *gptr;
457
458 /* Deal with annoying use of "!" as a global indicator, */
459 /* which is sometimes used. . . */
460 gptr = libport->name + strlen(libport->name) - 1;
461 if (*gptr == '!') {
462 *gptr = '\0';
463 for (port = inst->portlist; port; port = port->next) {
464 if (!strcasecmp(libport->name, port->name)) {
465 match = TRUE;
466 break;
467 }
468 }
469 *gptr = '!';
470 }
471 else {
472 for (port = inst->portlist; port; port = port->next) {
473 gptr = port->name + strlen(port->name) - 1;
474 if (*gptr == '!') {
475 *gptr = '\0';
476 if (!strcasecmp(libport->name, port->name)) match = TRUE;
477 *gptr = '!';
478 if (match == TRUE) break;
479 }
480 }
481 }
482 }
483 if (!match) {
484 fprintf(stderr, "Error: Instance %s has no port %s!\n",
485 inst->instname, libport->name);
486 }
487 else {
488 if (flags & DO_DELIMITER) {
489 char *d1ptr, *d2ptr;
490 if ((d1ptr = strchr(port->net, '[')) != NULL) {
491 if ((d2ptr = strchr(d1ptr + 1, ']')) != NULL) {
492 *d1ptr = '<';
493 *d2ptr = '>';
494 }
495 }
496 }
497 if (is_array) {
498 char *portname = port->net;
499 if (*portname == '{') {
500 char *epos, ssave;
501 int k;
502
503 /* Bus notation "{a, b, c, ... }" */
504 /* Go to the end and count bits backwards. */
505 /* until reaching the idx'th position. */
506
507 /* To be done: Move GetIndexedNet() from */
508 /* vlog2Verilog.c to readverilog.c and call */
509 /* it from here. It is more complete than */
510 /* this implementation. */
511
512 while (*portname != '}' && *portname != '\0') portname++;
513 for (k = 0; k <= idx; k++) {
514 epos = portname;
515 portname--;
516 while (*portname != ',' && portname > port->net)
517 portname--;
518 }
519 if (*portname == ',') portname++;
520 ssave = *epos;
521 *epos = '\0';
522 backslash_fix(portname);
523 fprintf(outfile, "%s", portname);
524 *epos = ssave;
525 }
526 else {
527 struct netrec wb;
528
529 GetBus(portname, &wb, &topcell->nets);
530
531 if (wb.start < 0) {
532 /* portname is not a bus */
533 backslash_fix(portname);
534 fprintf(outfile, "%s", portname);
535 }
536 else {
537 int lidx;
538 if (wb.start < wb.end)
539 lidx = wb.start + idx;
540 else
541 lidx = wb.start - idx;
542 /* portname is a partial or full bus */
543 dptr = strrchr(portname, '[');
544 if (dptr) *dptr = '\0';
545 backslash_fix(portname);
546 if (flags & DO_DELIMITER)
547 fprintf(outfile, "%s<%d>", portname, lidx);
548 else
549 fprintf(outfile, "%s[%d]", portname, lidx);
550 if (dptr) *dptr = '[';
551 }
552 }
553 }
554 else {
555 backslash_fix(port->net);
556 fprintf(outfile, "%s", port->net);
557 }
558
559 if (pcount++ % 8 == 7) {
560 pcount = 0;
561 fprintf(outfile, "\n+");
562 }
563 fprintf(outfile, " ");
564 }
565
566 if (portlist == NULL) {
567 fprintf(stdout, "Warning: No defined subcircuit %s for "
568 "instance %s!\n", inst->cellname, inst->instname);
569 fprintf(stdout, "Pins will be output in arbitrary order.\n");
570 break;
571 }
572 if (dptr != NULL) *dptr = '[';
573 }
574 fprintf(outfile, "%s\n", inst->cellname);
575
576 if ((inst->arraystart != -1) && (instidx != inst->arrayend)) continue;
577 instidx = -1;
578 inst = inst->next;
579 }
580 fprintf(outfile, "\n.ends\n");
581 fprintf(outfile, ".end\n");
582
583 if (outname != NULL) fclose(outfile);
584
585 return result;
586 }
587
588 /*--------------------------------------------------------------*/
589 /*C loc_getline: read a line, return length */
590 /* */
591 /* ARGS: */
592 /* RETURNS: 1 to OS */
593 /* SIDE EFFECTS: */
594 /*--------------------------------------------------------------*/
595
loc_getline(char * s,int lim,FILE * fp)596 int loc_getline(char *s, int lim, FILE *fp)
597 {
598 int c, i;
599
600 i = 0;
601 while(--lim > 0 && (c = getc(fp)) != EOF && c != '\n')
602 s[i++] = c;
603 if (c == '\n')
604 s[i++] = c;
605 s[i] = '\0';
606 if (c == EOF) i = 0;
607 return i;
608 }
609
610 /*--------------------------------------------------------------*/
611 /*C helpmessage - tell user how to use the program */
612 /* */
613 /* ARGS: error code (0 = success, 1 = error) */
614 /* RETURNS: 1 to OS */
615 /* SIDE EFFECTS: */
616 /*--------------------------------------------------------------*/
617
helpmessage(FILE * fout)618 void helpmessage(FILE *fout)
619 {
620 fprintf(fout, "vlog2Spice [-options] netlist \n");
621 fprintf(fout, "\n");
622 fprintf(fout, "vlog2Spice converts a netlist in verilog format \n");
623 fprintf(fout, "to Spice subcircuit format. Output on stdout unless -o option used.\n");
624 fprintf(fout, "Input file must be a structural verilog netlist with power and ground.\n");
625 fprintf(fout, "\n");
626 fprintf(fout, "Options:\n");
627 fprintf(fout, " -h Print this message\n");
628 fprintf(fout, " -i Generate include statement for library, not a dump.\n");
629 fprintf(fout, " -d Convert array delimiter brackets to angle brackets.\n");
630 fprintf(fout, " -D <key>=<value> Preregister a verilog definition.\n");
631 fprintf(fout, " -l <path> Specify path to SPICE library of standard cells.\n");
632 fprintf(fout, " -o <path> Specify path to output SPICE file.\n");
633 fprintf(fout, "\n");
634
635 } /* helpmessage() */
636
637