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 /* query.c -- simple command-line interpreter */
20 
21 #include "config.h"
22 
23 #include <stdio.h>
24 #include <ctype.h>
25 #include <setjmp.h>
26 #include <signal.h>
27 
28 #ifdef HAVE_MALLINFO
29 #include <malloc.h>
30 #endif
31 
32 #ifdef IBMPC
33 #include <alloc.h>
34 #include <process.h> /* for system() */
35 #include <bios.h>  /* for bioskey() */
36 #endif
37 
38 #include "netgen.h"
39 #include "timing.h"
40 #include "hash.h"
41 #include "objlist.h"
42 #include "query.h"
43 #include "netfile.h"
44 #include "print.h"
45 #include "dbug.h"
46 #include "netcmp.h"
47 
48 /*************************************************************************/
49 /*                                                                       */
50 /*    I/O support for Query() routine                                    */
51 /*                                                                       */
52 /*************************************************************************/
53 
54 static int SuppressPrompts = 0;
55 static char InputLine[200];
56 
typeahead(char * str)57 void typeahead(char *str)
58 {
59   if (strlen(str) + strlen(InputLine) + 3 < sizeof(InputLine)) {
60     strcat(InputLine," ");
61     strcat(InputLine,str);
62   }
63   else fprintf(stderr, "InputLine too long: ignored command '%s'\n",str);
64 }
65 
66 /* change the following to redirect the input stream */
67 FILE *promptstring_infile = NULL;
68 
promptstring(char * prompt,char * buf)69 void promptstring(char *prompt, char *buf)
70 /* tries to get a token out of 'line' variable,
71 but reads from 'promptstring_infile' if nec. */
72 /* copy it to buffer, when found */
73 /* If interactive, puts out 'prompt' */
74 {
75   char *nexttok;
76   char tmpstr[200];
77   int echo;
78 
79   if (promptstring_infile == NULL)
80     promptstring_infile = stdin;
81 
82   if (!SuppressPrompts) {
83     Printf("%s",prompt);
84     Fflush(stdout);
85   }
86   echo = 1;  /* assume we got it from typeahead */
87   nexttok = InputLine;
88   while (isspace(*nexttok) && *nexttok != '\0') nexttok++;
89   if (*nexttok == '\0') {
90     fgets(InputLine, sizeof(InputLine), promptstring_infile);
91     if (promptstring_infile == stdin) echo = 0;
92     nexttok = InputLine;
93     while (isspace(*nexttok) && *nexttok != '\0') nexttok++;
94     if (*nexttok == '\0') {
95       *buf = '\0';
96       return;
97     }
98   }
99   /* nexttok points to beginning of valid token */
100   strcpy(tmpstr,nexttok);
101   nexttok = tmpstr;
102   while (*nexttok != '\0' && !isspace(*nexttok)) nexttok++;
103   strcpy(InputLine, nexttok);
104   *nexttok = '\0';
105   strcpy(buf, tmpstr);
106   if (echo && !SuppressPrompts) Printf("%s\n",buf);
107 }
108 
109 
InitializeCommandLine(int argc,char ** argv)110 void InitializeCommandLine(int argc, char **argv)
111 {
112   /* neither of the two Inits below are strictly necessary,		*/
113   /* as static objects are initialized to 0 (NULL) automatically	*/
114 
115   InitCellHashTable();
116   InitGarbageCollection();
117 
118   RemoveCompareQueue();
119 
120 #ifdef TCL_NETGEN
121   return;
122 
123 #else
124   if (argv == NULL) return;	/* Don't run Query() */
125 
126   /* initialize command-line parser, including dbug code */
127   DBUG_PROCESS(argv[0]);
128   if (argc > 1) {
129     int start;
130     int usekbd, forceinteractive;
131     usekbd = 1;   /* assume we are interactive */
132     forceinteractive = 0; /* try to figure it out from cmd line */
133 
134     /* quiet prompting if program name is not netgen */
135     SuppressPrompts =  (strstr(argv[0], "netgen") == NULL);
136 
137     for (start = 1; start < argc; start++) {
138       if (argv[start][0] == '-') {
139 	switch (argv[start][1]) {
140 	case '#': DBUG_PUSH(&(argv[start][2]));
141 	  break;
142 	case '\0': forceinteractive = 1;
143 	  break;
144 	default: Fprintf(stderr,"Unrecognized switch: %s\n",argv[start]);
145 	  break;
146 	}
147       }
148       else {
149 	      typeahead(argv[start]);
150 	      usekbd = 0;
151       }
152     }
153     if (!usekbd && !forceinteractive) typeahead("Q"); /* exit when done */
154   }
155 
156   /* permit command-line typeahead even for X-windows */
157   if (getenv("DISPLAY")) {
158     int oldSuppressPrompts = SuppressPrompts;
159     SuppressPrompts = 1;
160     typeahead("q");  /* get out of one level of query */
161     Query();
162     SuppressPrompts = oldSuppressPrompts;
163   }
164 
165 #endif  /* TCL_NETGEN */
166 }
167 
Initialize(void)168 void Initialize(void)
169 {
170 #ifdef HAVE_MALLINFO
171   char *wasted;
172 
173   wasted = (char *)MALLOC(2);  /* need to initialize memory allocator */
174 #endif
175 
176   InitializeCommandLine(0, NULL);
177 }
178 
179 
180 /* Print the type of object (mostly diagnostic) */
181 
PrintObjectType(int type)182 void PrintObjectType(int type)
183 {
184    switch(type) {
185       case UNIQUEGLOBAL:
186 	Printf("Unique Global");
187 	break;
188       case GLOBAL:
189 	Printf("Global");
190 	break;
191       case PORT:
192 	Printf("Port");
193 	break;
194       case PROPERTY:
195 	Printf("Properties");
196 	break;
197       case NODE:
198 	Printf("Net");
199 	break;
200       default:
201 	if (type < 0)
202 	   Printf("Error!");
203 	else
204 	   Printf("Pin %d", type);
205 	break;
206    }
207 }
208 
209 
210 
211 /*************************************************************************/
212 /*                                                                       */
213 /*    Some convenient routines for printing internal data structures     */
214 /*                                                                       */
215 /*************************************************************************/
216 
217 #ifndef TCL_NETGEN
218 
219 /*--------------------------------------------------------------*/
220 /* generate and print a list of elements that match a regexp	*/
221 /*--------------------------------------------------------------*/
222 
PrintElement(char * cell,char * list_template)223 void PrintElement(char *cell, char *list_template)
224 {
225 
226   struct objlist *list;
227 
228   if (strlen(cell))  CurrentCell = LookupCell(cell);
229   list = List(list_template);
230   Printf("Devices matching template: %s\n",list_template);
231   while (list != NULL) {
232     Printf ("   %s\n",list->name);
233     list = list->next;
234   }
235 }
236 
237 #else
238 
239 /*--------------------------------------------------------------*/
240 /* PrintElement() for use with Tcl---return all elements,	*/
241 /* let Tcl sort them out.					*/
242 /*--------------------------------------------------------------*/
243 
PrintAllElements(char * cell,int filenum)244 void PrintAllElements(char *cell, int filenum)
245 {
246   struct nlist *np;
247   struct objlist *ob;
248   char *sfx;
249 
250   if ((filenum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
251       PrintAllElements(cell, Circuit1->file);
252       PrintAllElements(cell, Circuit2->file);
253       return;
254   }
255 
256   if (((cell == NULL) || (*cell == '\0')) && (CurrentCell != NULL))
257       np = CurrentCell;
258   else
259       np = LookupCellFile(cell, filenum);
260 
261   if (np == NULL) {
262     Printf("Circuit '%s' not found.\n",cell);
263     return;
264   }
265 
266   ob = np->cell;
267   for (ob = np->cell; ob != NULL; ob = ob->next) {
268     if (ob->type == FIRSTPIN) {
269        if ((sfx = strrchr(ob->name, '/')) != NULL) *sfx = '\0';
270        Printf("%s\n", ob->name);
271        if (sfx != NULL) *sfx = '/';
272     }
273   }
274 }
275 
276 #endif
277 
278 /*--------------------------------------------------------------*/
279 /* Print connectivity between objects belonging to a specific	*/
280 /* node.  'filter' may be used to restrict the returned list to	*/
281 /* a specific type of object (node, element, port, pin, etc.).	*/
282 /*--------------------------------------------------------------*/
283 
Fanout(char * cell,char * node,int filter)284 void Fanout(char *cell, char *node, int filter)
285 {
286   struct nlist *np;
287   struct objlist *ob;
288   int nodenum;
289 
290   if (*cell == '\0') np = CurrentCell;
291   else np = LookupCell(cell);
292 
293   if (np == NULL) {
294     Printf("Cell '%s' not found.\n",cell);
295     return;
296   }
297 
298   nodenum = -999;
299   for (ob = np->cell; ob != NULL; ob = ob->next) {
300     if ((*matchfunc)(node, ob->name)) {
301       nodenum = ob->node;
302       break;
303     }
304   }
305 
306   /* now print out all elements that connect to that node */
307 
308   if (nodenum == -999)
309     Printf("Net '%s' not found in circuit '%s'.\n", node, cell);
310   else if (nodenum < 0)
311     Printf("Net '%s' is disconnected.\n", node);
312   else {
313     if (ob != NULL)
314        PrintObjectType(ob->type);
315     else
316        Printf("Object");
317     Printf (" '%s' in circuit '%s' connects to:\n", node, cell);
318     ob = np->cell;
319     while (ob != NULL) {
320       char *obname = ob->name;
321       if (*obname == '/') obname++;
322       if (ob->node == nodenum)
323 	 if (filter == ALLOBJECTS) {
324 	   Printf("  %s (", obname);
325 	   PrintObjectType(ob->type);
326 	   Printf(")\n");
327 	 }
328 	 else if ((filter == ALLELEMENTS) && (ob->type >= FIRSTPIN)) {
329 	   Printf("  %s\n", obname);
330 	 }
331 	 else if (ob->type == filter) {
332 	   Printf("  %s\n", obname);
333 	 }
334       ob = ob->next;
335     }
336   }
337 }
338 
339 #ifdef TCL_NETGEN
340 
341 /* Print the nodes connected to each pin of the specified element */
342 
ElementNodes(char * cell,char * element,int fnum)343 void ElementNodes(char *cell, char *element, int fnum)
344 {
345   struct nlist *np;
346   struct objlist *ob, *nob, *nob2;
347   int ckto;
348   char *elementname, *obname;
349 
350   if ((fnum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
351       ElementNodes(cell, element, Circuit1->file);
352       ElementNodes(cell, element, Circuit2->file);
353       return;
354   }
355 
356   if (((cell == NULL) || (*cell == '\0')) && (CurrentCell != NULL))
357       np = CurrentCell;
358   else
359       np = LookupCellFile(cell, fnum);
360 
361   if (np == NULL) {
362     Printf("Circuit '%s' not found.\n",cell);
363     return;
364   }
365 
366   elementname = element;
367   if (*elementname == '/') elementname++;
368 
369   ckto = strlen(elementname);
370   for (ob = np->cell; ob != NULL; ob = ob->next) {
371     obname = ob->name;
372     if (*obname == '/') obname++;
373     if (!strncmp(elementname, obname, ckto))
374        if (*(obname + ckto) == '/' || *(obname + ckto) == '\0')
375 	  break;
376   }
377   if (ob == NULL) {
378     Printf("Device '%s' not found in circuit '%s'.\n", elementname, cell);
379     return;
380   }
381 
382   Printf("Device '%s' Pins:\n", elementname);
383   for (; ob != NULL; ob = ob->next) {
384     obname = ob->name;
385     if (*obname == '/') obname++;
386     if (!strncmp(elementname, obname, ckto)) {
387        if (*(obname + ckto) != '/' && *(obname + ckto) != '\0')
388 	  continue;
389 
390        Printf("   ");
391        PrintObjectType(ob->type);
392        Printf(" (%s)", obname + ckto + 1);
393        for (nob = np->cell; nob != NULL; nob = nob->next) {
394 	 if (nob->node == ob->node) {
395 	    if (nob->type == NODE) {
396 	       Printf(" = %s", nob->name);
397 	       break;
398 	    }
399 	    else if (nob->type == PORT) {
400 	       Printf(" = %s (port of %s)", nob->name, cell);
401 	       break;
402 	    }
403 	    else if (nob->type == GLOBAL) {
404 	       Printf(" = %s (global)", nob->name);
405 	       break;
406 	    }
407 	    else if (nob->type == UNIQUEGLOBAL) {
408 	       Printf(" = %s (unique global)", nob->name);
409 	       break;
410 	    }
411  	 }
412        }
413        Printf("\n");
414     }
415   }
416 }
417 
418 #endif  /* TCL_NETGEN */
419 
420 /*----------------------------------------------------------------------*/
421 /* Find all nodes by name or wildcard pattern match, in the scope of	*/
422 /* the cell "cellname", and change them to the type given by "type".	*/
423 /* Changes are only allowed among nodes of type NODE, GLOBAL or		*/
424 /* UNIQUEGLOBAL.							*/
425 /*----------------------------------------------------------------------*/
426 
ChangeScopeCurrent(char * pattern,int typefrom,int typeto)427 int ChangeScopeCurrent(char *pattern, int typefrom, int typeto)
428 {
429    /* Note that List() is supposed to operate on CurrentCell	*/
430    /* but we want to be able to change scope on any cell.	*/
431 
432    struct objlist *plist, *psrch;
433    struct nlist *tp;
434    int numchanged = 0;
435 
436    plist = List(pattern);
437    while (plist != NULL) {
438       if (plist->type == typefrom) {
439          for (psrch = CurrentCell->cell; psrch != NULL; psrch = psrch->next) {
440 	    if (psrch->type == typefrom && (*matchfunc)(psrch->name, plist->name)) {
441 	       psrch->type = typeto;
442 	       Printf("Cell %s:  Net %s changed to %s\n",
443 		   CurrentCell->name, psrch->name, psrch->type == NODE ?
444 		   "local" : psrch->type == GLOBAL ? "global" :
445 		   psrch->type == UNIQUEGLOBAL ? "unique global" : "unknown");
446 	       numchanged++;
447 	    }
448 	 }
449       }
450       plist = plist->next;
451    }
452 
453    /* Recursively search descendants, if they exist */
454 
455    if (CurrentCell != NULL) {
456       for (psrch = CurrentCell->cell; psrch != NULL; psrch = psrch->next) {
457          if (psrch->type == FIRSTPIN) {
458 	    numchanged += ChangeScope(CurrentCell->file, psrch->model.class,
459 			pattern, typefrom, typeto);
460          }
461       }
462    }
463 
464    return numchanged;
465 }
466 
467 /* Structure to pass information to doglobalscope() */
468 
469 typedef struct _gsd {
470    int fnum;
471    char *pattern;
472    int typefrom;
473    int typeto;
474    int *numchanged;
475 } gsdata;
476 
477 /*----------------------------------------------------------------------*/
478 /* Function called by hash search on cells, to call ChangeScopeCurrent	*/
479 /*----------------------------------------------------------------------*/
480 
doglobalscope(struct hashlist * p,void * clientdata)481 struct nlist *doglobalscope(struct hashlist *p, void *clientdata)
482 {
483    struct nlist *ptr;
484    struct objlist *ob, *lob, *nob;
485    int file, numchanged;
486    gsdata *gsd = (gsdata *)clientdata;
487 
488    ptr = (struct nlist *)(p->ptr);
489    file = gsd->fnum;
490 
491    if ((file != -1) && (ptr->file != file)) return NULL;
492 
493    CurrentCell = ptr;
494    numchanged = ChangeScopeCurrent(gsd->pattern, gsd->typefrom, gsd->typeto);
495    *(gsd->numchanged) += numchanged;
496 
497    return ptr;
498 }
499 
500 /*----------------------------------------------------------------------*/
501 /* Wrapper for ChangeScopeCurrent().  Takes a cellname as an 		*/
502 /* argument, instead of assuming the existance of a valid CurrentCell	*/
503 /*----------------------------------------------------------------------*/
504 
ChangeScope(int fnum,char * cellname,char * pattern,int typefrom,int typeto)505 int ChangeScope(int fnum, char *cellname, char *pattern, int typefrom, int typeto)
506 {
507    struct nlist *SaveCell, *tp;
508    int numchanged = 0;
509 
510    if ((fnum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
511       numchanged += ChangeScope(Circuit1->file, cellname,
512 			pattern, typefrom, typeto);
513       numchanged += ChangeScope(Circuit2->file, cellname,
514 			pattern, typefrom, typeto);
515       return numchanged;
516    }
517 
518    SaveCell = CurrentCell;
519 
520    if (cellname == NULL) {
521       /* No cellname given, so search all cells in file fnum */
522       gsdata locdata;
523 
524       locdata.fnum = fnum;
525       locdata.pattern = pattern;
526       locdata.typefrom = typefrom;
527       locdata.typeto = typeto;
528       locdata.numchanged = &numchanged;
529 
530       RecurseCellHashTable2(doglobalscope, (void *)(&locdata));
531    }
532    else {
533 
534       CurrentCell = LookupCellFile(cellname, fnum);
535       if (CurrentCell != NULL) {
536          numchanged = ChangeScopeCurrent(pattern, typefrom, typeto);
537       }
538       else {
539          Printf("No circuit '%s' found.\n", cellname);
540       }
541    }
542    CurrentCell = SaveCell;
543    return numchanged;
544 }
545 
546 /*--------------------------------------------------------------------*/
547 /* print all nodes in cell 'name', together with their connectivities */
548 /*--------------------------------------------------------------------*/
549 
550 typedef struct _noderecord {
551   char *name;					/* node name */
552   int uniqueglobal, global, port, node, pin;	/* counts */
553 } noderecord;
554 
PrintNodes(char * name,int filenum)555 void PrintNodes(char *name, int filenum)
556 {
557   int nodenum, nodemax;
558   struct nlist *tp;
559   struct objlist *ob;
560   int maxnamelen;
561   noderecord *nodelist;
562   int uniqueglobals, globals, ports, nodes, pins;
563 
564   if ((filenum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
565       PrintNodes(name, Circuit1->file);
566       PrintNodes(name, Circuit2->file);
567       return;
568   }
569 
570   tp = LookupCellFile(name, filenum);
571 
572   if (tp == NULL) {
573     Printf ("No circuit '%s' found.\n",name);
574     return;
575   }
576   Printf("Circuit: '%s'\n",tp->name);
577 
578   nodemax = 0;
579   maxnamelen = 0;
580   for (ob = tp->cell; ob != NULL; ob = ob->next) {
581     int len = strlen(NodeAlias(tp, ob));
582     if (len > maxnamelen) maxnamelen = len;
583     if (ob->node > nodemax) nodemax = ob->node;
584   }
585   nodelist = (noderecord *) CALLOC((nodemax + 1), sizeof(noderecord));
586 
587   for (ob = tp->cell; ob != NULL; ob = ob->next) {
588     nodenum = ob->node;
589     if (nodenum < 0) continue;
590     /* repeat bits of objlist.c here for speed */
591     if (tp->nodename_cache != NULL) {
592       nodelist[nodenum].name = tp->nodename_cache[nodenum]->name;
593     }
594     else {
595       /* Overwrite name, in order of precedence */
596       if ((nodelist[nodenum].port == 0) &&
597 	  ((IsPort(ob)) ||
598 	  ((nodelist[nodenum].node == 0) &&
599 	  ((ob->type == NODE) ||
600 	  ((nodelist[nodenum].uniqueglobal == 0) &&
601 	  ((ob->type == UNIQUEGLOBAL) ||
602 	  ((nodelist[nodenum].global == 0) &&
603 	  ((ob->type == GLOBAL) ||
604 	  ((nodelist[nodenum].pin == 0) &&
605 	  (ob->type >= FIRSTPIN))))))))))
606 	nodelist[nodenum].name = ob->name;
607 
608     }
609     switch (ob->type) {
610       case UNIQUEGLOBAL:
611 	nodelist[nodenum].uniqueglobal++; break;
612       case GLOBAL:
613 	nodelist[nodenum].global++; break;
614       case PORT:
615 	nodelist[nodenum].port++; break;
616       case NODE:
617 	nodelist[nodenum].node++; break;
618       case PROPERTY:
619 	break;
620       default:
621 	nodelist[nodenum].pin++; break;
622     }
623   }
624 
625   for (nodenum = 0; nodenum <= nodemax; nodenum++) {
626     if (nodelist[nodenum].name == NULL) continue;
627 
628     pins = nodelist[nodenum].pin;
629     ports = nodelist[nodenum].port;
630     globals = nodelist[nodenum].global;
631     uniqueglobals = nodelist[nodenum].uniqueglobal;
632     nodes = nodelist[nodenum].node;
633 
634     Printf("Net %d (%s):", nodenum, nodelist[nodenum].name);
635     Ftab(NULL, maxnamelen + 15);
636     Printf("Total = %d,", pins + ports + nodes + globals + uniqueglobals);
637     if (ports)
638       Printf(" Ports = %d,", ports);
639     Ftab(NULL, maxnamelen + 40);
640     if (pins)
641       Printf("Pins = %d,", pins);
642     Ftab(NULL, maxnamelen + 52);
643     if (nodes)
644       Printf("Nets = %d,", nodes);
645     Ftab(NULL, maxnamelen + 63);
646     if (globals)
647       Printf("Globals = %d,", globals);
648     Ftab(NULL, maxnamelen + 80);
649     if (uniqueglobals)
650       Printf("UniqueGlobals = %d", uniqueglobals);
651     Printf("\n");
652   }
653 
654   FREE(nodelist);
655 }
656 
PrintCell(char * name,int fnum)657 void PrintCell(char *name, int fnum)
658 {
659   struct nlist *tp;
660   struct objlist *ob;
661   int maxnamelen;
662 
663   if ((fnum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
664       PrintCell(name, Circuit1->file);
665       PrintCell(name, Circuit2->file);
666       return;
667   }
668 
669   tp = LookupCellFile(name, fnum);
670   if (tp == NULL) {
671     Printf ("No circuit '%s' found.\n",name);
672     return;
673   }
674   maxnamelen = 0;
675   for (ob = tp->cell; ob != NULL; ob = ob->next) {
676 	  int len;
677 	  if ((len = strlen(ob->name)) > maxnamelen) maxnamelen = len;
678   }
679 
680   Printf("Circuit: '%s'\n", tp->name);
681   for (ob = tp->cell; ob != NULL; ob = ob->next) {
682     Printf ("%s ", ob->name[1] == ':' ? ob->name : ob->name);
683     Ftab(NULL, maxnamelen + 2);
684     switch (ob->type) {
685       case UNIQUEGLOBAL:
686 	Printf("unique global"); break;
687       case GLOBAL:
688 	Printf("global"); break;
689       case PORT:
690 	Printf("port"); break;
691       case NODE:
692 	Printf("node"); break;
693       case PROPERTY:
694 	Printf("properties"); break;
695       default:
696 	Printf("pin %d", ob->type);
697 	break;
698     }
699     Ftab(NULL, 40);
700     if (ob->type != PROPERTY)
701        Printf(" Net #: %d", ob->node);
702     Printf("\n");
703   }
704 }
705 
PrintInstances(char * name,int filenum)706 void PrintInstances(char *name, int filenum)
707 {
708   struct nlist *tp;
709   struct objlist *ob;
710   int instancecount;
711 
712   if ((filenum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
713       PrintInstances(name, Circuit1->file);
714       PrintInstances(name, Circuit2->file);
715       return;
716   }
717 
718   tp = LookupCellFile(name, filenum);
719   if (tp == NULL) {
720     Printf ("No circuit '%s' found.\n",name);
721     return;
722   }
723   Printf("Circuit: '%s'\n",tp->name);
724   instancecount = 0;
725   for (ob = tp->cell; ob != NULL; ob = ob->next) {
726     if (ob->type == FIRSTPIN) {
727       struct objlist *ob2;
728       int port, node, global, uniqueglobal, pin;
729       int ports, nodes, globals, uniqueglobals, pins;
730 
731       port = node = global = uniqueglobal = pin = 0;
732       instancecount++;
733 
734       ob2 = ob;
735       do {
736 	struct objlist *ob3;
737 
738 	ports = nodes = globals = uniqueglobals = pins = 0;
739 	for (ob3 = tp->cell; ob3 != NULL; ob3 = ob3->next)
740 	  if (ob3->node == ob2->node)
741 	    switch (ob3->type) {
742 	    case UNIQUEGLOBAL: uniqueglobals++; break;
743 	    case GLOBAL: globals++; break;
744 	    case PORT:   ports++; break;
745 	    case NODE:   nodes++; break;
746 	    case PROPERTY: break;
747 	    default:     pins++; break;
748 	    }
749 	pin++;
750 	if (uniqueglobals) uniqueglobal++;
751 	else if (globals) global++;
752 	else if (ports) port++;
753 	else if (nodes) node++;
754 	ob2 = ob2->next;
755       } while (ob2 != NULL && ob2->type > FIRSTPIN);
756 /*      Fflush(stdout); */
757       Printf("%s (class: %s)", ob->instance, ob->model.class);
758       Ftab(NULL,35);
759       Printf("%2d pins ->",pin);
760       if (port) Printf("%2d ports,",port);
761       Ftab(NULL,55);
762       if (node) Printf("%2d nodes,",node);
763       Ftab(NULL,65);
764       if (global) Printf("%2d globals,",global);
765       Ftab(NULL,75);
766       if (uniqueglobal) Printf("%2d ug",uniqueglobal);
767       Printf("\n");
768     }
769   }
770   Printf("Cell %s contains %d instances.\n",name,instancecount);
771 }
772 
DescribeInstance(char * name,int file)773 void DescribeInstance(char *name, int file)
774 {
775   struct nlist *tp, *tp2;
776   struct objlist *ob;
777   unsigned char *instlist;
778   int nodemax, nodenum;
779 
780   int instancecount;
781   int node, nodenumber, morenodes, disconnectednodes;
782 
783   if ((file == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
784       DescribeInstance(name, Circuit1->file);
785       DescribeInstance(name, Circuit2->file);
786       return;
787   }
788 
789   tp = LookupCellFile(name, file);
790 
791   if (tp == NULL) {
792     Printf("No circuit '%s' found.\n",name);
793     return;
794   }
795   Printf("Circuit: '%s'\n",tp->name);
796 
797   /* First pass counts total number of entries */
798   nodemax = 0;
799   disconnectednodes = 0;
800   for (ob = tp->cell; ob != NULL; ob = ob->next)
801   {
802     if (ob->node > nodemax) nodemax = ob->node;
803     else if ((ob->node == -1) && (ob->model.port != PROXY)) {
804 
805       /* All black-box modules and placeholders by definition have all	*/
806       /* disconnected pins, so don't report those.			*/
807 
808       if (!(tp->flags & CELL_PLACEHOLDER) && (tp->class != CLASS_MODULE))
809       {
810 	//if (disconnectednodes == 0) Fprintf(stderr, "\n");
811         disconnectednodes++;
812         Fprintf(stderr, "Cell %s(%d) disconnected node: %s\n", tp->name, tp->file, ob->name);
813       }
814     }
815   }
816   instlist = (unsigned char *) CALLOC((nodemax + 1), sizeof(unsigned char));
817 
818   /* Second pass finds total number of unique nodes */
819   for (ob = tp->cell; ob != NULL; ob = ob->next)
820     if (ob->node > 0)
821       instlist[ob->node] = (unsigned char) 1;
822 
823   /* Now add them all together */
824   nodenumber = 0;
825   for (nodenum = 1; nodenum <= nodemax; nodenum++)
826      if (instlist[nodenum] == (unsigned char) 1) nodenumber++;
827 
828   /* And we're done with this record */
829   FREE(instlist);
830 
831   /* Now collect the relevant information per node */
832 
833   ClearDumpedList();
834 
835   instancecount = 0;
836   for (ob = tp->cell; ob != NULL; ob = ob->next) {
837     if (ob->type == FIRSTPIN) {
838       instancecount++;
839       tp2 = LookupCellFile(ob->model.class, tp->file);
840       tp2->dumped++;
841     }
842   }
843   Printf("Circuit %s contains %d device instances.\n", name, instancecount);
844 
845   /* print out results */
846   tp = FirstCell();
847   while (tp != NULL) {
848     if (tp->dumped) {
849       Printf("  Class: %s", tp->name);
850       Ftab(NULL, 30);
851       Printf(" instances: %3d\n", tp->dumped);
852     }
853     tp = NextCell();
854   }
855   Printf("Circuit contains %d nets", nodenumber);
856   if (disconnectednodes)
857     Printf(", and %d disconnected pin%s", disconnectednodes,
858 		((disconnectednodes == 1) ? "" : "s"));
859   Printf(".\n");
860 
861 }
862 
PrintPortsInCell(char * cellname,int filenum)863 void PrintPortsInCell(char *cellname, int filenum)
864 {
865   struct nlist *np;
866   struct objlist *ob;
867   int portcount;
868 
869   if ((filenum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
870       PrintPortsInCell(cellname, Circuit1->file);
871       PrintPortsInCell(cellname, Circuit2->file);
872       return;
873   }
874 
875   np = LookupCellFile(cellname, filenum);
876   if (np == NULL) {
877     Printf("No circuit: %s\n",cellname);
878     return;
879   }
880   portcount = 0;
881   for (ob = np->cell; ob != NULL; ob = ob->next)
882     if (IsPort(ob)) {
883       portcount++;
884       Printf("%s\n", ob->name);
885     }
886   Printf("Cell %s contains %d ports.\n",cellname, portcount);
887 }
888 
PrintLeavesInCell(char * cellname,int filenum)889 void PrintLeavesInCell(char *cellname, int filenum)
890 {
891   struct nlist *np;
892   struct objlist *ob;
893   int am_a_leaf;
894 
895   if ((filenum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
896       PrintLeavesInCell(cellname, Circuit1->file);
897       PrintLeavesInCell(cellname, Circuit2->file);
898       return;
899   }
900 
901   np = LookupCellFile(cellname, filenum);
902   if (np == NULL) {
903     Printf("No circuit: %s\n",cellname);
904     return;
905   }
906   if (np->dumped) return;
907   np->dumped = 1;
908 
909   if (np->class != CLASS_SUBCKT) {
910     Printf("%s; %d ports; Primitive.\n", cellname, NumberOfPorts(cellname, filenum));
911     return;
912   }
913 
914   /* otherwise, consider it's children */
915   am_a_leaf = 1; /* assume I am a leaf */
916   for (ob = np->cell; ob != NULL; ob = ob->next)
917     if (ob->type == FIRSTPIN) {
918       /* if I contain an instance, I cannot be a leaf */
919       PrintLeavesInCell(ob->model.class, filenum);
920       am_a_leaf = 0;
921     }
922 
923   if (am_a_leaf) Printf("%s; %d ports\n", cellname, NumberOfPorts(cellname, filenum));
924   return;
925 }
926 
PrintLeavesInCellHash(struct hashlist * p)927 static int PrintLeavesInCellHash(struct hashlist *p)
928 /* print leaves in hash table that are INSTANCED by other cells */
929 {
930   struct nlist *ptr;
931 
932   ptr = (struct nlist *)(p->ptr);
933   if ((ptr->class == CLASS_SUBCKT)) PrintLeavesInCell(ptr->name, ptr->file);
934   return(0);
935 }
936 
PrintAllLeaves(void)937 void PrintAllLeaves(void)
938 {
939   ClearDumpedList();
940   RecurseCellHashTable(PrintLeavesInCellHash);
941 }
942 
943 static jmp_buf jmpenv;
944 
945 /* static void handler(void) */
handler(int sig)946 static void handler(int sig)
947 {
948   fprintf(stderr,"\nInterrupt (%d)!!\n", sig);
949   fflush(stderr);
950   longjmp(jmpenv,1);
951 }
952 
953 #ifndef TCL_NETGEN
954 
Query(void)955 void Query(void)
956 {
957   /* little interactive debugger */
958   char reply;
959   char repstr[100];
960   char repstr2[100];
961   float StartTime;   /* for elapsed CPU times */
962   int Timing;  /* if true, print times of each command */
963   int filenum = -1;
964 
965   if (!SuppressPrompts)
966     Printf("Netgen %s.%s: %s, %s, %s\n", NETGEN_VERSION, NETGEN_REVISION,
967 		NETGEN_COPYRIGHT, NETGEN_AUTHOR, NETGEN_DEVELOPER);
968   setjmp(jmpenv);
969   signal(SIGINT,handler);
970   Timing = 0;
971   StartTime = 0.0;
972   do {
973     promptstring("NETGEN command: ",repstr);
974     if (Timing) StartTime = CPUTime();
975     reply = repstr[0];
976     switch (reply) {
977     case 'h' : PrintCellHashTable(0, filenum); break;
978     case 'H' : PrintCellHashTable(1, filenum); break;
979     case 'N' :
980       promptstring("Enter circuit name: ", repstr);
981       PrintNodes(repstr, -1);
982       break;
983     case 'n' :
984       promptstring("Enter element name: ", repstr);
985       if (CurrentCell == NULL)
986 	promptstring("Enter circuit name:    ", repstr2);
987       else strcpy(repstr2, CurrentCell->name);
988       Fanout(repstr2, repstr, ALLOBJECTS);
989       break;
990     case 'e' :
991       promptstring("Enter element name: ", repstr);
992       if (CurrentCell == NULL)
993 	promptstring("Enter circuit name:    ", repstr2);
994       else strcpy(repstr2, CurrentCell->name);
995       PrintElement(repstr2,repstr);
996       break;
997     case 'c' :
998       promptstring("Enter circuit name: ", repstr);
999       PrintCell(repstr, filenum);
1000       break;
1001     case 'i' :
1002       promptstring("Enter circuit name: ", repstr);
1003       PrintInstances(repstr, filenum);
1004       break;
1005     case 'd':
1006       promptstring("Enter circuit name: ", repstr);
1007       DescribeInstance(repstr, filenum);
1008       break;
1009 /* output file formats */
1010     case 'k' :
1011       promptstring("Write NTK: Enter circuit name: ", repstr);
1012       Ntk(repstr,"");
1013       break;
1014     case 'x' :
1015       promptstring("Write EXT: Enter circuit name: ", repstr);
1016       Ext(repstr, filenum);
1017       break;
1018     case 'z' :
1019       promptstring("Write SIM: Enter circuit name: ", repstr);
1020       Sim(repstr, filenum);
1021       break;
1022     case 'w' :
1023       promptstring("Write WOMBAT: circuit name: ", repstr);
1024       Wombat(repstr,NULL);
1025       break;
1026     case 'a' :
1027       promptstring("Write ACTEL: circuit name: ", repstr);
1028       Actel(repstr,"");
1029       break;
1030     case 's':
1031       promptstring("Write SPICE: circuit name: ", repstr);
1032       SpiceCell(repstr, filenum, "");
1033       break;
1034     case 'v':
1035       promptstring("Write Verilog: circuit name: ", repstr);
1036       VerilogTop(repstr, filenum, "");
1037       break;
1038     case 'E':
1039       promptstring("Write ESACAP: circuit name: ", repstr);
1040       EsacapCell(repstr,"");
1041       break;
1042     case 'g':
1043       promptstring("Write NETGEN: circuit name: ", repstr);
1044       WriteNetgenFile(repstr,"");
1045       break;
1046     case 'C':
1047       promptstring("Write C code: circuit name: ", repstr);
1048       Ccode(repstr,"");
1049       break;
1050 /* input file formats */
1051     case 'r':
1052     case 'R':
1053       promptstring("Read file: ",repstr);
1054       ReadNetlist(repstr, &filenum);
1055       break;
1056     case 'X' :
1057       promptstring("Read EXT: Enter file name: ", repstr);
1058       ReadExtHier(repstr, &filenum);
1059       break;
1060     case 'Z' :
1061       promptstring("Read SIM: Enter file name: ", repstr);
1062       ReadSim(repstr, &filenum);
1063       break;
1064     case 'K' :
1065       promptstring("Read NTK: file? ", repstr);
1066       ReadNtk(repstr, &filenum);
1067       break;
1068     case 'A' :
1069       printf("Reading ACTEL library.\n");
1070       ActelLib();
1071       break;
1072     case 'S':
1073       promptstring("Read SPICE (.spice) file? ", repstr);
1074       ReadSpice(repstr, &filenum);
1075       break;
1076     case 'V':
1077       promptstring("Read Verilog (.v) file? ", repstr);
1078       ReadVerilog(repstr, &filenum);
1079       break;
1080     case 'G' :
1081       promptstring("Read NETGEN: file? ", repstr);
1082       ReadNetgenFile(repstr, &filenum);
1083       break;
1084 
1085     case 'f' :
1086       promptstring("Enter circuit name to flatten: ", repstr);
1087       Flatten(repstr, filenum);
1088       break;
1089     case 'F' :
1090       promptstring("Enter class of circuit to flatten: ", repstr);
1091       FlattenInstancesOf(repstr, filenum);
1092       break;
1093     case 'p' :
1094       promptstring("Enter circuit name: ", repstr);
1095       PrintPortsInCell(repstr, filenum);
1096       break;
1097     case 'T' :
1098       NETCOMP();
1099       break;
1100     case 'l' :
1101       ClearDumpedList();
1102       promptstring("Enter circuit name: ", repstr);
1103       PrintLeavesInCell(repstr, filenum);
1104       break;
1105     case 'L' :
1106       printf("List of all leaf circuits:\n");
1107       PrintAllLeaves();
1108       break;
1109     case 'D' : Debug = !Debug;
1110       printf("Debug mode is %s\n", Debug?"ON":"OFF");
1111       break;
1112     case 't': StartTime = CPUTime();
1113       Timing = !Timing;
1114       printf("Timing of commands %s.\n", Timing?"enabled":"disabled");
1115       break;
1116     case '#':
1117       if (strlen(repstr) > 1) {
1118 	char *command;
1119 	command = repstr+1;
1120 	DBUG_PUSH(command);
1121       }
1122       else {
1123 	promptstring("Dbug command? ",repstr);
1124 	DBUG_PUSH(repstr);
1125       }
1126       break;
1127     case '!':
1128 #ifdef IBMPC
1129       system("");
1130 #else
1131       system("/bin/csh");
1132 #endif
1133       break;
1134     case 'I' : Initialize(); break;
1135     case 'q' : break;
1136     case 'Q' : exit(0);
1137     case 'P' : PROTOCHIP(); break;
1138 #ifdef HAVE_MALLINFO
1139     case 'm': PrintMemoryStats(); break;
1140 #endif
1141     case '<' :
1142       {
1143 	FILE *oldfile;
1144 	promptstring("Read from file? ",repstr);
1145 	oldfile = promptstring_infile;
1146 	promptstring_infile = fopen(repstr,"r");
1147 	if (promptstring_infile == NULL)
1148 	  Printf("Unable to open command file: %s\n", repstr);
1149 	else {
1150 	  Query();
1151 	  fclose(promptstring_infile);
1152 	}
1153 	promptstring_infile = oldfile;
1154 	break;
1155       }
1156     default :
1157       fflush(stdout);
1158       if (strlen(repstr)) fprintf(stderr,"Unknown command: %c\n",reply);
1159       fflush(stderr);
1160       printf(
1161 "WRITE: nt(k),e(x)t,sim (z),(w)ombat,(a)ctel,net(g)en,(s)pice,(E)sacap,(C)\n");
1162       printf(
1163 "READ:  (r)ead, nt(K), e(X)t, sim (Z), (A)ctel library, net(G)en, (S)pice\n");
1164       printf(
1165 "Print LISTS: (d)escribe circuit (c)ontents, (i)nstances, (p)orts, (l)eaves (L)\n"
1166 	    );
1167       printf(
1168 "PRINT: (n)ode connectivity (N), (e)lement list, (h)ash table entries (H))\n");
1169       printf(
1170 "CELL OPS: (f)latten circuit, (F)latten instance, make circuit primiti(v)e (V=all)\n"
1171 	    );
1172 
1173       printf("toggle (D)ebug, (t)ime commands, embed (P)rotochip, ne(T)cmp\n");
1174       printf("(!) push shell, (<) read input file");
1175 
1176 #ifdef HAVE_MALLINFO
1177       printf(", show (m)emory usage");
1178 #endif
1179       printf("\n");
1180       printf("(q)uit, (Q)uit immediately, re-(I)nitialize \n");
1181       break;
1182     }
1183     if (Timing) {
1184       printf("CPU time used by last operation = %0.2f s\n",
1185 	     ElapsedCPUTime(StartTime));
1186       fflush(stdout); /* just in case we have been redirected */
1187     }
1188   } while (reply != 'q');
1189   signal(SIGINT,SIG_DFL);
1190 }
1191 
1192 #endif
1193