1 /* "NETGEN", a netlist-specification tool for VLSI
2    Copyright (C) 1989, 1990   Massimo A. Sivilotti
3    Author's address: mass@csvax.cs.caltech.edu;
4                      Caltech 256-80, Pasadena CA 91125.
5 
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation (any version).
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file copying.  If not, write to
17 the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
18 
19 /* verilog.c -- Input for Verilog format (structural verilog only) */
20 
21 /* The verilog input is limited to "structural verilog", that is,	*/
22 /* verilog code that only defines inputs, outputs, local nodes (via the	*/
23 /* "wire" statement), and instanced modules.  All modules are read down	*/
24 /* to the point where either a module (1) does not conform to the	*/
25 /* requirements above, or (2) has no module definition, in which case	*/
26 /* it is treated as a "black box" subcircuit and therefore becomes a	*/
27 /* low-level device.  Because in verilog syntax all instances of a	*/
28 /* module repeat both the module pin names and the local connections,	*/
29 /* placeholders can be built without the need to redefine pins later,	*/
30 /* as must be done for formats like SPICE that don't declare pin names	*/
31 /* in an instance call.							*/
32 
33 /* Note that use of 1'b0 or 1'b1 and similar variants is prohibited;	*/
34 /* the structural netlist should either declare VSS and/or VDD as	*/
35 /* inputs, or use tie-high and tie-low standard cells.			*/
36 
37 /* Most verilog syntax has been captured below.  Still to do:  Handle	*/
38 /* vectors that are created on the fly using {...} notation, including	*/
39 /* the {n{...}} concatenation method.					*/
40 
41 #include "config.h"
42 
43 #include <stdio.h>
44 #include <stdlib.h>  /* for calloc(), free(), getenv() */
45 #ifndef IBMPC
46 #include <sys/types.h>	/* for getpwnam() tilde expansion */
47 #include <pwd.h>
48 #endif
49 
50 #ifdef TCL_NETGEN
51 #include <tcl.h>
52 #endif
53 
54 #include "netgen.h"
55 #include "objlist.h"
56 #include "netfile.h"
57 #include "print.h"
58 #include "hash.h"
59 
60 // See netfile.c for explanation of delimiters.  'X'
61 // separates single-character delimiters from two-character delimiters.
62 #define VLOG_DELIMITERS "X///**/#((**)X,;:(){}[]="
63 #define VLOG_PIN_NAME_DELIMITERS "X///**/(**)X()"
64 #define VLOG_PIN_CHECK_DELIMITERS "X///**/(**)X,;(){}"
65 
66 // Used by portelement structure "flags" record.
67 #define PORT_NOT_FOUND	0
68 #define PORT_FOUND	1
69 
70 // Global storage for verilog parameters
71 struct hashdict verilogparams;
72 // Global storage for verilog definitions
73 struct hashdict verilogdefs;
74 
75 // Global storage for wire buses
76 struct hashdict buses;
77 
78 struct bus {
79     int start;
80     int end;
81 };
82 
83 // Free a bus structure in the hash table during cleanup
84 
freebus(struct hashlist * p)85 int freebus (struct hashlist *p)
86 {
87     struct bus *wb;
88 
89     wb = (struct bus *)(p->ptr);
90     FREE(wb);
91     return 1;
92 }
93 
94 // Create a new bus structure
95 
NewBus()96 struct bus *NewBus()
97 {
98     struct bus *wb;
99 
100     wb = (struct bus *)CALLOC(1, sizeof(struct bus));
101     if (wb == NULL) Fprintf(stderr, "NewBus: Core allocation error\n");
102     return (wb);
103 }
104 
105 //-------------------------------------------------------------------------
106 // Find a character c in a string, assuming that string may contain
107 // verilog names, where anything, including char c, may appear in the
108 // string if it is a backslash-escaped name.  Only the position of
109 // character c outside of a verilog name is reported.
110 //-------------------------------------------------------------------------
111 
strvchr(char * string,char c)112 char *strvchr(char *string, char c)
113 {
114     char *s;
115 
116     for (s = string; *s != '\0'; s++) {
117 	if (*s == '\\') {
118 	    while (*s != '\0' && *s != ' ') s++;
119 	    if (*s == '\0') {
120 		Fprintf(stderr, "Error:  Verilog backslash-escaped name"
121 			" does not end with a space.\n");
122 		break;
123 	    }
124 	}
125 	if (*s == c) return s;
126     }
127     return NULL;
128 }
129 
130 //-------------------------------------------------------------------------
131 // Get bus indexes from the notation name[a:b].  If there is only "name"
132 // then look up the name in the bus hash list and return the index bounds.
133 // Return 0 on success, 1 on syntax error, and -1 if signal is not a bus.
134 //
135 // Note that this routine relies on the delimiter characters including
136 // "[", ":", and "]" when calling NextTok.
137 //-------------------------------------------------------------------------
138 
GetBusTok(struct bus * wb)139 int GetBusTok(struct bus *wb)
140 {
141     int result, start, end;
142     struct property *kl = NULL;
143 
144     if (wb == NULL) return 0;
145     else {
146         wb->start = -1;
147         wb->end = -1;
148     }
149 
150     if (match(nexttok, "[")) {
151 	SkipTokComments(VLOG_DELIMITERS);
152 
153 	result = sscanf(nexttok, "%d", &start);
154 	if (result != 1) {
155 	    char *aptr = NULL;
156 	    char addin;
157 
158 	    // Check for "+/-(n)" at end of a parameter name
159 	    aptr = strrchr(nexttok, '+');
160 	    if (aptr == NULL) aptr = strrchr(nexttok, '-');
161 	    if (aptr != NULL) {
162 		addin = *aptr;
163 		*aptr = '\0';
164 	    }
165 
166 	    // Is name in the parameter list?
167 	    kl = (struct property *)HashLookup(nexttok, &verilogparams);
168 	    if (kl == NULL) {
169 		Printf("Array value %s is not a number or a parameter.\n",
170 				nexttok);
171 		return 1;
172 	    }
173 	    else {
174 		if (kl->type == PROP_STRING) {
175 		    result = sscanf(kl->pdefault.string, "%d", &start);
176 		    if (result != 1) {
177 		        Printf("Parameter %s has value %s that cannot be parsed"
178 				" as an integer.\n", nexttok, kl->pdefault.string);
179 			return 1;
180 		    }
181 		}
182 		else if (kl->type == PROP_INTEGER) {
183 		    start = kl->pdefault.ival;
184 		}
185 		else if (kl->type == PROP_DOUBLE) {
186 		    start = (int)kl->pdefault.dval;
187 		    if ((double)start != kl->pdefault.dval) {
188 		        Printf("Parameter %s has value %g that cannot be parsed"
189 				" as an integer.\n", nexttok, kl->pdefault.dval);
190 			return 1;
191 		    }
192 		}
193 		else {
194 		    Printf("Parameter %s has unknown type; don't know how"
195 				" to parse.\n", nexttok);
196 		    return 1;
197 		}
198 	    }
199 	    if (aptr != NULL) {
200 		int addval;
201 		*aptr = addin;
202 		if (sscanf(aptr + 1, "%d", &addval) != 1) {
203 		    Printf("Unable to parse parameter increment '%s'\n", aptr);
204 		    return 1;
205 		}
206 		start += (addin == '+') ? addval : -addval;
207 	    }
208 	}
209 	SkipTokComments(VLOG_DELIMITERS);
210 	if (match(nexttok, "]")) {
211 	    result = 1;
212 	    end = start;	// Single bit
213 	}
214 	else if (!match(nexttok, ":")) {
215 	    Printf("Badly formed array notation:  Expected colon, found %s\n", nexttok);
216 	    return 1;
217 	}
218 	else {
219 	    SkipTokComments(VLOG_DELIMITERS);
220 
221 	    result = sscanf(nexttok, "%d", &end);
222 	    if (result != 1) {
223 		char *aptr = NULL;
224 		char addin;
225 
226 		// Check for "+/-(n)" at end of a parameter name
227 		aptr = strrchr(nexttok, '+');
228 		if (aptr == NULL) aptr = strrchr(nexttok, '-');
229 		if (aptr != NULL) {
230 		    addin = *aptr;
231 		    *aptr = '\0';
232 		}
233 
234 		// Is name in the parameter list?
235 	        kl = (struct property *)HashLookup(nexttok, &verilogparams);
236 		if (kl == NULL) {
237 		    Printf("Array value %s is not a number or a parameter.\n",
238 					nexttok);
239 		    return 1;
240 		}
241 		else {
242 		    if (kl->type == PROP_STRING) {
243 			result = sscanf(kl->pdefault.string, "%d", &end);
244 			if (result != 1) {
245 		            Printf("Parameter %s has value %s that cannot be parsed"
246 					" as an integer.\n", nexttok,
247 					kl->pdefault.string);
248 			    return 1;
249 			}
250 		    }
251 		    else if (kl->type == PROP_INTEGER) {
252 			end = kl->pdefault.ival;
253 		    }
254 		    else if (kl->type == PROP_DOUBLE) {
255 		        end = (int)kl->pdefault.dval;
256 		        if ((double)end != kl->pdefault.dval) {
257 			    Printf("Cannot parse second digit from parameter "
258 					"%s value %g\n", nexttok, kl->pdefault.dval);
259 			    return 1;
260 			}
261 		    }
262 		    else {
263 		        Printf("Parameter %s has unknown type; don't know how"
264 					" to parse.\n", nexttok);
265 		        return 1;
266 		    }
267 		}
268 		if (aptr != NULL) {
269 		    int addval;
270 		    *aptr = addin;
271 		    if (sscanf(aptr + 1, "%d", &addval) != 1) {
272 			Printf("Unable to parse parameter increment '%s'\n", aptr);
273 			return 1;
274 		    }
275 		    end += (addin == '+') ? addval : -addval;
276 		}
277 	    }
278 	}
279 	wb->start = start;
280 	wb->end = end;
281 
282 	while (!match(nexttok, "]")) {
283 	    SkipTokComments(VLOG_DELIMITERS);
284 	    if (nexttok == NULL) {
285 		Printf("End of file reached while reading array bounds.\n");
286 		return 1;
287 	    }
288 	    else if (match(nexttok, ";")) {
289 		// Better than reading to end-of-file, give up on end-of-statement
290 		Printf("End of statement reached while reading array bounds.\n");
291 		return 1;
292 	    }
293 	}
294     }
295     else {
296 	struct bus *hbus;
297 	hbus = (struct bus *)HashLookup(nexttok, &buses);
298 	if (hbus != NULL) {
299 	    wb->start = hbus->start;
300 	    wb->end = hbus->end;
301 	}
302 	else
303 	    return -1;
304     }
305     return 0;
306 }
307 
308 //--------------------------------------------------------------------
309 // GetBus() is similar to GetBusTok() (see above), but it parses from
310 // a string instead of the input tokenizer.
311 //--------------------------------------------------------------------
312 
GetBus(char * astr,struct bus * wb)313 int GetBus(char *astr, struct bus *wb)
314 {
315     char *colonptr, *brackstart, *brackend, *sigend, sdelim, *aastr;
316     int result, start, end;
317 
318     if (wb == NULL) return 0;
319     else {
320         wb->start = -1;
321         wb->end = -1;
322     }
323 
324     /* Check for wire bundles.  If there are bundles, process each  */
325     /* section separately and concatenate the sizes.		    */
326     /* To be done:  Handle nested bundles, including N-times concatenation */
327 
328     if (*astr == '{') {
329 	struct bus wbb;
330 
331 	astr++;
332 	wb->end = 0;
333 	while((*astr != '\0') && (*astr != '}')) {
334 	    sigend = strvchr(astr, ',');
335 	    if (sigend == NULL) sigend = strvchr(astr, '}');
336 	    if (sigend == NULL) {
337 		Printf("Badly formed wire bundle \"%s\"\n", astr - 1);
338 		return 1;
339 	    }
340 	    sdelim = *sigend;
341 	    *sigend = '\0';
342 	    if (GetBus(astr, &wbb) == 0) {
343 		if (wbb.start > wbb.end)
344 		    wb->start += (wbb.start - wbb.end + 1);
345 		else
346 		    wb->start += (wbb.end - wbb.start + 1);
347 	    }
348 	    else {
349 		wb->start++;
350 	    }
351 	    *sigend = sdelim;
352 	    astr = sigend + 1;
353 	}
354 	return 0;
355     }
356 
357     // Delimiters may appear in backslash-escaped names. . . ignore these.
358     aastr = astr;
359     if (*aastr == '\\') {
360 	aastr++;
361 	while (*aastr != ' ' && *aastr != '\\' && *aastr != '\0') aastr++;
362     }
363 
364     brackstart = strvchr(aastr, '[');
365     if (brackstart != NULL) {
366 	brackend = strvchr(aastr, ']');
367 	if (brackend == NULL) {
368 	    Printf("Badly formed array notation \"%s\"\n", astr);
369 	    return 1;
370 	}
371 	*brackend = '\0';
372 	colonptr = strvchr(aastr, ':');
373 	if (colonptr) *colonptr = '\0';
374 	result = sscanf(brackstart + 1, "%d", &start);
375 	if (colonptr) *colonptr = ':';
376 	if (result != 1) {
377 	    Printf("Badly formed array notation \"%s\"\n", astr);
378 	    *brackend = ']';
379 	    return 1;
380 	}
381 	if (colonptr)
382 	    result = sscanf(colonptr + 1, "%d", &end);
383 	else {
384 	    result = 1;
385 	    end = start;        // Single bit
386 	}
387 	*brackend = ']';
388 	if (result != 1) {
389 	    Printf("Badly formed array notation \"%s\"\n", astr);
390 	    return 1;
391 	}
392 	wb->start = start;
393 	wb->end = end;
394     }
395     else {
396 	struct bus *hbus;
397 	hbus = (struct bus *)HashLookup(astr, &buses);
398 	if (hbus != NULL) {
399 	    wb->start = hbus->start;
400 	    wb->end = hbus->end;
401 	}
402 	else
403 	    return -1;
404     }
405     return 0;
406 }
407 
408 // Output a Verilog Module.  Note that since Verilog does not describe
409 // low-level devices like transistors, capacitors, etc., then this
410 // format is limited to black-box subcircuits.  Cells containing any
411 // such low-level devices are ignored.
412 
VerilogModule(struct nlist * tp)413 void VerilogModule(struct nlist *tp)
414 {
415   struct objlist *ob, *mob;
416   int node, maxnode;
417   char *model;
418   struct tokstack *stackptr;
419 
420   /* 1st pass:  traverse list of objects for low-level device checks */
421 
422   for (ob = tp->cell; ob != NULL; ob = ob->next) {
423      if (ob->type == FIRSTPIN) {
424 	struct nlist *tp2;
425 
426 	tp2 = LookupCellFile(ob->model.class, tp->file);
427 
428 	/* Check the class.  Low-level devices cause the	*/
429 	/* routine to return without generating output.		*/
430 
431 	switch (tp2->class) {
432 	   case CLASS_NMOS4: case CLASS_PMOS4: case CLASS_FET4:
433 	   case CLASS_NMOS: case CLASS_PMOS: case CLASS_FET3:
434 	   case CLASS_FET: case CLASS_ECAP:
435 	   case CLASS_NPN: case CLASS_PNP: case CLASS_BJT:
436 	   case CLASS_RES: case CLASS_RES3:
437 	   case CLASS_DIODE: case CLASS_INDUCTOR:
438 	   case CLASS_CAP: case CLASS_CAP3:
439 	   case CLASS_XLINE:
440 	      return;
441 	   case CLASS_SUBCKT: case CLASS_MODULE:
442 	      break;
443 	   default:
444 	      Printf ("Bad device class \"%s\" found.\n", tp2->class);
445 	      break;		/* ignore it. . . */
446 	}
447      }
448   }
449 
450   /* Check to see that all children have been dumped first */
451 
452   for (ob = tp->cell; ob != NULL; ob = ob->next) {
453     if (ob->type == FIRSTPIN) {
454       struct nlist *tp2;
455 
456       tp2 = LookupCellFile(ob->model.class, tp->file);
457       if ((tp2 != NULL) && !(tp2->dumped) && (tp2->class == CLASS_SUBCKT))
458 	VerilogModule(tp2);
459     }
460   }
461 
462   /* Print module pin list */
463 
464   FlushString("module %s (\n",tp->name);
465   for (ob = tp->cell; ob != NULL; ob = ob->next)
466       if (IsPortInPortlist(ob, tp)) FlushString("input %s,\n", ob->name);
467   FlushString(");\n");
468 
469   /* Print names of all nodes as 'wire' statements */
470 
471   maxnode = 0;
472   for (ob = tp->cell; ob != NULL; ob = ob->next)
473     if (ob->node > maxnode) maxnode = ob->node;
474 
475   /* was:  for (node = 0; node <= maxnode; node++)  */
476   for (node = 1; node <= maxnode; node++)
477     FlushString("   wire %s;\n", NodeName(tp, node));
478 
479   /* 2nd pass:  traverse list of objects for output */
480 
481   for (ob = tp->cell; ob != NULL; ob = ob->next) {
482      if (ob->type == FIRSTPIN) {
483         int drain_node, gate_node, source_node;
484 	struct nlist *tp2;
485 
486 	tp2 = LookupCellFile(ob->model.class, tp->file);
487 	model = tp2->name;
488 
489 	/* Check the class.  Low-level devices cause the routine to	*/
490 	/* return value 1 (don't output).				*/
491 
492 	switch (tp2->class) {
493 	   case CLASS_SUBCKT: case CLASS_MODULE:
494 	      break;
495 	   default:
496 	      Printf ("Bad device class found.\n");
497 	      continue;		/* ignore it. . . */
498 	}
499 
500         FlushString("%s %s (\n", model, ob->instance.name);
501 
502         /* Print out nodes.  */
503 
504 	mob = tp2->cell;
505 	while (ob) {
506 	   if (ob->type >= FIRSTPIN)
507               FlushString(".%s(%s),\n", mob->name, ob->name);
508            ob = ob->next;
509            mob = mob->next;
510 	   if (ob->next && ob->next->type <= FIRSTPIN) break;
511 	}
512         FlushString(");\n", model, ob->instance.name);
513      }
514   }
515 
516   FlushString("endmodule\n");
517   tp->dumped = 1;
518 }
519 
520 /* Write a Verilog module (top-level routine) */
521 
VerilogTop(char * name,int fnum,char * filename)522 void VerilogTop(char *name, int fnum, char *filename)
523 {
524   struct nlist *tp;
525   char FileName[500];
526 
527   tp = LookupCellFile(name, fnum);
528 
529   if (tp == NULL) {
530     Printf ("No cell '%s' found.\n", name);
531     return;
532   }
533 
534   if (filename == NULL || strlen(filename) == 0)
535     SetExtension(FileName, name, VERILOG_EXTENSION);
536   else
537     SetExtension(FileName, filename, VERILOG_EXTENSION);
538 
539   if (!OpenFile(FileName, 80)) {
540     perror("write verilog: Unable to open output file.");
541     return;
542   }
543   ClearDumpedList();
544   /* Start with general information in comment lines at the top */
545   FlushString("/*\n");
546   FlushString(" * Verilog structural netlist for cell %s\n", name);
547   FlushString(" * Written by Netgen %s.%s\n\n", NETGEN_VERSION, NETGEN_REVISION);
548   FlushString(" */\n");
549   VerilogModule(tp);
550   CloseFile(FileName);
551 }
552 
553 /* If any pins are marked unconnected, see if there are	*/
554 /* other pins of the same name that have connections.	*/
555 
CleanupModule()556 void CleanupModule() {
557    int maxnode = 0;
558    int has_submodules = FALSE;
559    struct objlist *sobj, *nobj, *lobj, *pobj;
560    struct objlist *myLastPort, *object_it, *myNextObject;
561 
562    if (CurrentCell == NULL) return;
563 
564    myLastPort = NULL;
565 
566    /* Reorder objects so that all ports come first, before nodes, because
567     * parts of the code depend on it.
568     */
569 
570    for (object_it = CurrentCell->cell; object_it && object_it->type <= 0;
571 		object_it = myNextObject ) {
572 
573        myNextObject = object_it->next;
574        if (!myNextObject)	// end of list
575            continue;
576 
577        if (myLastPort == NULL) {
578            if (object_it->type == PORT) {
579                myLastPort = object_it;	    // port at begining of list
580                myNextObject = object_it;    // otherwise skips one
581            }
582            else if (myNextObject->type == PORT) {
583                object_it->next = myNextObject->next;
584                myNextObject->next = CurrentCell->cell;
585                CurrentCell->cell = myNextObject;
586                myLastPort = myNextObject;
587            }
588        }
589        else if (myNextObject->type == PORT) {
590 	   object_it->next = myNextObject->next;
591 	   myNextObject->next = myLastPort->next;
592 	   myLastPort->next = myNextObject;
593 	   myLastPort = myNextObject;
594        }
595    }
596 
597    for (sobj = CurrentCell->cell; sobj; sobj = sobj->next)
598       if (sobj->node > maxnode)
599 	 maxnode = sobj->node + 1;
600 
601    lobj = NULL;
602    for (sobj = CurrentCell->cell; sobj != NULL;) {
603       nobj = sobj->next;
604       if (sobj->type == FIRSTPIN)
605 	 has_submodules = TRUE;
606       if (sobj->node < 0) {
607 	 if (IsPort(sobj) && sobj->model.port == PROXY)
608 	    sobj->node = maxnode++;
609 	 else if (IsPort(sobj)) {
610 	    for (pobj = CurrentCell->cell; pobj && (pobj->type == PORT);
611 			pobj = pobj->next) {
612 	       if (pobj == sobj) continue;
613 	       if (match(pobj->name, sobj->name) && pobj->node >= 0) {
614 		  sobj->node = pobj->node;
615 		  break;
616 	       }
617 	    }
618 	    lobj = sobj;
619 	 }
620 	 else
621 	    lobj = sobj;
622       }
623       else
624          lobj = sobj;
625       sobj = nobj;
626    }
627    if (has_submodules == FALSE) SetClass(CLASS_MODULE);
628 
629    if (buses.hashtab != NULL) {
630       RecurseHashTable(&buses, freebus);
631       HashKill(&buses);
632    }
633 }
634 
635 /*------------------------------------------------------*/
636 /* Structure for stacking nested module definitions	*/
637 /*------------------------------------------------------*/
638 
639 /* Forward declarations */
640 extern void IncludeVerilog(char *, int, struct cellstack **, int);
641 
642 /* External declarations (from spice.c) */
643 extern void PushStack(char *cellname, struct cellstack **top);
644 extern void PopStack(struct cellstack **top);
645 
646 /*------------------------------------------------------*/
647 /* Read a verilog structural netlist			*/
648 /*------------------------------------------------------*/
649 
ReadVerilogFile(char * fname,int filenum,struct cellstack ** CellStackPtr,int blackbox)650 void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr,
651 		int blackbox)
652 {
653   int cdnum = 1, rdnum = 1, i, ival;
654   int warnings = 0, hasports, inlined_decls = 0, localcount = 1;
655   double dval;
656   char devtype, in_module, in_param;
657   char *eqptr, *matchptr;
658   struct keyvalue *kvlist = NULL;
659   char inst[256], model[256], instname[256], portname[256], pkey[256];
660   struct nlist *tp;
661   struct objlist *parent, *sobj, *nobj, *lobj, *pobj;
662 
663   inst[255] = '\0';
664   model[255] = '\0';
665   instname[255] = '\0';
666   in_module = (char)0;
667   in_param = (char)0;
668 
669   while (!EndParseFile()) {
670 
671     SkipTokComments(VLOG_DELIMITERS); /* get the next token */
672     if ((EndParseFile()) && (nexttok == NULL)) break;
673     else if (nexttok == NULL)
674       break;
675 
676     /* Ignore end-of-statement markers */
677     else if (match(nexttok, ";"))
678       continue;
679 
680     /* Ignore primitive definitions */
681     else if (match(nexttok, "primitive")) {
682 	while (1) {
683 	    SkipNewLine(VLOG_DELIMITERS);
684 	    SkipTokComments(VLOG_DELIMITERS);
685 	    if (EndParseFile()) break;
686 	    if (match(nexttok, "endprimitive")) {
687 	       in_module = 0;
688 	       break;
689 	    }
690 	}
691     }
692 
693     /* Handle parameters by treating as a localparam or definition.	*/
694     /* Currently anything other than a constant value is not handled	*/
695     /* and so will flag a warning.					*/
696 
697     else if (match(nexttok, "parameter") || match(nexttok, "localparam")) {
698 	char *paramkey = NULL;
699 	char *paramval = NULL;
700 
701 	// Pick up key = value pairs and store in current cell.  Look only
702 	// at the keyword before "=".  Then set the definition as everything
703 	// remaining in the line, excluding comments, until the end-of-statement
704 
705 	while (nexttok != NULL)
706 	{
707 	    struct property *kl = NULL;
708 
709 	    /* Parse for parameters used in expressions.  Save	*/
710 	    /* parameters in the "verilogparams" hash table.	*/
711 
712 	    SkipTok(VLOG_DELIMITERS);
713 	    if ((nexttok == NULL) || (nexttok[0] == '\0')) break;
714 	    if (match(nexttok, "=")) {
715 		/* Pick up remainder of statement */
716 		while (nexttok != NULL) {
717 		    SkipTokNoNewline("X///**/X;,");
718 		    if (nexttok == NULL) break;
719 		    if (match(nexttok, ";") || match(nexttok, ",")) break;
720 		    if (paramval == NULL) paramval = strsave(nexttok);
721 		    else {
722 			char *paramlast;
723 			/* Append nexttok to paramval */
724 			paramlast = paramval;
725 			paramval = (char *)MALLOC(strlen(paramlast) + strlen(nexttok)
726 				+ 2);
727 			sprintf(paramval, "%s %s", paramlast, nexttok);
728 			FREE(paramlast);
729 		    }
730 		}
731 
732 		kl = NewProperty();
733 		kl->key = strsave(paramkey);
734 		kl->idx = 0;
735 		kl->merge = MERGE_NONE;
736 
737 		if (ConvertStringToInteger(paramval, &ival) == 1) {
738 		    kl->type = PROP_INTEGER;
739 		    kl->slop.ival = 0;
740 		    kl->pdefault.ival = ival;
741 		}
742 		else if (ConvertStringToFloat(paramval, &dval) == 1) {
743 		    kl->type = PROP_DOUBLE;
744 		    kl->slop.dval = 0.01;
745 		    kl->pdefault.dval = dval;
746 		}
747 		else {
748 		    kl->type = PROP_STRING;
749 		    kl->slop.dval = 0.0;
750 		    kl->pdefault.string = strsave(paramval);
751 		}
752 
753 		HashPtrInstall(paramkey, kl, &verilogparams);
754 		FREE(paramval);
755 		paramval = NULL;
756 
757 		if ((nexttok == NULL) || match(nexttok, ";")) break;
758 	    }
759 	    else {
760 		if (paramkey != NULL) FREE(paramkey);
761 		paramkey = strsave(nexttok);
762 	    }
763 	}
764 	if (paramval != NULL) FREE(paramval);
765 	if (paramkey != NULL) FREE(paramkey);
766     }
767 
768     else if (match(nexttok, "module")) {
769       InitializeHashTable(&buses, OBJHASHSIZE);
770       SkipTokNoNewline(VLOG_DELIMITERS);
771       if (nexttok == NULL) {
772 	 Fprintf(stderr, "Badly formed \"module\" line\n");
773 	 goto skip_endmodule;
774       }
775 
776       if (in_module == (char)1) {
777 	  Fprintf(stderr, "Missing \"endmodule\" statement on subcircuit.\n");
778           InputParseError(stderr);
779       }
780       in_module = (char)1;
781 
782       /* Save pointer to current cell */
783       if (CurrentCell != NULL)
784          parent = CurrentCell->cell;
785       else
786 	 parent = NULL;
787 
788       /* Check for existence of the cell.  We may need to rename it. */
789 
790       snprintf(model, 99, "%s", nexttok);
791       tp = LookupCellFile(nexttok, filenum);
792 
793       /* Check for name conflict with duplicate cell names	*/
794       /* This may mean that the cell was used before it was	*/
795       /* defined, but CDL files sometimes just redefine the	*/
796       /* same cell over and over.  So check if it's empty.	*/
797 
798       if ((tp != NULL) && (tp->class != CLASS_MODULE)) {
799 	 int n;
800 	 char *ds;
801 
802 	 // NOTE:  Use this to ignore the new definition---should be
803 	 // an option to netgen.
804 	 /* goto skip_endmodule; */
805 
806 	 ds = strrchr(model, '[');
807 	 if ((ds != NULL) && (*(ds + 1) == '['))
808 	    sscanf(ds + 2, "%d", &n);
809 	 else {
810 	    ds = model + strlen(model);
811 	    sprintf(ds, "[[0]]");
812 	    n = -1;
813 	 }
814 
815 	 Printf("Duplicate cell %s in file\n", nexttok);
816 	 tp->flags |= CELL_DUPLICATE;
817          while (tp != NULL) {
818 	    n++;
819 	    /* Append "[[n]]" to the preexisting model name to force uniqueness */
820 	    sprintf(ds, "[[%d]]", n);
821             tp = LookupCellFile(model, filenum);
822 	 }
823 	 Printf("Renaming original cell to %s\n", model);
824 	 InstanceRename(nexttok, model, filenum);
825 	 CellRehash(nexttok, model, filenum);
826          CellDef(nexttok, filenum);
827          tp = LookupCellFile(nexttok, filenum);
828       }
829       else if (tp != NULL) {	/* Make a new definition for an empty cell */
830 	 FreePorts(nexttok);
831 	 CellDelete(nexttok, filenum);	/* This removes any PLACEHOLDER flag */
832 	 CellDef(model, filenum);
833 	 tp = LookupCellFile(model, filenum);
834       }
835       else if (tp == NULL) {	/* Completely new cell, no name conflict */
836          CellDef(model, filenum);
837          tp = LookupCellFile(model, filenum);
838       }
839 
840       hasports = (char)0;
841       inlined_decls = (char)0;
842 
843       if (tp != NULL) {
844 	 struct bus wb, *nb;
845 
846 	 PushStack(tp->name, CellStackPtr);
847 
848 	 /* Need to support both types of I/O lists:  Those	*/
849 	 /* that declare names only in the module list and	*/
850 	 /* follow with input/output and vector size		*/
851 	 /* declarations as individual statements in the module	*/
852 	 /* definition, and those which declare everything	*/
853 	 /* inside the pin list.				*/
854 
855          SkipTokComments(VLOG_DELIMITERS);
856 
857 	 // Check for parameters within #( ... )
858 
859 	 if (match(nexttok, "#(")) {
860 	    SkipTokComments(VLOG_DELIMITERS);
861 	    in_param = (char)1;
862 	 }
863 	 else if (match(nexttok, "(")) {
864 	    SkipTokComments(VLOG_DELIMITERS);
865 	 }
866 
867 	 wb.start = wb.end = -1;
868          while ((nexttok != NULL) && !match(nexttok, ";")) {
869 	    if (in_param) {
870 		if (match(nexttok, ")")) {
871 		    in_param = (char)0;
872 		    SkipTokComments(VLOG_DELIMITERS);
873 		    if (!match(nexttok, "(")) {
874 		        Fprintf(stderr, "Badly formed module block parameter list.\n");
875 		        goto skip_endmodule;
876 		    }
877 		}
878 		else if (match(nexttok, "=")) {
879 
880 		    // The parameter value is the next token.
881 		    SkipTokComments(VLOG_DELIMITERS); /* get the next token */
882 		    eqptr = nexttok;
883 
884 		    // Try first as a double, otherwise it's a string
885 		    // Double value's slop defaults to 1%.
886 		    if (ConvertStringToFloat(eqptr, &dval) == 1)
887 		        PropertyDouble(tp->name, filenum, pkey, 0.01, dval);
888 		    else
889 			PropertyString(tp->name, filenum, pkey, 0, eqptr);
890 		}
891 		else {
892 		    /* Assume this is a keyword and save it */
893 		    strcpy(pkey, nexttok);
894 		}
895 	    }
896 	    else if (!match(nexttok, ",")) {
897 	        if (match(nexttok, ")")) break;
898 		// Ignore input, output, and inout keywords, and handle buses.
899 
900 		if (inlined_decls == (char)0) {
901 		    if (match(nexttok, "input") || match(nexttok, "output") ||
902 				match(nexttok, "inout"))
903 			inlined_decls = (char)1;
904 		}
905 		else {
906 		    if (!match(nexttok, "input") && !match(nexttok, "output") &&
907 				!match(nexttok, "inout") && !match(nexttok, "real") &&
908 				!match(nexttok, "wire") && !match(nexttok, "logic") &&
909 				!match(nexttok, "integer")) {
910 			if (match(nexttok, "[")) {
911 			   if (GetBusTok(&wb) != 0) {
912 			      // Didn't parse as a bus, so wing it
913 			      wb.start = wb.end = -1;
914 			      Port(nexttok);
915 			   }
916 			}
917 			else {
918 			   if (wb.start != -1) {
919 			      if (wb.start > wb.end) {
920 				 for (i = wb.start; i >= wb.end; i--) {
921 				    sprintf(portname, "%s[%d]", nexttok, i);
922 				    Port(portname);
923 				 }
924 			      }
925 			      else {
926 				 for (i = wb.start; i <= wb.end; i++) {
927 				    sprintf(portname, "%s[%d]", nexttok, i);
928 				    Port(portname);
929 				 }
930 			      }
931 			      /* Also register this port as a bus */
932 			      nb = NewBus();
933 			      nb->start = wb.start;
934 			      nb->end = wb.end;
935 			      HashPtrInstall(nexttok, nb, &buses);
936 
937 			      wb.start = wb.end = -1;
938 			   }
939 			   else {
940 			      Port(nexttok);
941 			   }
942 			}
943 		        hasports = 1;
944 		    }
945 		}
946 	    }
947 	    SkipTokComments(VLOG_DELIMITERS);
948 	    if (nexttok == NULL) break;
949          }
950 	 SetClass((blackbox) ? CLASS_MODULE : CLASS_SUBCKT);
951 
952 	 if (inlined_decls == 1) {
953 	    if (hasports == 0)
954 		// If the cell defines no ports, then create a proxy
955 		Port((char *)NULL);
956 
957 	    /* In the blackbox case, don't read the cell contents	*/
958 	    if (blackbox) goto skip_endmodule;
959 	 }
960       }
961       else {
962 
963 skip_endmodule:
964 	 /* There was an error, so skip to the end of the	*/
965 	 /* subcircuit definition				*/
966 
967 	 while (1) {
968 	    SkipNewLine(VLOG_DELIMITERS);
969 	    SkipTokComments(VLOG_DELIMITERS);
970 	    if (EndParseFile()) break;
971 	    if (match(nexttok, "endmodule")) {
972 	       in_module = 0;
973 	       break;
974 	    }
975 	 }
976       }
977     }
978     else if (match(nexttok, "input") || match(nexttok, "output")
979 		|| match(nexttok, "inout")) {
980 	struct bus wb, *nb;
981 
982 	// Parsing of ports as statements not in the module pin list.
983 	wb.start = wb.end = -1;
984 	while (1) {
985 	    SkipTokComments(VLOG_DELIMITERS);
986 	    if (EndParseFile()) break;
987 
988 	    if (match(nexttok, ";")) {
989 		// End of statement
990 		break;
991 	    }
992 	    else if (match(nexttok, "[")) {
993 		if (GetBusTok(&wb) != 0) {
994 		    // Didn't parse as a bus, so wing it
995 		    wb.start = wb.end = -1;
996 		    Port(nexttok);
997 		}
998 	    }
999 	    else if (!match(nexttok, ",")) {
1000 		if (wb.start != -1) {
1001 		    if (wb.start > wb.end) {
1002 			for (i = wb.start; i >= wb.end; i--) {
1003 			    sprintf(portname, "%s[%d]", nexttok, i);
1004 			    Port(portname);
1005 			}
1006 		    }
1007 		    else {
1008 			for (i = wb.start; i <= wb.end; i++) {
1009 			    sprintf(portname, "%s[%d]", nexttok, i);
1010 			    Port(portname);
1011 			}
1012 		    }
1013 		    /* Also register this port as a bus */
1014 		    nb = NewBus();
1015 		    nb->start = wb.start;
1016 		    nb->end = wb.end;
1017 		    HashPtrInstall(nexttok, nb, &buses);
1018 		    wb.start = wb.end = -1;
1019 		}
1020 		else {
1021 		    Port(nexttok);
1022 		}
1023 	    }
1024 	    hasports = 1;
1025 	}
1026     }
1027     else if (match(nexttok, "endmodule")) {
1028 
1029       CleanupModule();
1030       EndCell();
1031 
1032       if (in_module == (char)0) {
1033 	  Fprintf(stderr, "\"endmodule\" occurred outside of a module!\n");
1034           InputParseError(stderr);
1035       }
1036       in_module = (char)0;
1037 
1038       if (*CellStackPtr) PopStack(CellStackPtr);
1039       if (*CellStackPtr) ReopenCellDef((*CellStackPtr)->cellname, filenum);
1040       SkipNewLine(VLOG_DELIMITERS);
1041     }
1042 
1043     else if (match(nexttok, "`include")) {
1044       char *iname, *iptr, *quotptr, *pathend, *userpath = NULL;
1045 
1046       SkipTokNoNewline(VLOG_DELIMITERS);
1047       if (nexttok == NULL) continue;	/* Ignore if no filename */
1048 
1049       // Any file included in another Verilog file needs to be
1050       // interpreted relative to the path of the parent Verilog file,
1051       // unless it's an absolute pathname.
1052 
1053       pathend = strrchr(fname, '/');
1054       iptr = nexttok;
1055       while (*iptr == '\'' || *iptr == '\"') iptr++;
1056       if ((pathend != NULL) && (*iptr != '/') && (*iptr != '~')) {
1057 	 *pathend = '\0';
1058 	 iname = (char *)MALLOC(strlen(fname) + strlen(iptr) + 2);
1059 	 sprintf(iname, "%s/%s", fname, iptr);
1060 	 *pathend = '/';
1061       }
1062 #ifndef IBMPC
1063       else if ((*iptr == '~') && (*(iptr + 1) == '/')) {
1064 	 /* For ~/<path>, substitute tilde from $HOME */
1065 	 userpath = getenv("HOME");
1066 	 iname = (char *)MALLOC(strlen(userpath) + strlen(iptr));
1067 	 sprintf(iname, "%s%s", userpath, iptr + 1);
1068       }
1069       else if (*iptr == '~') {
1070 	 /* For ~<user>/<path>, substitute tilde from getpwnam() */
1071 	 struct passwd *passwd;
1072 	 char *pathstart;
1073          pathstart = strchr(iptr, '/');
1074 	 if (pathstart) *pathstart = '\0';
1075 	 passwd = getpwnam(iptr + 1);
1076 	 if (passwd != NULL) {
1077 	    userpath = passwd->pw_dir;
1078 	    if (pathstart) {
1079 	       *pathstart = '/';
1080 	       iname = (char *)MALLOC(strlen(userpath) + strlen(pathstart) + 1);
1081 	       sprintf(iname, "%s%s", userpath, pathstart);
1082 	    }
1083 	    else {
1084 	       /* Almost certainly an error, but make the substitution anyway */
1085 	       iname = STRDUP(userpath);
1086 	    }
1087 	 }
1088 	 else {
1089 	    /* Probably an error, but copy the filename verbatim */
1090 	    iname = STRDUP(iptr);
1091 	 }
1092       }
1093 #endif
1094       else
1095 	 iname = STRDUP(iptr);
1096 
1097       // Eliminate any single or double quotes around the filename
1098       iptr = iname;
1099       quotptr = iptr;
1100       while (*quotptr != '\'' && *quotptr != '\"' &&
1101 		*quotptr != '\0' && *quotptr != '\n') quotptr++;
1102       if (*quotptr == '\'' || *quotptr == '\"') *quotptr = '\0';
1103 
1104       IncludeVerilog(iptr, filenum, CellStackPtr, blackbox);
1105       FREE(iname);
1106       SkipNewLine(VLOG_DELIMITERS);
1107     }
1108     else if (match(nexttok, "`define")) {
1109       struct property *kl = NULL;
1110 
1111       // Pick up key-value pair and store in current cell
1112 
1113       /* Parse for definitions used in expressions.  Save */
1114       /* definitions in the "verilogdefs" hash table.	 */
1115 
1116       SkipTokNoNewline(VLOG_DELIMITERS);
1117       if ((nexttok == NULL) || (nexttok[0] == '\0')) break;
1118 
1119       kl = NewProperty();
1120       kl->key = strsave(nexttok);
1121       kl->idx = 0;
1122       kl->merge = MERGE_NONE;
1123 
1124       SkipTokNoNewline(VLOG_DELIMITERS);
1125       if ((nexttok == NULL) || (nexttok[0] == '\0')) {
1126 	 // Let "`define X" be equivalent to "`define X 1".  Use integer value.
1127 	 kl->type = PROP_INTEGER;
1128 	 kl->pdefault.ival = 1;
1129          kl->slop.ival = 0;
1130       }
1131       else if (nexttok[0] == '(') {
1132 	 /* For now, the netgen verilog parser doesn't handle `define f(X) ... */
1133 	 SkipNewLine(VLOG_DELIMITERS);
1134 	 FREE(kl->key);
1135 	 FREE(kl);
1136 	 kl = NULL;
1137       }
1138       else if (ConvertStringToInteger(nexttok, &ival) == 1) {
1139 	 /* Parameter parses as an integer */
1140       	 kl->type = PROP_INTEGER;
1141 	 kl->pdefault.ival = ival;
1142          kl->slop.ival = 0;		// Exact match default
1143       }
1144       else if (ConvertStringToFloat(nexttok, &dval) == 1) {
1145 	 /* Parameter parses as a floating-point number */
1146       	 kl->type = PROP_DOUBLE;
1147 	 kl->pdefault.dval = dval;
1148          kl->slop.dval = 0.01;		// One percent default
1149       }
1150       else {
1151          char *toks;
1152 
1153 	 /* Treat the parameter as a string; BUT pull everything to */
1154 	 /* EOL, not just the current token.			    */
1155 	 toks = GetLineAtTok();
1156 
1157       	 kl->type = PROP_STRING;
1158 	 kl->pdefault.string = strsave(toks);
1159          kl->slop.dval = 0.0;
1160 
1161 	 SkipNewLine(VLOG_DELIMITERS);
1162       }
1163       if (kl) HashPtrInstall(kl->key, kl, &verilogdefs);
1164     }
1165     else if (match(nexttok, "`undef")) {
1166       struct property *kl = NULL;
1167 
1168       SkipTokNoNewline(VLOG_DELIMITERS);
1169       if ((nexttok == NULL) || (nexttok[0] == '\0')) break;
1170 
1171       kl = HashLookup(nexttok, &verilogdefs);
1172       if (kl != NULL) {
1173 	  HashDelete(nexttok, &verilogdefs);
1174 	  if (kl->type == PROP_STRING)
1175              if (kl->pdefault.string != NULL)
1176 	         FREE(kl->pdefault.string);
1177 	  FREE(kl->key);
1178       }
1179       /* Presumably it is not an error to undefine an undefined keyword */
1180     }
1181     else if (match(nexttok, "real") || match(nexttok, "integer")) {
1182 	Printf("Ignoring '%s' in module '%s'\n", nexttok, model);
1183 	/* Do not skip to end of module, as these can be in the middle of   */
1184 	/* I/O assignments, which need to be parsed.			    */
1185 	while (!match(nexttok, ";")) SkipTok("X///**/X,;");
1186 	continue;
1187     }
1188     else if (match(nexttok, "wire") || match(nexttok, "assign")) {	/* wire = node */
1189 	struct bus wb, wb2, *nb;
1190 	char nodename[128], noderoot[100];
1191 	int is_wire = match(nexttok, "wire");
1192 	int j;
1193 	struct objlist *lhs, *rhs;
1194 
1195 	/* Get left-hand side expression.  If this is a wire statement,	*/
1196 	/* then define the wire.  If is_wire is false, then the wire	*/
1197 	/* should already be defined.					*/
1198 
1199 	if (is_wire) {
1200 	    SkipTokNoNewline(VLOG_DELIMITERS);
1201 	    if (match(nexttok, "real"))
1202 		SkipTokNoNewline(VLOG_DELIMITERS);
1203 	    else if (match(nexttok, "logic"))
1204 		SkipTokNoNewline(VLOG_DELIMITERS);
1205 
1206 	    if (GetBusTok(&wb) == 0) {
1207 		/* Handle bus notation */
1208 		SkipTokNoNewline(VLOG_DELIMITERS);
1209 		strcpy(noderoot, nexttok);
1210 		if (wb.start > wb.end) {
1211 		    for (i = wb.end; i <= wb.start; i++) {
1212 			sprintf(nodename, "%s[%d]", nexttok, i);
1213 			if (LookupObject(nodename, CurrentCell) == NULL)
1214 			    Node(nodename);
1215 			if (i == wb.start) lhs = LookupObject(nodename, CurrentCell);
1216 		    }
1217 		}
1218 		else {
1219 		    for (i = wb.start; i <= wb.end; i++) {
1220 			sprintf(nodename, "%s[%d]", nexttok, i);
1221 			if (LookupObject(nodename, CurrentCell) == NULL)
1222 			    Node(nodename);
1223 			if (i == wb.start) lhs = LookupObject(nodename, CurrentCell);
1224 		    }
1225 		}
1226 		nb = NewBus();
1227 		nb->start = wb.start;
1228 		nb->end = wb.end;
1229 		HashPtrInstall(nexttok, nb, &buses);
1230 	    }
1231 	    else {
1232 		if (LookupObject(nexttok, CurrentCell) == NULL) {
1233 		    Node(nexttok);
1234 		    lhs = LookupObject(nexttok, CurrentCell);
1235 		}
1236 	    }
1237 	    while (1) {
1238 		SkipTokNoNewline(VLOG_DELIMITERS);
1239 		if (match(nexttok, ",")) {
1240 		    SkipTokComments(VLOG_DELIMITERS);
1241 		    if (LookupObject(nexttok, CurrentCell) == NULL) {
1242 			Node(nexttok);
1243 			lhs = LookupObject(nexttok, CurrentCell);
1244 		    }
1245 		}
1246 		else break;
1247 	    }
1248 	}
1249 	else {	    /* "assign" */
1250 	    SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
1251 	    if (GetBus(nexttok, &wb) == 0) {
1252 		char *aptr = strvchr(nexttok, '[');
1253 		if (aptr != NULL) {
1254 		    *aptr = '\0';
1255 		    /* Find object of first net in bus */
1256 		    strcpy(noderoot, nexttok);
1257 		    sprintf(nodename, "%s[%d]", nexttok, wb.start);
1258 		    lhs = LookupObject(nodename, CurrentCell);
1259 		    *aptr = '[';
1260 		}
1261 		else {
1262 		    strcpy(noderoot, nexttok);
1263 		    /* Set LHS to the start of the vector */
1264 		    sprintf(nodename, "%s[%d]", nexttok, wb.start);
1265 		    lhs = LookupObject(nodename, CurrentCell);
1266 		}
1267 	    }
1268 	    else {
1269 		lhs = LookupObject(nexttok, CurrentCell);
1270 		strcpy(noderoot, nexttok);
1271 	    }
1272 	    SkipTokComments(VLOG_DELIMITERS);
1273 	    if (lhs && ((!nexttok) || (!match(nexttok, "=")))) {
1274 		fprintf(stderr, "Empty assignment for net %s\n", lhs->name);
1275 	    }
1276 	}
1277 
1278 	/* Check for assignment statement, and handle any allowed uses.	    */
1279 	/* Any uses other than those mentioned below will cause the entire  */
1280 	/* module to be treated as a black box.				    */
1281 
1282 	// Allowed uses of "assign" for netlists:
1283 	//    "assign a = b" joins two nets.
1284 	//    "assign a = {b, c, ...}" creates a bus from components.
1285 	//    "assign" using any boolean arithmetic is not structural verilog.
1286 
1287 	if (nexttok && match(nexttok, "=")) {
1288 	    char assignname[128], assignroot[100];
1289 
1290 	    i = wb.start;
1291 	    while (1) {
1292 		SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
1293 		if (!nexttok) break;
1294 
1295 		if (match(nexttok, "{")) {
1296 		    /* RHS is a bundle */
1297 		    continue;
1298 		}
1299 		else if (match(nexttok, "}")) {
1300 		    /* End of bundle */
1301 		    continue;
1302 		}
1303 		else if (match(nexttok, ",")) {
1304 		    /* Additional signals in bundle */
1305 		    continue;
1306 		}
1307 		else if (match(nexttok, ";")) {
1308 		    /* End of assignment */
1309 		    break;
1310 		}
1311 		else {
1312 		    if (GetBus(nexttok, &wb2) == 0) {
1313 			char *aptr = strvchr(nexttok, '[');
1314 			j = wb2.start;
1315 			if (aptr != NULL) {
1316 			    *aptr = '\0';
1317 			    strcpy(assignroot, nexttok);
1318 			    sprintf(assignname, "%s[%d]", nexttok, j);
1319 			    rhs = LookupObject(assignname, CurrentCell);
1320 			    *aptr = '[';
1321 			}
1322 		    }
1323 		    else {
1324 			j = -1;
1325 			rhs = LookupObject(nexttok, CurrentCell);
1326 		    }
1327 		    if ((lhs == NULL) || (rhs == NULL)) {
1328 			if (rhs != NULL) {
1329 			    Printf("Improper assignment;  left-hand side cannot "
1330 					"be parsed.\n");
1331 			    if (j != -1)
1332 			    	Printf("Right-hand side is \"%s\".\n", assignroot);
1333 			    else
1334 			    	Printf("Right-hand side is \"%s\".\n", rhs->name);
1335 			    Printf("Improper expression is \"%s\".\n", nexttok);
1336 			    break;
1337 			}
1338 			if (lhs != NULL) {
1339 			    Printf("Improper assignment;  right-hand side cannot "
1340 					"be parsed.\n");
1341 			    if (i != -1)
1342 			    	Printf("Left-hand side is \"%s\".\n", noderoot);
1343 			    else
1344 			    	Printf("Left-hand side is \"%s\".\n", lhs->name);
1345 			    Printf("Improper expression is \"%s\".\n", nexttok);
1346 			    /* Not parsable, probably behavioral verilog? */
1347 			    Printf("Module '%s' is not structural verilog, "
1348 				    "making black-box.\n", model);
1349 			    SetClass(CLASS_MODULE);
1350 			    goto skip_endmodule;
1351 			}
1352 		    }
1353 		    while (1) {
1354 			/* Assign bits in turn from bundle in RHS to bits of LHS    */
1355 			/* until bits in signal are exhausted or LHS is full.	    */
1356 
1357 			if (i != -1)
1358 			    sprintf(nodename, "%s[%d]", noderoot, i);
1359 			else
1360 			    sprintf(nodename, lhs->name);
1361 			if (j != -1)
1362 			    sprintf(assignname, "%s[%d]", assignroot, j);
1363 			else
1364 			    sprintf(assignname, rhs->name);
1365 
1366 			join(nodename, assignname);
1367 
1368 			if (i == wb.end) break;
1369 			i += (wb.end > wb.start) ? 1 : -1;
1370 
1371 			if (j == wb2.end) break;
1372 			j += (wb2.end > wb2.start) ? 1 : -1;
1373 		    }
1374 		}
1375 	    }
1376 	}
1377 	while (nexttok && !match(nexttok, ";"))
1378 	    SkipTokComments(VLOG_DELIMITERS);
1379     }
1380     else if (match(nexttok, "endmodule")) {
1381       // No action---new module is started with next 'module' statement,
1382       // if any.
1383       SkipNewLine(VLOG_DELIMITERS);
1384       in_module = (char)0;	    /* Should have been done already */
1385     }
1386     else if (nexttok[0] == '`') {
1387       // Ignore any other directive starting with a backtick (e.g., `timescale)
1388       SkipNewLine(VLOG_DELIMITERS);
1389     }
1390     else if (match(nexttok, "reg") || match(nexttok, "always") ||
1391 	    match(nexttok, "specify") || match(nexttok, "initial")) {
1392       Printf("Behavioral keyword '%s' found in source.\n", nexttok);
1393       Printf("Module '%s' is not structural verilog, making black-box.\n", model);
1394       // To be done:  Remove any contents (but may not be necessary)
1395       // Recast as module
1396       SetClass(CLASS_MODULE);
1397       goto skip_endmodule;
1398     }
1399     else {	/* module instances */
1400       char instancename[100], modulename[100];
1401       int itype, arraystart, arrayend, arraymax, arraymin;
1402       char ignore;
1403 
1404       instancename[99] = '\0';
1405       modulename[99] = '\0';
1406 
1407       struct portelement {
1408 	char *name;	// Name of port in subcell
1409 	char *net;	// Name of net connecting to port in the parent
1410 	int   width;	// Width of port, if port is a bus
1411 	char  flags;	// Used for marking if port was added into netlist
1412 	struct portelement *next;
1413       };
1414 
1415       struct portelement *head, *tail, *scan, *last, *scannext;
1416       struct objlist *obptr;
1417 
1418       strncpy(modulename, nexttok, 99);
1419 
1420       /* If module name is a verilog primitive, then treat the module as a  */
1421       /* black box (this is not a complete list.  Preferable to use hash    */
1422       /* function instead of lots of strcmp() calls).			    */
1423 
1424       if (!strcmp(modulename, "buf") || !strcmp(modulename, "notif1") ||
1425 	    !strcmp(modulename, "not") || !strcmp(modulename, "and") ||
1426 	    !strcmp(modulename, "or") || !strcmp(modulename, "bufif0") ||
1427 	    !strcmp(modulename, "bufif1") || !strcmp(modulename, "notif0")) {
1428 
1429          Printf("Module contains verilog primitive '%s'.\n", nexttok);
1430          Printf("Module '%s' is not structural verilog, making black-box.\n", model);
1431 	 SetClass(CLASS_MODULE);
1432 	 goto skip_endmodule;
1433       }
1434 
1435       if (!(*CellStackPtr)) {
1436 	CellDef(fname, filenum);
1437 	PushStack(fname, CellStackPtr);
1438       }
1439 
1440       SkipTokComments(VLOG_DELIMITERS);
1441 
1442 nextinst:
1443       ignore = FALSE;
1444       head = NULL;
1445       tail = NULL;
1446 
1447       // Next token must be '#(' (parameters) or an instance name
1448 
1449       if (match(nexttok, "#(")) {
1450 
1451 	 // Read the parameter list
1452 	 SkipTokComments(VLOG_DELIMITERS);
1453 
1454          while (nexttok != NULL) {
1455 	    char *paramname;
1456 
1457 	    if (match(nexttok, ")")) {
1458 		SkipTokComments(VLOG_DELIMITERS);
1459 		break;
1460 	    }
1461 	    else if (match(nexttok, ",")) {
1462 		SkipTokComments(VLOG_DELIMITERS);
1463 		continue;
1464 	    }
1465 
1466 	    // We need to look for parameters of the type ".name(value)"
1467 
1468 	    else if (nexttok[0] == '.') {
1469 		paramname = strsave(nexttok + 1);
1470 	        SkipTokComments(VLOG_DELIMITERS);
1471 		if (!match(nexttok, "(")) {
1472 		    Printf("Error: Expecting parameter value, got %s.\n", nexttok);
1473 		}
1474 	        SkipTokComments(VLOG_DELIMITERS);
1475 		if (match(nexttok, ")")) {
1476 		    Printf("Error: Parameter with no value found.\n");
1477 		}
1478 		else {
1479 	            AddProperty(&kvlist, paramname, nexttok);
1480 	            SkipTokComments(VLOG_DELIMITERS);
1481 		    if (!match(nexttok, ")")) {
1482 		       Printf("Error: Expecting end of parameter value, "
1483 				"got %s.\n", nexttok);
1484 		    }
1485 		}
1486 		FREE(paramname);
1487 	    }
1488 	    SkipTokComments(VLOG_DELIMITERS);
1489 	 }
1490 	 if (!nexttok) {
1491 	    Printf("Error: Still reading module, but got end-of-file.\n");
1492 	    goto skip_endmodule;
1493 	 }
1494       }
1495 
1496       strncpy(instancename, nexttok, 99);
1497       /* Printf("Diagnostic:  new instance is %s\n", instancename); */
1498       SkipTokComments(VLOG_DELIMITERS);
1499 
1500       arraystart = arrayend = -1;
1501       if (match(nexttok, "[")) {
1502 	 // Handle instance array notation.
1503 	 struct bus wb;
1504 	 if (GetBusTok(&wb) == 0) {
1505 	     arraystart = wb.start;
1506 	     arrayend = wb.end;
1507 	 }
1508 	 SkipTokComments(VLOG_DELIMITERS);
1509       }
1510 
1511       if (match(nexttok, "(")) {
1512 	 char savetok = (char)0;
1513 	 struct portelement *new_port;
1514 
1515 	 // Read the pin list
1516          while (nexttok != NULL) {
1517 	    SkipTokComments(VLOG_DELIMITERS);
1518 	    if (match(nexttok, ")")) break;
1519 	    else if (match(nexttok, ",")) continue;
1520 
1521 	    // We need to look for pins of the type ".name(value)"
1522 
1523 	    if (nexttok[0] != '.') {
1524 	        Printf("Warning:  Ignoring subcircuit with no pin names "
1525 			    "at \"%s\"\n", nexttok);
1526 		InputParseError(stderr);
1527 		while (nexttok != NULL) {
1528 		    SkipTokComments(VLOG_DELIMITERS);
1529 		    if (match(nexttok, ";")) break;
1530 		}
1531 		ignore = TRUE;
1532 		break;
1533 	    }
1534 	    else {
1535 	       new_port = (struct portelement *)CALLOC(1, sizeof(struct portelement));
1536 	       new_port->name = strsave(nexttok + 1);
1537 	       new_port->width = -1;
1538 	       new_port->flags = PORT_NOT_FOUND;
1539 	       SkipTokComments(VLOG_DELIMITERS);
1540 	       if (!match(nexttok, "(")) {
1541 	           Printf("Badly formed subcircuit pin line at \"%s\"\n", nexttok);
1542 	           SkipNewLine(VLOG_DELIMITERS);
1543 	       }
1544 	       SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
1545 	       if (match(nexttok, ")")) {
1546 		  char localnet[100];
1547 		  // Empty parens, so create a new local node
1548 		  savetok = (char)1;
1549 		  if (arraystart != -1) {
1550 		     /* No-connect on an instance array must also be an array */
1551 		     sprintf(localnet, "_noconnect_%d_[%d:%d]", localcount++,
1552 				arraystart, arrayend);
1553 		  }
1554 		  else
1555 		     sprintf(localnet, "_noconnect_%d_", localcount++);
1556 		  new_port->net = strsave(localnet);
1557 	       }
1558 	       else {
1559 		  if (!strcmp(nexttok, "{")) {
1560 		     char *wire_bundle = (char *)MALLOC(1);
1561 		     char *new_wire_bundle = NULL;
1562 		     *wire_bundle = '\0';
1563 		     /* Wire bundle---read to "}" */
1564 		     while (nexttok) {
1565 			 new_wire_bundle = (char *)MALLOC(strlen(wire_bundle) +
1566 				    strlen(nexttok) + 1);
1567 			 /* Roundabout way to do realloc() becase there is no REALLOC() */
1568 			 strcpy(new_wire_bundle, wire_bundle);
1569 			 strcat(new_wire_bundle, nexttok);
1570 			 FREE(wire_bundle);
1571 			 wire_bundle = new_wire_bundle;
1572 			 if (!strcmp(nexttok, "}")) break;
1573 			 SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
1574 		     }
1575 		     if (!nexttok) {
1576 			 Printf("Unterminated net in pin %s\n", wire_bundle);
1577 		     }
1578 		     new_port->net = wire_bundle;
1579 		  }
1580 		  else if (nexttok[0] == '~' || nexttok[0] == '!' || nexttok[0] == '-') {
1581 		     /* All of these imply that the signal is logically manipulated */
1582 		     /* in turn implying behavioral code.			    */
1583 		     Printf("Module '%s' is not structural verilog, "
1584 				    "making black-box.\n", model);
1585 		     SetClass(CLASS_MODULE);
1586 		     goto skip_endmodule;
1587 		  }
1588 		  else
1589 		     new_port->net = strsave(nexttok);
1590 
1591 		  /* Read array information along with name;  will be parsed later */
1592 		  SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
1593 		  if (match(nexttok, "[")) {
1594 		      /* Check for space between name and array identifier */
1595 		      SkipTokComments(VLOG_PIN_NAME_DELIMITERS);
1596 		      if (!match(nexttok, ")")) {
1597 			 char *expnet;
1598 			 expnet = (char *)MALLOC(strlen(new_port->net)
1599 				    + strlen(nexttok) + 2);
1600 			 sprintf(expnet, "%s[%s", new_port->net, nexttok);
1601 			 FREE(new_port->net);
1602 			 new_port->net = expnet;
1603 		      }
1604 		      SkipTokComments(VLOG_DELIMITERS);
1605 		  }
1606 
1607 	          if (!match(nexttok, ")")) {
1608 	              Printf("Badly formed subcircuit pin line at \"%s\"\n", nexttok);
1609 	              SkipNewLine(VLOG_DELIMITERS);
1610 		  }
1611 	       }
1612 
1613 	       if (head == NULL) head = new_port;
1614 	       else tail->next = new_port;
1615 	       new_port->next = NULL;
1616 	       tail = new_port;
1617 	    }
1618 	 }
1619       }
1620       else {
1621          Printf("Expected to find instance pin block but got \"%s\"\n", nexttok);
1622       }
1623       if (ignore == TRUE) continue;	/* moving along. . . */
1624 
1625       /* Verilog allows multiple instances of a single cell type to be chained	*/
1626       /* together with commas.							*/
1627 
1628       SkipTokComments(VLOG_DELIMITERS);
1629       if (match(nexttok, ",")) {
1630 	 goto nextinst;
1631       }
1632 
1633       /* Otherwise, instance must end with a semicolon */
1634 
1635       else if (!match(nexttok, ";")) {
1636 	 Printf("Expected to find end of instance but got \"%s\"\n", nexttok);
1637 	 InputParseError(stderr);
1638       }
1639 
1640       /* Check for ignored class */
1641 
1642       if ((itype = IsIgnored(modulename, filenum)) == IGNORE_CLASS) {
1643           Printf("Class '%s' instanced in input but is being ignored.\n", model);
1644           return;
1645       }
1646 
1647       /* Check for shorted pins */
1648 
1649       if ((itype == IGNORE_SHORTED) && (head != NULL)) {
1650          unsigned char shorted = (unsigned char)1;
1651          struct portelement *p;
1652          for (p = head->next; p; p = p->next) {
1653             if (strcasecmp(head->name, p->name))
1654                shorted = (unsigned char)0;
1655                break;
1656          }
1657          if (shorted == (unsigned char)1) {
1658             Printf("Instance of '%s' is shorted, ignoring.\n", modulename);
1659 	    while (head) {
1660 	       p = head->next;
1661 	       FREE(head);
1662 	       head = p;
1663             }
1664             return;
1665          }
1666       }
1667 
1668       if (head == NULL) {
1669 	 Fprintf(stderr, "Warning:  Cell %s has no pins\n", modulename);
1670       }
1671 
1672       /* Check that the module exists.  If not, generate an empty	*/
1673       /* module entry matching the call.				*/
1674 
1675       tp = LookupCellFile(modulename, filenum);
1676       if (tp == NULL) {
1677          struct bus wb, pb;
1678 	 char defport[128];
1679 
1680 	 Fprintf(stdout, "Creating placeholder cell definition for "
1681 			"module %s.\n", modulename);
1682 	 CellDef(modulename, filenum);
1683 	 CurrentCell->flags |= CELL_PLACEHOLDER;
1684          for (scan = head; scan != NULL; scan = scan->next) {
1685 	    // Check if net name is a wire bus or portion of a bus
1686 	    if (GetBus(scan->net, &wb) == 0) {
1687 		int range;
1688 
1689 		// This takes care of three situations:
1690 		// (1) The signal bus length matches the number of instances:
1691 		//     apply one signal per instance.
1692 		// (2) The signal bus length is a multiple of the number of instances:
1693 		//     apply a signal sub-bus to each instance.
1694 		// (3) The number of instances is a multiple of the signal bus length:
1695 		//     apply the same signal to each instance.
1696 
1697 		if ((arrayend - arraystart) == (wb.end - wb.start)) {
1698 		    // Net is a bus, but net is split over arrayed instances
1699 		    Port(scan->name);
1700 		}
1701 		else if (wb.start > wb.end) {
1702 		    if ((arraystart - arrayend) > (wb.start - wb.end))
1703 			range = (((arraystart - arrayend) + 1) /
1704 				    ((wb.start - wb.end) + 1)) - 1;
1705 		    else
1706 			range = (((wb.start - wb.end) + 1) /
1707 				    ((arraystart - arrayend) + 1)) - 1;
1708 
1709 		    for (i = range; i >= 0; i--) {
1710 			sprintf(defport, "%s[%d]", scan->name, i);
1711 			Port(defport);
1712 		    }
1713 		}
1714 		else {
1715 		    if ((arrayend - arraystart) >  (wb.end - wb.start))
1716 			range = (((arrayend - arraystart) + 1) /
1717 				    ((wb.end - wb.start) + 1)) - 1;
1718 		    else
1719 			range = (((wb.end - wb.start) + 1) /
1720 				    ((arrayend - arraystart) + 1)) - 1;
1721 
1722 		    for (i = 0; i <= range; i++) {
1723 			sprintf(defport, "%s[%d]", scan->name, i);
1724 			Port(defport);
1725 		    }
1726 		}
1727 	    }
1728 	    else {
1729 		Port(scan->name);
1730 	    }
1731 	 }
1732 	 if (head == NULL) {
1733 	    Port((char *)NULL);	// Must have something for pin 1
1734 	 }
1735 	 SetClass(CLASS_MODULE);
1736 	 tp = CurrentCell;
1737          EndCell();
1738 	 ReopenCellDef((*CellStackPtr)->cellname, filenum);		/* Reopen */
1739       }
1740 
1741       /* Work through scan list and expand ports/nets that are arrays */
1742 
1743       last = (struct portelement *)NULL;
1744       scan = head;
1745       while (scan != NULL) {
1746 	 int portstart, portend, portnum;
1747 
1748 	 scannext = scan->next;
1749 	 portstart = -1;
1750 
1751 	 for (obptr = tp->cell; obptr && obptr->type == PORT; obptr = obptr->next) {
1752 	    char *delimiter;
1753 	    if ((delimiter = strrchr(obptr->name, '[')) != NULL) {
1754 	       *delimiter = '\0';
1755 	       if ((*matchfunc)(obptr->name, scan->name)) {
1756 		  if (sscanf(delimiter + 1, "%d", &portnum) == 1) {
1757 		     if (portstart == -1)
1758 			portstart = portnum;
1759 		     else
1760 		        portend = portnum;
1761 		  }
1762 	       }
1763 	       *delimiter = '[';
1764 	    }
1765 	 }
1766 	 if (portstart != -1) {
1767 	    struct bus wb;
1768 	    struct portelement *new_port;
1769 	    char vname[256];
1770 	    int j, result;
1771 	    struct objlist *bobj;
1772 	    char *bptr;
1773 	    int minnet, maxnet, testidx, width;
1774 
1775 	    width = portstart - portend;
1776 	    if (width < 0) width = -width;
1777 	    width++;
1778 	    scan->width = width;
1779 
1780 	    result = GetBus(scan->net, &wb);
1781 	    if (result == -1) {
1782 		/* CHECK:  THIS CODE SHOULD BE DELETED, IT IS NOT THE ISSUE */
1783 		/* Not bus notation, but check if signal was defined as a bus */
1784 		wb.start = wb.end = -1;
1785 		minnet = maxnet = -1;
1786 
1787 		/* Pins should be in index order start->end.  Other nodes */
1788 		/* should be in order start->end by node number.	  */
1789 
1790 		for (bobj = CurrentCell->cell; bobj; bobj = bobj->next) {
1791 		    if (bobj->type == PORT) {
1792 			if ((bptr = strvchr(bobj->name, '[')) != NULL) {
1793 			    *bptr = '\0';
1794 			    if (!strcmp(bobj->name, scan->net)) {
1795 				*bptr = '[';
1796 				if (wb.start == -1)
1797 				    sscanf(bptr + 1, "%d", &wb.start);
1798 				else
1799 				    sscanf(bptr + 1, "%d", &wb.end);
1800 			    }
1801 			}
1802 		    }
1803 		    else if (bobj->type == NODE) {
1804 			if ((bptr = strvchr(bobj->name, '[')) != NULL) {
1805 			    *bptr = '\0';
1806 			    if (!strcmp(bobj->name, scan->net)) {
1807 				if (sscanf(bptr + 1, "%d", &testidx) == 1) {
1808 				    if (minnet == -1) {
1809 					minnet = maxnet = bobj->node;
1810 					wb.start = wb.end = testidx;
1811 				    }
1812 				    else if (bobj->node < minnet) {
1813 					minnet = bobj->node;
1814 					wb.start = testidx;
1815 				    }
1816 				    else if (bobj->node > maxnet) {
1817 					maxnet = bobj->node;
1818 					wb.end = testidx;
1819 				    }
1820 				}
1821 			    }
1822 			    *bptr = '[';
1823 			}
1824 		    }
1825 		}
1826 		if (wb.start != -1) result = 0;
1827 	    }
1828 
1829 	    if (result == 0) {
1830 	       int match = 0;
1831 	       int wblen, arraylen;
1832 
1833 	       arraylen = arraystart - arrayend;
1834 	       wblen = wb.start - wb.end;
1835 
1836 	       if (arraylen < 0) arraylen = -arraylen;
1837 	       if (wblen < 0) wblen = -wblen;
1838 
1839 	       arraylen++;
1840 	       wblen++;
1841 
1842 	       if ((scan->width * arraylen) == wblen) match = 1;
1843 	       else if (wblen == scan->width) match = 1;
1844 	       else if (wblen == arraylen) match = 1;
1845 	       else {
1846 		  Fprintf(stderr, "Warning:  Net %s bus width (%d) does not match "
1847 				"port %s bus width (%d) or array width (%d).\n",
1848 				scan->net, wblen, scan->name, scan->width, arraylen);
1849 	       }
1850 
1851 	       // Net is bit-sliced across array of instances.
1852 
1853 	       if (wb.start > wb.end) {
1854 		  char *bptr = NULL, *cptr = NULL, cchar, *netname;
1855 		  unsigned char is_bundle = 0;
1856 		  struct bus wbb;
1857 
1858 		  i = wb.start;
1859 		  j = portstart;
1860 
1861 		  netname = scan->net;
1862 		  if (*netname == '{') {
1863 		     is_bundle = 1;
1864 		     netname++;
1865 		     cptr = strvchr(netname, ',');
1866 		     if (cptr == NULL) cptr = strvchr(netname, '}');
1867 		     if (cptr == NULL) cptr = netname + strlen(netname) - 1;
1868 		     cchar = *cptr;
1869 		     *cptr = '\0';
1870 		  }
1871 
1872 		  // Remove indexed part of scan->net
1873 		  if (GetBus(netname, &wbb) == 0) {
1874 		     i = wbb.start;
1875 		     if ((bptr = strvchr(netname, '[')) != NULL)
1876 			 *bptr = '\0';
1877 		  }
1878 		  else
1879 		     i = -1;
1880 
1881 		  while (1) {
1882 	             new_port = (struct portelement *)CALLOC(1,
1883 				sizeof(struct portelement));
1884 	             sprintf(vname, "%s[%d]", scan->name, j);
1885 	             new_port->name = strsave(vname);
1886 		     if (i == -1)
1887 			 sprintf(vname, "%s", netname);
1888 		     else
1889 			 sprintf(vname, "%s[%d]", netname, i);
1890 	             new_port->net = strsave(vname);
1891 		     new_port->width = scan->width;
1892 
1893 		     if (last == NULL)
1894 			head = new_port;
1895 		     else
1896 			last->next = new_port;
1897 
1898 		     new_port->next = scannext;
1899 		     last = new_port;
1900 
1901 		     if (j == portend) break;
1902 
1903 		     if (portstart > portend) j--;
1904 		     else j++;
1905 		     if (i != -1) {
1906 			if (wbb.start > wbb.end) i--;
1907 			else i++;
1908 		     }
1909 
1910 		     if (is_bundle &&
1911 			    ((i == -1) ||
1912 			    ((wbb.start > wbb.end) && (i < wbb.end)) ||
1913 			    ((wbb.start <= wbb.end) && (i > wbb.end)))) {
1914 		         if (bptr) *bptr = '[';
1915 
1916 			 netname = cptr + 1;
1917 			 if (cptr) *cptr = cchar; /* Restore previous bundle delimiter */
1918 		         cptr = strvchr(netname, ',');
1919 			 if (cptr == NULL) cptr = strvchr(netname, '}');
1920 			 if (cptr == NULL) cptr = netname + strlen(netname) - 1;
1921 			 cchar = *cptr;
1922 			 *cptr = '\0';
1923 
1924 			 if (GetBus(netname, &wbb) == 0) {
1925 			    i = wbb.start;
1926 			    if ((bptr = strvchr(netname, '[')) != NULL)
1927 				*bptr = '\0';
1928 			 }
1929 			 else i = -1;
1930 		     }
1931 		  }
1932 		  FREE(scan);
1933 		  scan = last;
1934 		  if (cptr) *cptr = cchar; /* Restore bundle delimiter */
1935 	       }
1936 	    }
1937 	    else if (portstart != portend) {
1938 	       Fprintf(stderr, "Error:  Single net %s is connected to bus port %s\n",
1939 			scan->net, scan->name);
1940 	    }
1941 	 }
1942          last = scan;
1943 	 scan = scannext;
1944       }
1945 
1946       arraymax = (arraystart > arrayend) ? arraystart : arrayend;
1947       arraymin = (arraystart > arrayend) ? arrayend : arraystart;
1948 
1949       for (i = arraymin; i <= arraymax; i++) {
1950 	 char *brackptr;
1951 	 int j;
1952 	 char locinst[128];
1953 
1954          if (i != -1)
1955 	    sprintf(locinst, "%s[%d]", instancename, i);
1956 	 else
1957 	    strcpy(locinst, instancename);
1958 	 Instance(modulename, locinst);
1959 	 LinkProperties(modulename, kvlist);
1960 
1961          obptr = LookupInstance(locinst, CurrentCell);
1962          if (obptr != NULL) {
1963             do {
1964 	       struct bus wb, wb2;
1965 	       char *obpinname;
1966 	       int obpinidx;
1967 
1968 	       // NOTE:  Verilog allows any order of pins, since both the
1969 	       // instance and cell pin names are given.  So for each pin
1970 	       // in obptr (which defines the pin order) , we have to find
1971 	       // the corresponding pin in the scan list.
1972 
1973 	       obpinname = strrchr(obptr->name, '/');
1974 	       if (!obpinname) break;
1975 	       obpinname++;
1976 
1977 	       scan = head;
1978 	       obpinidx = -1;
1979 	       while (scan != NULL) {
1980 		  if (match(obpinname, scan->name)) {
1981 		     scan->flags |= PORT_FOUND;
1982 		     break;
1983 		  }
1984 		  scan = scan->next;
1985 	       }
1986 	       if (scan == NULL) {
1987 		  char localnet[100];
1988 
1989 		  /* Assume an implicit unconnected pin */
1990 		  sprintf(localnet, "_noconnect_%d_", localcount++);
1991 		  Node(localnet);
1992 		  join(localnet, obptr->name);
1993 		  Fprintf(stderr,
1994 			 "Note:  Implicit pin %s in instance %s of %s in cell %s\n",
1995 			 obpinname, locinst, modulename, CurrentCell->name);
1996 	       }
1997 	       else if (GetBus(scan->net, &wb) == 0) {
1998 		   char *bptr2;
1999 		   char *scanroot;
2000 		   scanroot = strsave(scan->net);
2001 		   brackptr = strvchr(scanroot, '[');
2002 		   if (brackptr) *brackptr = '\0';
2003 
2004 		   if (arraystart == -1) {
2005 		       // Port may be an array
2006 		       int range;
2007 		       char pinname[128];
2008 
2009 		       // Check if port is an array
2010 		       if (obpinidx == -1) {
2011 			   if (wb.start != wb.end) {
2012 			       Printf("Error: Bus connected to single port\n");
2013 			   }
2014 			   // Use only the first bit of the bus
2015 			   sprintf(pinname, "%s[%d]", scanroot, wb.start);
2016 	                   if (LookupObject(pinname, CurrentCell) == NULL)
2017 				Node(pinname);
2018 	                   join(pinname, obptr->name);
2019 			   if (brackptr) *brackptr = '[';
2020 		       }
2021 		       else {
2022 			  // NOTE:  Making unsupportable assumption that
2023 			  // pin and port indexes match---need to fix this!
2024 			  sprintf(pinname, "%s[%d]", scanroot, obpinidx);
2025 	                  if (LookupObject(pinname, CurrentCell) == NULL)
2026 			     Node(pinname);
2027 	                  join(pinname, obptr->name);
2028 		       }
2029 		   }
2030 		   else {
2031 		       // Instance must be an array
2032 		       char netname[128];
2033 		       int slice, portlen, siglen;
2034 
2035 		       /* Get the array size of the port for bit slicing */
2036 		       portlen = (scan->width < 0) ? 1 : scan->width;
2037 
2038 		       /* Get the full array size of the connecting bus */
2039 		       GetBus(scanroot, &wb2);
2040 		       siglen = wb2.start - wb2.end;
2041 		       if (siglen < 0) siglen = -siglen;
2042 		       siglen++;
2043 
2044 		       // If signal array is smaller than the portlength *
2045 		       // length of instance array, then the signal wraps.
2046 
2047 		       if (wb2.start >= wb2.end && arraystart >= arrayend) {
2048 			   slice = wb.start - (arraystart - i) * portlen;
2049 			   while (slice < wb2.end) slice += siglen;
2050 		       }
2051 		       else if (wb2.start < wb2.end && arraystart > arrayend) {
2052 			   slice = wb.start + (arraystart - i) * portlen;
2053 			   while (slice > wb2.end) slice -= siglen;
2054 		       }
2055 		       else if (wb2.start > wb2.end && arraystart < arrayend) {
2056 			   slice = wb.start - (arraystart + i) * portlen;
2057 			   while (slice < wb2.end) slice += siglen;
2058 		       }
2059 		       else { // (wb2.start < wb2.end && arraystart < arrayend)
2060 			   slice = wb.start + (arraystart + i) * portlen;
2061 			   while (slice > wb2.end) slice -= siglen;
2062 		       }
2063 
2064 		       sprintf(netname, "%s[%d]", scanroot, slice);
2065 	               if (LookupObject(netname, CurrentCell) == NULL) Node(netname);
2066 	               join(netname, obptr->name);
2067 		   }
2068 		   FREE(scanroot);
2069 	       }
2070 	       else {
2071 	           if (LookupObject(scan->net, CurrentCell) == NULL) Node(scan->net);
2072 	           join(scan->net, obptr->name);
2073 	       }
2074 
2075 	       /* Before exiting the loop, check if all ports in the	*/
2076 	       /* scan list were handled.				*/
2077 
2078 	       if ((obptr->next == NULL) || (obptr->next->type <= FIRSTPIN)) {
2079 	          for (scan = head; scan; scan = scan->next) {
2080 	             if (!(scan->flags & PORT_FOUND)) {
2081 		        if (tp->flags & CELL_PLACEHOLDER) {
2082 			   char tempname[128];
2083 			   int maxnode;
2084 
2085 		           /* This pin was probably implicit in the first call */
2086 		           /* and so it needs to be added to the definition.	 */
2087 
2088 			   ReopenCellDef(modulename, filenum);
2089 		           Port(scan->name);
2090 			   ReopenCellDef((*CellStackPtr)->cellname, filenum);
2091 
2092 			   /* obptr->next now gets the new port.  Update the	*/
2093 			   /* port number, and copy class and instance name.	*/
2094 			   nobj = GetObject();
2095 			   sprintf(tempname, "%s%s%s", obptr->instance.name,
2096 						SEPARATOR, scan->name);
2097 			   nobj->name = strsave(tempname);
2098 			   nobj->model.class = strsave(obptr->model.class);
2099 			   nobj->instance.name = strsave(obptr->instance.name);
2100 			   nobj->type = obptr->type + 1;
2101 			   nobj->next = obptr->next;
2102 			   nobj->node = -1;
2103 			   obptr->next = nobj;
2104       			   HashPtrInstall(nobj->name, nobj, &(CurrentCell->objdict));
2105 
2106 	           	   if (LookupObject(scan->net, CurrentCell) == NULL)
2107 			      Node(scan->net);
2108 	           	   join(scan->net, nobj->name);
2109 	             	   scan->flags |= PORT_FOUND;
2110 
2111 			   /* Now any previous instance of the same cell must	*/
2112 			   /* insert the same additional pin as a no-connect.	*/
2113 			   /* NOTE:  This should be running a callback on all	*/
2114 			   /* cells in the file, not just CurrentCell.		*/
2115 
2116 			   for (sobj = CurrentCell->cell; sobj && (sobj != obptr);
2117 					sobj = sobj->next) {
2118 			      if (sobj->type == FIRSTPIN) {
2119 				 if (match(sobj->model.class, obptr->model.class)) {
2120 				    while (sobj->next->type > FIRSTPIN)
2121 				       sobj = sobj->next;
2122 				    /* Stop when reaching the current instance */
2123 				    if (sobj->type == obptr->type + 1) break;
2124 				    nobj = GetObject();
2125 				    sprintf(tempname, "%s%s%s", sobj->instance.name,
2126 						SEPARATOR, scan->name);
2127 				    nobj->name = strsave(tempname);
2128 				    nobj->model.class = strsave(sobj->model.class);
2129 				    nobj->instance.name = strsave(sobj->instance.name);
2130 				    nobj->type = obptr->type + 1;
2131 				    nobj->node = -1;
2132 				    nobj->next = sobj->next;
2133 				    sobj->next = nobj;
2134       				    HashPtrInstall(nobj->name, nobj,
2135 							&(CurrentCell->objdict));
2136 
2137 		  	   	    sprintf(tempname, "_noconnect_%d_", localcount++);
2138 		  	   	    Node(tempname);
2139 		  	   	    join(tempname, nobj->name);
2140 		  	   	    Fprintf(stderr, "Note:  Implicit pin %s in instance "
2141 						"%s of %s in cell %s\n",
2142 			 			scan->name, sobj->instance.name,
2143 						modulename, CurrentCell->name);
2144 				 }
2145 			      }
2146 			   }
2147 		        }
2148 		        else {
2149 		           Fprintf(stderr, "Error:  Instance %s has pin %s which is "
2150 					"not in the %s cell definition.\n",
2151 					locinst, scan->name, modulename);
2152 		        }
2153 	             }
2154 	          }
2155 	       }
2156 
2157 	       obptr = obptr->next;
2158             } while (obptr != NULL && obptr->type > FIRSTPIN);
2159 	 }
2160 	 if (i == -1) break;	/* No array */
2161       }
2162       DeleteProperties(&kvlist);
2163 
2164       /* free up the allocated list */
2165       scan = head;
2166       while (scan != NULL) {
2167 	scannext = scan->next;
2168 	FREE(scan->name);
2169 	FREE(scan->net);
2170 	FREE(scan);
2171 	scan = scannext;
2172       }
2173     }
2174     continue;
2175 
2176 baddevice:
2177     Fprintf(stderr, "Badly formed line in input.\n");
2178   }
2179 
2180   /* Watch for bad ending syntax */
2181 
2182   if (in_module == (char)1) {
2183      Fprintf(stderr, "Missing \"endmodule\" statement in module.\n");
2184      InputParseError(stderr);
2185   }
2186 
2187   if (*(CellStackPtr)) {
2188      CleanupModule();
2189      EndCell();
2190      if (*CellStackPtr) PopStack(CellStackPtr);
2191      if (*CellStackPtr) ReopenCellDef((*CellStackPtr)->cellname, filenum);
2192   }
2193 
2194   if (warnings)
2195      Fprintf(stderr, "File %s read with %d warning%s.\n", fname,
2196 		warnings, (warnings == 1) ? "" : "s");
2197 }
2198 
2199 /*----------------------------------------------*/
2200 /* Top-level verilog module file read routine	*/
2201 /*----------------------------------------------*/
2202 
ReadVerilogTop(char * fname,int * fnum,int blackbox)2203 char *ReadVerilogTop(char *fname, int *fnum, int blackbox)
2204 {
2205   struct property *kl = NULL;
2206   struct cellstack *CellStack = NULL;
2207   struct nlist *tp;
2208   int filenum;
2209 
2210   // Make sure CurrentCell is clear
2211   CurrentCell = NULL;
2212 
2213   if ((filenum = OpenParseFile(fname, *fnum)) < 0) {
2214 
2215     if (strchr(fname, '.') == NULL) {
2216       char name[1024];
2217       SetExtension(name, fname, VERILOG_EXTENSION);
2218       if ((filenum = OpenParseFile(name, *fnum)) < 0) {
2219         Fprintf(stderr, "Error in Verilog file read: No file %s\n", name);
2220         *fnum = filenum;
2221         return NULL;
2222       }
2223     }
2224     else {
2225        Fprintf(stderr, "Error in Verilog file read: No file %s\n", fname);
2226        *fnum = filenum;
2227        return NULL;
2228     }
2229   }
2230 
2231   /* All Verilog file reading is case sensitive.  However:  if	*/
2232   /* a SPICE file was read before it, then it will be forced to	*/
2233   /* be case insensitive, with a stern warning.			*/
2234 
2235   if (matchfunc == matchnocase) {
2236      Printf("Warning:  A case-insensitive file has been read and so the	"
2237 		"verilog file must be treated case-insensitive to match.\n");
2238   }
2239   else {
2240      matchfunc = match;
2241      matchintfunc = matchfile;
2242      hashfunc = hashcase;
2243   }
2244 
2245   InitializeHashTable(&verilogparams, OBJHASHSIZE);
2246   InitializeHashTable(&verilogdefs, OBJHASHSIZE);
2247   definitions = &verilogdefs;
2248 
2249   /* Add the pre-defined key "LVS" to verilogdefs */
2250 
2251   kl = NewProperty();
2252   kl->merge = MERGE_NONE;
2253   kl->key = strsave("LVS");
2254   kl->idx = 0;
2255   kl->type = PROP_INTEGER;
2256   kl->slop.ival = 0;
2257   kl->pdefault.ival = 1;
2258   HashPtrInstall(kl->key, kl, &verilogdefs);
2259 
2260   ReadVerilogFile(fname, filenum, &CellStack, blackbox);
2261   CloseParseFile();
2262 
2263   // Cleanup
2264   while (CellStack != NULL) PopStack(&CellStack);
2265 
2266   RecurseHashTable(&verilogparams, freeprop);
2267   HashKill(&verilogparams);
2268   RecurseHashTable(&verilogdefs, freeprop);
2269   HashKill(&verilogdefs);
2270   definitions = (struct hashdict *)NULL;
2271 
2272   // Record the top level file.
2273   if (LookupCellFile(fname, filenum) == NULL) CellDef(fname, filenum);
2274 
2275   tp = LookupCellFile(fname, filenum);
2276   if (tp) tp->flags |= CELL_TOP;
2277 
2278   *fnum = filenum;
2279   return fname;
2280 }
2281 
2282 /*--------------------------------------*/
2283 /* Wrappers for ReadVerilogTop()	*/
2284 /*--------------------------------------*/
2285 
ReadVerilog(char * fname,int * fnum)2286 char *ReadVerilog(char *fname, int *fnum)
2287 {
2288    return ReadVerilogTop(fname, fnum, 0);
2289 }
2290 
2291 /*--------------------------------------*/
2292 /* Verilog file include routine		*/
2293 /*--------------------------------------*/
2294 
IncludeVerilog(char * fname,int parent,struct cellstack ** CellStackPtr,int blackbox)2295 void IncludeVerilog(char *fname, int parent, struct cellstack **CellStackPtr,
2296 		int blackbox)
2297 {
2298   int filenum = -1;
2299   char name[256];
2300 
2301   /* If fname does not begin with "/", then assume that it is	*/
2302   /* in the same relative path as its parent.			*/
2303 
2304   if (fname[0] != '/') {
2305      char *ppath;
2306      if (*CellStackPtr && ((*CellStackPtr)->cellname != NULL)) {
2307 	strcpy(name, (*CellStackPtr)->cellname);
2308 	ppath = strrchr(name, '/');
2309 	if (ppath != NULL)
2310            strcpy(ppath + 1, fname);
2311 	else
2312            strcpy(name, fname);
2313         filenum = OpenParseFile(name, parent);
2314      }
2315   }
2316 
2317   /* If we failed the path relative to the parent, then try the	*/
2318   /* filename alone (relative to the path where netgen was	*/
2319   /* executed).							*/
2320 
2321   if (filenum < 0) {
2322      if ((filenum = OpenParseFile(fname, parent)) < 0) {
2323 
2324 	/* If that fails, see if a standard Verilog extension	*/
2325 	/* helps, if the file didn't have an extension.  But	*/
2326 	/* really, we're getting desperate at this point.	*/
2327 
2328 	if (strchr(fname, '.') == NULL) {
2329            SetExtension(name, fname, VERILOG_EXTENSION);
2330            filenum = OpenParseFile(name, parent);
2331 	   if (filenum < 0) {
2332 	      fprintf(stderr,"Error in Verilog file include: No file %s\n", name);
2333 	      return;
2334 	   }
2335         }
2336 	else {
2337 	   fprintf(stderr,"Error in Verilog file include: No file %s\n", fname);
2338 	   return;
2339         }
2340      }
2341   }
2342   ReadVerilogFile(fname, parent, CellStackPtr, blackbox);
2343   CloseParseFile();
2344 }
2345 
2346