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