summaryrefslogtreecommitdiff
path: root/src/vlog2Verilog.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vlog2Verilog.c')
-rw-r--r--src/vlog2Verilog.c1018
1 files changed, 1018 insertions, 0 deletions
diff --git a/src/vlog2Verilog.c b/src/vlog2Verilog.c
new file mode 100644
index 0000000..1b0ebf8
--- /dev/null
+++ b/src/vlog2Verilog.c
@@ -0,0 +1,1018 @@
+//----------------------------------------------------------------
+// vlog2Verilog
+//----------------------------------------------------------------
+// Convert between verilog styles.
+// Options include bit-blasting vectors and adding power
+// supply connections.
+//
+// Revision 0, 2018-11-29: First release by R. Timothy Edwards.
+//
+// This program is written in ISO C99.
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h> /* For getopt() */
+#include <math.h>
+#include <ctype.h>
+#include <float.h>
+
+#include "hash.h"
+#include "readverilog.h"
+#include "readlef.h"
+
+int write_output(struct cellrec *, unsigned char, char *);
+void helpmessage(FILE *outf);
+void cleanup_string(char *);
+int is_pwr_name(char *);
+
+char *VddNet = NULL;
+char *GndNet = NULL;
+char *AntennaCell = NULL;
+
+struct hashtable Lefhash;
+
+/* Define option flags */
+
+#define IMPLICIT_POWER (unsigned char)0x01
+#define MAINTAIN_CASE (unsigned char)0x02
+#define BIT_BLAST (unsigned char)0x04
+#define NONAME_POWER (unsigned char)0x08
+#define ADD_ANTENNA (unsigned char)0x10
+
+/*--------------------------------------------------------------*/
+
+int main (int argc, char *argv[])
+{
+ int i, result;
+ unsigned char Flags;
+
+ char *vloginname = NULL;
+ char *vlogoutname = NULL;
+ struct cellrec *topcell;
+
+ Flags = (unsigned char)IMPLICIT_POWER;
+
+ VddNet = strdup("VDD");
+ GndNet = strdup("VSS");
+
+ InitializeHashTable(&Lefhash, SMALLHASHSIZE);
+
+ while ((i = getopt(argc, argv, "pbchnHv:g:l:o:a:")) != EOF) {
+ switch( i ) {
+ case 'p':
+ Flags &= ~IMPLICIT_POWER;
+ break;
+ case 'b':
+ Flags |= BIT_BLAST;
+ break;
+ case 'c':
+ Flags |= MAINTAIN_CASE;
+ break;
+ case 'a':
+ Flags |= ADD_ANTENNA;
+ if (AntennaCell != NULL) free(AntennaCell);
+ AntennaCell = strdup(optarg);
+ break;
+ case 'n':
+ Flags |= NONAME_POWER;
+ break;
+ case 'h':
+ case 'H':
+ helpmessage(stdout);
+ exit(0);
+ break;
+ case 'l':
+ LefRead(optarg); /* Can be called multiple times */
+ break;
+ case 'v':
+ free(VddNet);
+ VddNet = strdup(optarg);
+ cleanup_string(VddNet);
+ break;
+ case 'o':
+ vlogoutname = strdup(optarg);
+ break;
+ case 'g':
+ free(GndNet);
+ GndNet = strdup(optarg);
+ cleanup_string(GndNet);
+ break;
+ default:
+ fprintf(stderr,"Bad switch \"%c\"\n", (char)i);
+ helpmessage(stderr);
+ return 1;
+ }
+ }
+
+ if (optind < argc) {
+ vloginname = strdup(argv[optind]);
+ optind++;
+ }
+ else {
+ fprintf(stderr, "Couldn't find a filename as input\n");
+ helpmessage(stderr);
+ return 1;
+ }
+ optind++;
+
+ /* If any LEF files were read, hash the GateInfo list */
+ if (GateInfo != NULL) {
+ GATE gate;
+ for (gate = GateInfo; gate; gate = gate->next) {
+ HashPtrInstall(gate->gatename, gate, &Lefhash);
+ }
+ }
+
+ topcell = ReadVerilog(vloginname);
+ result = write_output(topcell, Flags, vlogoutname);
+ return result;
+}
+
+/*--------------------------------------------------------------*/
+/* Name compare for VddNet and GndNet. Remove any trailing "!" */
+/* (global reference) from the net name. */
+/*--------------------------------------------------------------*/
+
+int is_pwr_name(char *text)
+{
+ int n = strlen(text);
+
+ if (*(text + n - 1) == '!') *(text + n - 1) = '\0';
+
+ if (!strcmp(text, VddNet)) return 0;
+ if (!strcmp(text, GndNet)) return 0;
+ return 1;
+}
+
+/*--------------------------------------------------------------*/
+/* String input cleanup (mainly strip quoted text) */
+/*--------------------------------------------------------------*/
+
+void cleanup_string(char *text)
+{
+ int i;
+ char *sptr, *wptr;
+
+ /* Remove quotes from quoted strings */
+
+ sptr = strchr(text, '"');
+ if (sptr != NULL) {
+ i = 0;
+ while (sptr[i + 1] != '"') {
+ sptr[i] = sptr[i + 1];
+ i++;
+ }
+ sptr[i] = '\0';
+ }
+
+ /* Remove any trailing "!" used as a global identifier */
+ if ((sptr > text) && (*(sptr - 1) == '!')) {
+ *(sptr - 1) = '\0';
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+/* Recursion callback function for each item in the cellrec nets hash table */
+/*--------------------------------------------------------------------------*/
+
+struct nlist *output_wires(struct hashlist *p, void *cptr)
+{
+ struct netrec *net;
+ FILE *outf = (FILE *)cptr;
+
+ net = (struct netrec *)(p->ptr);
+
+ /* Ignore the power and ground nets; these have already been output */
+ /* This also extends to any net in the form <digit><single quote> */
+
+ if (p->name[0] == '\'') return NULL;
+ if (isdigit(p->name[0])) {
+ char c, *dptr;
+
+ dptr = p->name;
+ while (isdigit(*dptr)) dptr++;
+ if (*dptr == '\0') return NULL;
+ else if (*dptr == '\'') {
+ c = *(dptr + 1);
+ if (c == 'b' || c == 'h' || c == 'd' || c == 'o')
+ return NULL;
+ }
+ }
+ else if (is_pwr_name(p->name)) return NULL;
+
+ fprintf(outf, "wire ");
+ if (net->start >= 0 && net->end >= 0) {
+ fprintf(outf, "[%d:%d] ", net->start, net->end);
+ }
+ fprintf(outf, "%s ;\n", p->name);
+ return NULL;
+}
+
+/*----------------------------------------------------------------------*/
+/* Convert a verilog number into a binary string. The target string */
+/* "bitstring" is assumed to be at least (bits + 1) bytes in length. */
+/* "c" is a conversion type ('h', 'o', or 'd'). */
+/*----------------------------------------------------------------------*/
+/* hexidecimal to binary */
+
+char *hex2binary(char *uval, int bits)
+{
+ int first, dval, hexc;
+ char *bitstring = (char *)malloc(1 + bits);
+ char *hptr, *bptr, *hstring;
+ char binhex[5];
+
+ first = bits % 4;
+ hexc = ((first == 0) ? 0 : 1) + (bits / 4); /* Number of hex characters */
+
+ hstring = (char *)malloc(hexc + 1);
+ strncpy(hstring, uval, hexc);
+ *(hstring + hexc) = '\0';
+ for (hptr = hstring; *hptr != '\0'; hptr++) {
+
+ /* Catch 'x', 'X', etc., and convert to zero. */
+ /* Keep 'z'/'Z' as this must be handled differently */
+
+ if ((*hptr == 'z') || (*hptr == 'Z')) *hptr = 'Z';
+ else if ((*hptr == 'x') || (*hptr == 'X')) *hptr = '0';
+ }
+
+ hptr = hstring;
+ bptr = bitstring;
+ while (*hptr != '\0') {
+ switch(*hptr) {
+ case 'Z':
+ strcpy(binhex, "ZZZZ");
+ break;
+ case '0':
+ strcpy(binhex, "0000");
+ break;
+ case '1':
+ strcpy(binhex, "0001");
+ break;
+ case '2':
+ strcpy(binhex, "0010");
+ break;
+ case '3':
+ strcpy(binhex, "0011");
+ break;
+ case '4':
+ strcpy(binhex, "0100");
+ break;
+ case '5':
+ strcpy(binhex, "0101");
+ break;
+ case '6':
+ strcpy(binhex, "0110");
+ break;
+ case '7':
+ strcpy(binhex, "0111");
+ break;
+ case '8':
+ strcpy(binhex, "1000");
+ break;
+ case '9':
+ strcpy(binhex, "1001");
+ break;
+ case 'a':
+ strcpy(binhex, "1010");
+ break;
+ case 'b':
+ strcpy(binhex, "1011");
+ break;
+ case 'c':
+ strcpy(binhex, "1100");
+ break;
+ case 'd':
+ strcpy(binhex, "1101");
+ break;
+ case 'e':
+ strcpy(binhex, "1110");
+ break;
+ case 'f':
+ strcpy(binhex, "1111");
+ break;
+ }
+ if (first > 0) {
+ strncpy(bptr, binhex + (4 - first), first);
+ *(bptr + first) = '\0';
+ bptr += first;
+ first = 0;
+ }
+ else {
+ strcpy(bptr, binhex);
+ bptr += 4;
+ }
+ hptr++;
+ }
+ return bitstring;
+}
+
+/* octal to binary */
+
+char *oct2binary(char *uval, int bits)
+{
+ int first, dval, octc;
+ char *bitstring = (char *)malloc(1 + bits);
+ char *optr, *bptr, *ostring;
+ char binoct[4];
+
+ first = bits % 3;
+ octc = ((first == 0) ? 0 : 1) + (bits / 3); /* Number of octal characters */
+ ostring = (char *)malloc(1 + octc);
+
+ ostring = (char *)malloc(octc + 1);
+ strncpy(ostring, uval, octc);
+ *(ostring + octc) = '\0';
+ for (optr = ostring; *optr != '\0'; optr++) {
+
+ /* Catch 'x', 'X', etc., and convert to zero. */
+ /* Keep 'z'/'Z' as this must be handled differently */
+
+ if ((*optr == 'z') || (*optr == 'Z')) *optr = 'Z';
+ else if ((*optr == 'x') || (*optr == 'X')) *optr = '0';
+ }
+
+ optr = ostring;
+ bptr = bitstring;
+ while (*optr != '\0') {
+ switch(*optr) {
+ case 'Z':
+ strcpy(binoct, "ZZZ");
+ break;
+ case '0':
+ strcpy(binoct, "000");
+ break;
+ case '1':
+ strcpy(binoct, "001");
+ break;
+ case '2':
+ strcpy(binoct, "010");
+ break;
+ case '3':
+ strcpy(binoct, "011");
+ break;
+ case '4':
+ strcpy(binoct, "100");
+ break;
+ case '5':
+ strcpy(binoct, "101");
+ break;
+ case '6':
+ strcpy(binoct, "110");
+ break;
+ case '7':
+ strcpy(binoct, "11");
+ break;
+ }
+ if (first > 0) {
+ strncpy(bptr, binoct + (3 - first), first);
+ *(bptr + first) = '\0';
+ bptr += first;
+ first = 0;
+ }
+ else {
+ strcpy(bptr, binoct);
+ bptr += 3;
+ }
+ optr++;
+ }
+ return bitstring;
+}
+
+/* decimal to binary */
+
+char *dec2binary(char *uval, int bits)
+{
+ int first, dval, hexc;
+ char *bitstring = (char *)malloc(1 + bits);
+ char *hptr, *bptr, *hstring, *nval;
+ char binhex[5];
+
+ first = bits % 4;
+ hexc = ((first == 0) ? 0 : 1) + bits >> 2; /* Number of hex characters */
+ hstring = (char *)malloc(1 + hexc);
+
+ /* Scan integer value then convert to hex */
+ sscanf(uval, "%d", &dval);
+ sprintf(hstring, "%0*x", hexc, dval);
+
+ hptr = hstring;
+ bptr = bitstring;
+ while (*hptr != '\0') {
+ switch(*hptr) {
+ case '0':
+ strcpy(binhex, "0000");
+ break;
+ case '1':
+ strcpy(binhex, "0001");
+ break;
+ case '2':
+ strcpy(binhex, "0010");
+ break;
+ case '3':
+ strcpy(binhex, "0011");
+ break;
+ case '4':
+ strcpy(binhex, "0100");
+ break;
+ case '5':
+ strcpy(binhex, "0101");
+ break;
+ case '6':
+ strcpy(binhex, "0110");
+ break;
+ case '7':
+ strcpy(binhex, "0111");
+ break;
+ case '8':
+ strcpy(binhex, "1000");
+ break;
+ case '9':
+ strcpy(binhex, "1001");
+ break;
+ case 'a':
+ strcpy(binhex, "1010");
+ break;
+ case 'b':
+ strcpy(binhex, "1011");
+ break;
+ case 'c':
+ strcpy(binhex, "1100");
+ break;
+ case 'd':
+ strcpy(binhex, "1101");
+ break;
+ case 'e':
+ strcpy(binhex, "1110");
+ break;
+ case 'f':
+ strcpy(binhex, "1111");
+ break;
+ }
+ if (first > 0) {
+ strncpy(bptr, binhex + (4 - first), first);
+ bptr += first;
+ first = 0;
+ }
+ else {
+ strcpy(bptr, binhex);
+ bptr += 4;
+ }
+ hptr++;
+ }
+ return bitstring;
+}
+
+/*----------------------------------------------------------------------*/
+/* Recursion callback function for each item in the cellrec properties */
+/* hash table */
+/*----------------------------------------------------------------------*/
+
+struct nlist *output_props(struct hashlist *p, void *cptr)
+{
+ char *propval = (char *)(p->ptr);
+ FILE *outf = (FILE *)cptr;
+
+ fprintf(outf, ".%s(%s),\n", p->name, propval);
+ return NULL;
+}
+
+/*--------------------------------------------------------------*/
+/* Find the idx'th component of a net name. This pulls the */
+/* single wire name out of an indexed or concatenated array. */
+/* */
+/* Note that this routine does not handle nested braces. */
+/*--------------------------------------------------------------*/
+
+char *GetIndexedNet(char *netname, int ridx, struct cellrec *topcell)
+{
+ int i, alen, idx;
+ struct netrec wb;
+ char *sptr, *pptr, savc, *bptr;
+ static char *subname = NULL;
+ if (subname == NULL) subname = (char *)malloc(1);
+
+ if (*netname == '{') {
+ sptr = netname + 1;
+ i = 0;
+ while (i <= ridx) {
+ /* Advance to next comma or close-brace */
+ pptr = strchr(sptr, ',');
+ if (pptr == NULL) pptr = strchr(sptr, '}');
+ if (pptr == NULL) pptr = sptr + strlen(sptr) - 1;
+
+ savc = *pptr;
+ *pptr = '\0';
+
+ /* Does the array component at sptr have array bounds? */
+ GetBus(sptr, &wb, &topcell->nets);
+ if (wb.start != -1) {
+ alen = (wb.start - wb.end);
+ if (alen < 0) alen = -alen;
+ if (i + alen < ridx)
+ i += alen;
+ else {
+ if (wb.start < wb.end) idx = wb.start + (ridx - i);
+ else idx = wb.start - (ridx - i);
+ bptr = strrchr(sptr, '[');
+ if (bptr != NULL) *bptr = '\0';
+ subname = (char *)realloc(subname, strlen(sptr) + 10);
+ sprintf(subname, "%s[%d]", sptr, idx);
+ i = ridx;
+ if (bptr != NULL) *bptr = '[';
+ }
+ }
+ else {
+ if (i == ridx) {
+ subname = (char *)realloc(subname, strlen(sptr) + 1);
+ sprintf(subname, "%s", sptr);
+ }
+ i++;
+ }
+ *pptr = savc;
+ }
+ }
+ else {
+ GetBus(netname, &wb, &topcell->nets);
+ idx = (wb.start > wb.end) ? (wb.start - ridx) : (wb.start + ridx);
+ bptr = strrchr(netname, '[');
+ if (bptr != NULL) *bptr = '\0';
+
+ subname = (char *)realloc(subname, strlen(netname) + 10);
+ sprintf(subname, "%s[%d]", netname, idx);
+ if (bptr != NULL) *bptr = '[';
+ }
+ return subname;
+}
+
+/*--------------------------------------------------------------*/
+/* write_output */
+/* */
+/* ARGS: */
+/* RETURNS: 1 to OS */
+/* SIDE EFFECTS: */
+/*--------------------------------------------------------------*/
+
+int write_output(struct cellrec *topcell, unsigned char Flags, char *outname)
+{
+ FILE *outfptr = stdout;
+ int result = 0;
+ int nunconn = 0;
+ int arrayidx = -1;
+
+ GATE gate = (GATE)NULL;
+
+ struct netrec *net;
+ struct portrec *port;
+ struct instance *inst;
+
+ if (outname != NULL) {
+ outfptr = fopen(outname, "w");
+ if (outfptr == NULL) {
+ fprintf(stderr, "Error: Cannot open file %s for writing.\n", outname);
+ return 1;
+ }
+ }
+
+ /* Write output module header */
+ fprintf(outfptr, "/* Verilog module written by vlog2Verilog (qflow) */\n");
+
+ if (Flags & IMPLICIT_POWER)
+ fprintf(outfptr, "/* With explicit power connections */\n");
+ if (!(Flags & MAINTAIN_CASE))
+ fprintf(outfptr, "/* With case-insensitive names (SPICE-compatible) */\n");
+ if (Flags & BIT_BLAST)
+ fprintf(outfptr, "/* With bit-blasted vectors */\n");
+ if (Flags & NONAME_POWER)
+ fprintf(outfptr, "/* With power connections converted to binary 1, 0 */\n");
+ fprintf(outfptr, "\n");
+
+ fprintf(outfptr, "module %s(\n", topcell->name);
+
+ if (Flags & IMPLICIT_POWER) {
+ fprintf(outfptr, " inout %s,\n", VddNet);
+ fprintf(outfptr, " inout %s,\n", GndNet);
+ }
+
+ for (port = topcell->portlist; port; port = port->next) {
+ if (port->name == NULL) continue;
+ switch(port->direction) {
+ case PORT_INPUT:
+ fprintf(outfptr, " input ");
+ break;
+ case PORT_OUTPUT:
+ fprintf(outfptr, " output ");
+ break;
+ case PORT_INOUT:
+ fprintf(outfptr, " inout ");
+ break;
+ }
+ net = HashLookup(port->name, &topcell->nets);
+ if (net && net->start >= 0 && net->end >= 0) {
+ fprintf(outfptr, "[%d:%d] ", net->start, net->end);
+ }
+ fprintf(outfptr, "%s", port->name);
+ if (port->next) fprintf(outfptr, ",");
+ fprintf(outfptr, "\n");
+ }
+ fprintf(outfptr, ");\n\n");
+
+ /* Declare all wires */
+
+ if (!(Flags & IMPLICIT_POWER) && !(Flags & NONAME_POWER)) {
+ fprintf(outfptr, "wire %s = 1'b1;\n", VddNet);
+ fprintf(outfptr, "wire %s = 1'b0;\n\n", GndNet);
+ }
+
+ RecurseHashTablePointer(&topcell->nets, output_wires, outfptr);
+ fprintf(outfptr, "\n");
+
+ /* Write instances in the order of the input file */
+
+ for (inst = topcell->instlist; inst; ) {
+ int nprops = RecurseHashTable(&inst->propdict, CountHashTableEntries);
+ fprintf(outfptr, "%s ", inst->cellname);
+ if (nprops > 0) {
+ fprintf(outfptr, "#(\n");
+ RecurseHashTablePointer(&inst->propdict, output_props, outfptr);
+ fprintf(outfptr, ") ");
+ }
+ if (inst->cellname)
+ fprintf(outfptr, "%s", inst->instname);
+ else {
+ fprintf(outfptr, "vlog2Verilog: No cell for instance %s\n", inst->instname);
+ result = 1; // Set error result but continue output.
+ }
+ if (inst->arraystart != -1) {
+ if (Flags & BIT_BLAST) {
+ if (arrayidx == -1) arrayidx = inst->arraystart;
+ fprintf(outfptr, "[%d]", arrayidx);
+ }
+ else {
+ fprintf(outfptr, " [%d:%d]", inst->arraystart, inst->arrayend);
+ }
+ }
+ fprintf(outfptr, " (\n");
+
+ // If there is a gate record read from LEF, keep a pointer to it.
+ if (GateInfo != NULL)
+ gate = (GATE)HashLookup(inst->cellname, &Lefhash);
+
+ if (Flags & IMPLICIT_POWER) {
+
+ /* If any LEF files were read, then get the power and */
+ /* ground net names from the LEF file definition. */
+
+ if (gate) {
+ int n;
+ u_char found = 0;
+ for (n = 0; n < gate->nodes; n++) {
+ if (gate->use[n] == PORT_USE_POWER) {
+ fprintf(outfptr, " .%s(%s),\n", gate->node[n], VddNet);
+ found++;
+ }
+ else if (gate->use[n] == PORT_USE_GROUND) {
+ fprintf(outfptr, " .%s(%s),\n", gate->node[n], GndNet);
+ found++;
+ }
+ if (found == 2) break;
+ }
+ }
+ else {
+ /* Fall back on VddNet and GndNet names */
+ fprintf(outfptr, " .%s(%s),\n", GndNet, GndNet);
+ fprintf(outfptr, " .%s(%s),\n", VddNet, VddNet);
+ }
+ }
+
+ /* Write each port and net connection */
+ for (port = inst->portlist; port; port = port->next) {
+
+ /* If writing explicit power net names, then watch */
+ /* for power connections encoded as binary, and */
+ /* convert them to the power bus names. */
+
+ if ((Flags & IMPLICIT_POWER) || (!(Flags & NONAME_POWER))) {
+ int brepeat = 0;
+ char is_array = FALSE, saveptr;
+ char *sptr = port->net, *nptr;
+ char *expand = (char *)malloc(1);
+
+ *expand = '\0';
+ if (*sptr == '{') {
+ is_array = TRUE;
+ sptr++;
+ expand = (char *)realloc(expand, 2);
+ strcpy(expand, "{");
+ }
+ while ((*sptr != '}') && (*sptr != '\0')) {
+ int nest = 0;
+
+ nptr = sptr + 1;
+ while ((*nptr != '\0') && (*nptr != ',')) {
+ if (*nptr == '{') nest++;
+ if (*nptr == '}') {
+ if (nest == 0) break;
+ else nest--;
+ }
+ nptr++;
+ }
+ saveptr = *nptr;
+ *nptr = '\0';
+
+ if (isdigit(*sptr) || (*sptr == '\'')) {
+ char *bptr = sptr;
+ if (sscanf(bptr, "%d", &brepeat) == 0) brepeat = -1;
+ while (isdigit(*bptr)) bptr++;
+
+ /* Is digit followed by "'" (fixed values 1 or 0)? */
+
+ if (*bptr == '\'') {
+ char *bitstring;
+ bptr++;
+
+ /* Important note: Need to check if 'x' is */
+ /* on an output, in which case it should be */
+ /* treated like 'z' (unconnected). */
+
+ /* Ports in verilog instances have no */
+ /* direction information so it is necessary */
+ /* to pull the information from the LEF */
+ /* record of the cell. */
+
+ if (gate) {
+ int n;
+ for (n = 0; n < gate->nodes; n++) {
+ if (!strcmp(gate->node[n], port->name)) {
+ switch (gate->direction[n]) {
+ case PORT_CLASS_INPUT:
+ port->direction = PORT_INPUT;
+ break;
+ case PORT_CLASS_OUTPUT:
+ port->direction = PORT_OUTPUT;
+ break;
+ default:
+ port->direction = PORT_INOUT;
+ break;
+ }
+ break;
+ }
+ }
+ }
+
+ if (port->direction != PORT_INPUT) {
+ char *xptr;
+ for (xptr = bptr; *xptr != '\0'; xptr++) {
+ if ((*xptr == 'X') || (*xptr == 'x'))
+ *xptr = 'z';
+ }
+ }
+
+ switch(*bptr) {
+ case 'd':
+ bitstring = dec2binary(bptr + 1, brepeat);
+ break;
+ case 'h':
+ bitstring = hex2binary(bptr + 1, brepeat);
+ break;
+ case 'o':
+ bitstring = oct2binary(bptr + 1, brepeat);
+ break;
+ default:
+ bitstring = strdup(bptr + 1);
+ break;
+ }
+
+ if (brepeat < 0) brepeat = strlen(bitstring);
+
+ if ((brepeat > 1) && (is_array == FALSE)) {
+ is_array = TRUE;
+ expand = (char *)realloc(expand, strlen(expand) + 2);
+ strcat(expand, "{");
+ }
+
+ bptr = bitstring;
+ while (*bptr != '\0') {
+ if (*bptr == '1') {
+ expand = (char *)realloc(expand,
+ strlen(expand) +
+ strlen(VddNet) + 2);
+ strcat(expand, VddNet);
+ }
+ else if (tolower(*bptr) == 'z') {
+ char unconnect[20];
+ /* Unconnected node: Make a new node name. */
+ /* This is a single bit, so it can be */
+ /* implicitly declared. */
+ sprintf(unconnect, "\\$_unconn_%d_ ", nunconn++);
+ expand = (char *)realloc(expand,
+ strlen(expand) + strlen(unconnect)
+ + 1);
+ strcat(expand, unconnect);
+ }
+ else { /* Note: If 'X', then ground it */
+ expand = (char *)realloc(expand,
+ strlen(expand) +
+ strlen(GndNet) + 2);
+ strcat(expand, GndNet);
+ }
+ brepeat--;
+ if (brepeat > 0)
+ strcat(expand, ",");
+ bptr++;
+ if (brepeat <= 0) break;
+ }
+ if (bptr == bitstring) {
+ fprintf(stderr, "Warning: Cannot parse \"%s\"\n", sptr);
+ }
+ while (brepeat > 0) {
+ if ((bptr > bitstring) && (*(bptr - 1) == '1')) {
+ expand = (char *)realloc(expand,
+ strlen(expand) +
+ strlen(VddNet) + 2);
+ strcat(expand, VddNet);
+ }
+ else { /* Note: If 'X', then ground it */
+ expand = (char *)realloc(expand,
+ strlen(expand) +
+ strlen(GndNet) + 2);
+ strcat(expand, GndNet);
+ }
+ brepeat--;
+ if (brepeat > 0)
+ strcat(expand, ",");
+ }
+ free(bitstring);
+ }
+
+ /* Otherwise add to "expand" verbatim */
+ else {
+ expand = (char *)realloc(expand, strlen(expand) +
+ strlen(sptr) + 1);
+ strcat(expand, sptr);
+ }
+ }
+ else {
+ /* Normal net name, add to "expand" */
+ expand = (char *)realloc(expand, strlen(expand) +
+ strlen(sptr) + 1);
+ strcat(expand, sptr);
+ }
+ if (saveptr == ',') {
+ expand = (char *)realloc(expand, strlen(expand) + 2);
+ strcat(expand, ",");
+ }
+ *nptr = saveptr;
+ sptr = nptr;
+ if (saveptr != '\0') sptr++;
+ }
+
+ if (is_array) {
+ expand = (char *)realloc(expand, strlen(expand) + 2);
+ strcat(expand, "}");
+ }
+
+ /* Replace port->net */
+
+ free(port->net);
+ port->net = expand;
+ }
+ fprintf(outfptr, " .%s(", port->name);
+ if ((Flags & BIT_BLAST) && (arrayidx != -1)) {
+ /* Find the index from the start and pull that item from port->net */
+ int ridx;
+ ridx = arrayidx - inst->arraystart;
+ if (ridx < 0) ridx = -ridx;
+ fprintf(outfptr, "%s", GetIndexedNet(port->net, ridx, topcell));
+ }
+ else
+ fprintf(outfptr, "%s", port->net);
+ fprintf(outfptr, ")");
+ if (port->next) fprintf(outfptr, ",");
+ fprintf(outfptr, "\n");
+ }
+ fprintf(outfptr, ");\n\n");
+
+ /* For bit-blasted output, output each element of an array separately. */
+ if (Flags & BIT_BLAST) {
+ if (arrayidx == inst->arrayend) {
+ inst = inst->next;
+ arrayidx = -1;
+ }
+ else if (arrayidx < inst->arrayend)
+ arrayidx++;
+ else if (arrayidx > inst->arrayend)
+ arrayidx--;
+ }
+ else
+ inst = inst->next;
+ }
+
+ if (Flags & ADD_ANTENNA) {
+ char *antennapin = NULL;
+ GATE gate, acell = NULL;
+ double asize;
+
+ /* Find the cell name that matches the antenna cell */
+ /* Can't use the hash table here because name may be a */
+ /* prefix. If more than one cell matches by prefix, */
+ /* then use the cell with the smallest area. */
+
+ for (gate = GateInfo; gate; gate = gate->next) {
+ if (!strncmp(gate->gatename, AntennaCell, strlen(AntennaCell))) {
+ if (!strcmp(gate->gatename, AntennaCell)) {
+ acell = gate;
+ break;
+ }
+ else if (acell == NULL) {
+ acell = gate;
+ }
+ else {
+ if (gate->width < acell->width) {
+ acell = gate;
+ }
+ }
+ }
+ }
+
+ if (acell) {
+ int i;
+ /* Find the node that isn't a power pin */
+ for (i = 0; i < acell->nodes; i++) {
+ if (acell->use[i] != PORT_USE_POWER &&
+ acell->use[i] != PORT_USE_GROUND) {
+ antennapin = acell->node[i];
+ break;
+ }
+ }
+ }
+
+ if (antennapin) {
+ int antcnt = 0;
+
+ /* Add antenna cells to all module inputs */
+
+ for (port = topcell->portlist; port; port = port->next) {
+ if (port->name == NULL) continue;
+ switch(port->direction) {
+ case PORT_INPUT:
+ fprintf(outfptr, "%s antenna_%d ", acell->gatename, antcnt);
+
+ net = HashLookup(port->name, &topcell->nets);
+ if (net && net->start >= 0 && net->end >= 0) {
+ fprintf(outfptr, "[%d:%d] ", net->start, net->end);
+ }
+
+ fprintf(outfptr, "(\n");
+ fprintf(outfptr, " .%s(%s)\n", antennapin, port->name);
+ fprintf(outfptr, ");\n\n");
+ antcnt++;
+ break;
+ }
+ }
+ }
+ }
+
+ /* End the module */
+ fprintf(outfptr, "endmodule\n");
+
+ if (outname != NULL) fclose(outfptr);
+
+ fflush(stdout);
+ return result;
+}
+
+/*--------------------------------------------------------------*/
+/* C helpmessage - tell user how to use the program */
+/* */
+/* ARGS: */
+/* RETURNS: 1 to OS */
+/* SIDE EFFECTS: */
+/*--------------------------------------------------------------*/
+
+void helpmessage(FILE *outf)
+{
+ fprintf(outf, "vlog2Verilog [-options] <netlist>\n");
+ fprintf(outf, "\n");
+ fprintf(outf, "vlog2Verilog converts a netlist in one verilog style to\n");
+ fprintf(outf, "another. LEF files may be given as inputs to determine\n");
+ fprintf(outf, "power and ground net names for cells.\n");
+ fprintf(outf, "\n");
+ fprintf(outf, "options:\n");
+ fprintf(outf, "\n");
+ fprintf(outf, " -h Print this message\n");
+ fprintf(outf, " -o <path> Set output filename (otherwise output is on stdout).\n");
+ fprintf(outf, " -p Don't add power nodes to instances\n");
+ fprintf(outf, " (only nodes present in the instance used)\n");
+ fprintf(outf, " -b Remove vectors (bit-blasted)\n");
+ fprintf(outf, " -c Case-insensitive output (SPICE compatible) \n");
+ fprintf(outf, " -n Convert power nets to binary 1 and 0\n");
+ fprintf(outf, " -a <name> Add antenna cells to module input pins.\n");
+ fprintf(outf, " -l <path> Read LEF file from <path>\n");
+ fprintf(outf, " -v <name> Use <name> for power net (default \"Vdd\")\n");
+ fprintf(outf, " -g <name> Use <name> for ground net (default \"Gnd\")\n");
+
+} /* helpmessage() */
+