1 /*----------------------------------------------------------------------*/
2 /* netlist.c --- xcircuit routines specific to schematic capture and */
3 /* netlist generation */
4 /*----------------------------------------------------------------------*/
5 /* Copyright (c) 2004 Tim Edwards, Johns Hopkins University, */
6 /* MultiGiG, Inc., and Open Circuit Design, Inc. */
7 /* Copyright (c) 2005 Tim Edwards, MultiGiG, Inc. */
9 /* Written April 1998 to January 2004 */
10 /* Original version for Pcb netlisting 3/20/98 by Chow Seong Hwai, */
11 /* Leeds University, U.K. */
13 /* Greatly modified 4/2/04 to handle bus notation; net identifier */
14 /* changed from a listing by net to two listings, by polygon and by */
15 /* label, with nets and subnets identifiers attached to each element, */
16 /* rather than vice versa. */
17 /*----------------------------------------------------------------------*/
24 #include <sys/types.h> /* For preventing multiple file inclusions, use stat() */
35 #include <X11/Intrinsic.h>
36 #include <X11/StringDefs.h>
43 /*----------------------------------------------------------------------*/
45 /*----------------------------------------------------------------------*/
48 #include "colordefs.h"
50 /*----------------------------------------------------------------------*/
51 /* Function prototype declarations */
52 /*----------------------------------------------------------------------*/
53 #include "prototypes.h"
56 extern PyObject
*PyGetStringParts(stringpart
*);
59 extern Tcl_Interp
*xcinterp
;
60 extern Tcl_Obj
*TclGetStringParts(stringpart
*);
63 /*----------------------------------------------------------------------*/
64 /* Externally declared global variables */
65 /*----------------------------------------------------------------------*/
69 /*----------------------------------------------------------------------*/
71 extern char _STR
[150];
72 extern char _STR2
[250];
73 extern XCWindowData
*areawin
;
74 extern Globaldata xobjs
;
75 extern Boolean load_in_progress
;
76 extern int number_colors
;
77 extern colorindex
*colorlist
;
79 LabellistPtr global_labels
;
81 typedef struct _flatindex
*fidxptr
;
83 typedef struct _flatindex
{
87 } flatindex
; /* count for labeling devices in a flattened file */
89 flatindex
*flatrecord
= NULL
;
91 static char *spice_devname
= "X"; /* SPICE subcircuit device name */
92 Boolean spice_end
= True
; /* whether or not to write a .end statement */
93 ino_t
*included_files
= NULL
; /* Files included with "%F" escape */
95 #define EndPoint(n) (((n == 1) ? 1 : (int)(n - 1)))
96 #define NextPoint(n) (((n == 1) ? 0 : 1))
98 /* For bus matching: whether to match by number of nets, by */
99 /* exact match of sub-bus numbers, or an exact match of net IDs. */
101 #define MATCH_EXACT 0
102 #define MATCH_SUBNETS 1
104 #define MATCH_OVERLAP 3
106 /*----------------------------------------------------------------------*/
107 /* Check whether two line segments attach to or cross each other */
108 /* Return 1 if attached, 0 if not (INLINE code) */
109 /* int onsegment(XPoint *a, XPoint *b, XPoint *x) {} */
110 /*----------------------------------------------------------------------*/
112 #define ONDIST 4 /* "slack" in algorithm for almost-touching lines */
113 #define onsegment(a, b, x) (finddist(a, b, x) <= ONDIST)
115 /*--------------------------------------------------------------*/
116 /* d36a: Base 36 to string conversion */
117 /*--------------------------------------------------------------*/
119 char *d36a(int number
)
121 static char bconv
[10];
128 while ((locn
> 0) && (i
>= 0)) {
131 bconv
[i
--] = (rem
< 10) ? (rem
+ '0') : (rem
- 10 + 'A');
133 return &bconv
[i
+ 1];
136 /*--------------------------------------------------------------*/
137 /* Translate a pin name to a position relative to an object's */
138 /* point of origin. This is used by the ASG module to find */
139 /* the placement of pins based on names from a netlist. */
141 /* returns 0 on success and fills x_ret and y_ret with the */
142 /* pin position coordinates. Returns -1 if the pin name did */
143 /* not match any label names in the object. */
144 /*--------------------------------------------------------------*/
146 int NameToPinLocation(objinstptr thisinst
, char *pinname
, int *x_ret
, int *y_ret
)
148 objectptr thisobj
= thisinst
->thisobject
;
152 if (thisobj
->schemtype
== SECONDARY
)
153 thisobj
= thisobj
->symschem
;
155 for (pgen
= thisobj
->plist
; pgen
< thisobj
->plist
+ thisobj
->parts
; pgen
++) {
156 if (IS_LABEL(*pgen
)) {
157 plab
= TOLABEL(pgen
);
158 if (plab
->pin
!= False
&& plab
->pin
!= INFO
) {
159 if (!textcomp(plab
->string
, pinname
, thisinst
)) {
160 *x_ret
= (int)plab
->position
.x
;
161 *y_ret
= (int)plab
->position
.y
;
170 /*--------------------------------------------------------------*/
171 /* Translate a point position back to the calling object's */
172 /* coordinate system. */
173 /* Original value is passed in "thispoint"; Translated value */
174 /* is put in "refpoint". */
175 /*--------------------------------------------------------------*/
177 void ReferencePosition(objinstptr thisinst
, XPoint
*thispoint
, XPoint
*refpoint
)
179 /* objectptr thisobj = thisinst->thisobject; (jdk) */
182 /* Translate pin position back to originating object */
185 UPreMultCTM(&locctm
, thisinst
->position
, thisinst
->scale
,
187 UTransformbyCTM(&locctm
, thispoint
, refpoint
, 1);
190 /*--------------------------------------------------------------*/
191 /* Variant of NameToPinLocation(): Given a port number, find */
192 /* the pin associated with that port. */
193 /*--------------------------------------------------------------*/
195 labelptr
PortToLabel(objinstptr thisinst
, int portno
)
198 objectptr thisobj
= thisinst
->thisobject
;
201 if ((thisobj
->schemtype
== SYMBOL
) && (thisobj
->symschem
!= NULL
))
202 ports
= thisobj
->symschem
->ports
;
204 ports
= thisobj
->ports
;
206 for (; ports
!= NULL
; ports
= ports
->next
) {
207 if (ports
->portid
== portno
) {
208 plab
= NetToLabel(ports
->netid
, thisobj
); /* in the symbol! */
215 /*--------------------------------------------------------------*/
216 /* This function is the same as PortToLocalPosition() but */
217 /* returns the point in the coordinate system of the parent. */
218 /*--------------------------------------------------------------*/
220 Boolean
PortToPosition(objinstptr thisinst
, int portno
, XPoint
*refpoint
)
222 labelptr plab
= PortToLabel(thisinst
, portno
);
224 ReferencePosition(thisinst
, &(plab
->position
), refpoint
);
226 return (plab
!= NULL
) ? TRUE
: FALSE
;
229 /*----------------------------------------------------------------------*/
230 /* Get the hierarchy of the page stack and return as a string */
231 /*----------------------------------------------------------------------*/
233 Boolean
getnexthier(pushlistptr stack
, char **hierstr
, objinstptr callinst
,
236 objectptr topobj
, thisobj
;
238 /* char numstr[12]; (jdk) */
242 if (!stack
) return False
;
244 /* Recurse so we build up the prefix string from top down */
245 if (stack
->next
!= NULL
) {
246 if (getnexthier(stack
->next
, hierstr
, stack
->thisinst
, canonical
) == False
)
250 topobj
= stack
->thisinst
->thisobject
;
252 if (topobj
->schemtype
!= PRIMARY
&& topobj
->symschem
!= NULL
)
253 topobj
= topobj
->symschem
;
255 if (topobj
->calls
== NULL
) {
256 if (topobj
->schemtype
== FUNDAMENTAL
) {
257 /* Top level is a fundamental symbol */
260 else if ((updatenets(stack
->thisinst
, FALSE
) <= 0) || (topobj
->calls
== NULL
)) {
261 Wprintf("Error in generating netlists!");
267 thisobj
= stack
->thisinst
->thisobject
;
269 /* When we have "traveled" through both a symbol and its */
270 /* associated schematic, only append the prefix for the */
271 /* first one encountered. */
274 if (thisobj->symschem != NULL && stack->next != NULL &&
275 thisobj->symschem == stack->next->thisinst->thisobject)
279 if ((thisobj
->calls
== NULL
) && (thisobj
->schemtype
!= PRIMARY
)
280 && (thisobj
->symschem
!= NULL
))
281 thisobj
= thisobj
->symschem
;
283 /* Check for resolved device indices and generate them if necessary */
285 for (calls
= thisobj
->calls
; calls
!= NULL
; calls
= calls
->next
)
286 if (calls
->callinst
== callinst
)
287 if (calls
->devindex
== -1) {
288 cleartraversed(thisobj
);
289 resolve_indices(thisobj
, FALSE
);
293 /* Add this level of the hierarchy to the prefix string */
295 for (calls
= thisobj
->calls
; calls
!= NULL
; calls
= calls
->next
) {
296 if (calls
->callinst
== callinst
) {
297 devlen
= (canonical
|| calls
->devname
== NULL
) ?
298 strlen(callinst
->thisobject
->name
) : strlen(calls
->devname
);
299 devstr
= d36a(calls
->devindex
);
300 devlen
+= strlen(devstr
) + 1;
301 if (*hierstr
== NULL
) {
302 *hierstr
= malloc(devlen
);
306 hierlen
= strlen(*hierstr
) + 2;
307 *hierstr
= realloc(*hierstr
, hierlen
+ devlen
);
310 sprintf(*hierstr
+ hierlen
, "%s%s(%s)",
311 ((hierlen
> 0) ? "/" : ""),
312 callinst
->thisobject
->name
, devstr
);
314 sprintf(*hierstr
+ hierlen
, "%s%s%s",
315 ((hierlen
> 0) ? "/" : ""),
316 (calls
->devname
== NULL
) ? callinst
->thisobject
->name
317 : calls
->devname
, devstr
);
324 /*----------------------------------------------------------------------*/
326 char *GetHierarchy(pushlistptr
*stackptr
, Boolean canonical
)
328 Boolean pushed_top
= FALSE
;
331 if ((*stackptr
) && ((*stackptr
)->thisinst
!= areawin
->topinstance
)) {
333 push_stack(stackptr
, areawin
->topinstance
, NULL
);
336 getnexthier(*stackptr
, &snew
, NULL
, canonical
);
338 if (pushed_top
) pop_stack(stackptr
);
343 /*----------------------------------------------------------------------*/
344 /* Invalidate a netlist. The invalidation must be referred to the */
345 /* master schematic, if the object is a secondary schematic. */
346 /*----------------------------------------------------------------------*/
348 void invalidate_netlist(objectptr thisobject
)
350 if (thisobject
->schemtype
!= NONETWORK
) {
351 if (thisobject
->schemtype
== SECONDARY
)
352 thisobject
->symschem
->valid
= False
;
354 thisobject
->valid
= False
;
358 /*--------------------------------------------------------------*/
359 /* Check if the selected items are relevant to the netlist. */
360 /* Only invalidate the current netlist if they are. */
361 /*--------------------------------------------------------------*/
363 void select_invalidate_netlist()
366 Boolean netcheck
= FALSE
;
368 for (i
= 0; i
< areawin
->selects
; i
++) {
369 genericptr gptr
= SELTOGENERIC(areawin
->selectlist
+ i
);
370 switch (gptr
->type
) {
372 if (!nonnetwork(TOPOLY(&gptr
)))
376 if ((TOLABEL(&gptr
))->pin
== LOCAL
|| (TOLABEL(&gptr
))->pin
== GLOBAL
)
380 if ((TOOBJINST(&gptr
))->thisobject
->schemtype
!= NONETWORK
)
385 if (netcheck
) invalidate_netlist(topobject
);
388 /*------------------------------------------------------------------*/
389 /* Check proximity of two points (within roundoff tolerance ONDIST) */
390 /*------------------------------------------------------------------*/
392 Boolean
proximity(XPoint
*point1
, XPoint
*point2
)
396 dx
= point1
->x
- point2
->x
;
397 dy
= point1
->y
- point2
->y
;
399 if ((abs(dx
) < ONDIST
) && (abs(dy
) < ONDIST
)) return True
;
403 /*----------------------------------------------------------------------*/
404 /* createnets(): Generate netlist structures */
406 /* Result is the creation of three linked lists inside each object in */
407 /* the circuit hierarchy: */
409 /* 1) the netlist: assigns a number to each network of polygons and */
410 /* pin labels on the object. */
411 /* 2) the ports: a list of every network which is connected from */
412 /* objects above this one in the hierarchy. */
413 /* 3) the calls: a list of calls made from the object to all sub- */
414 /* circuits. Each calls indicates the object and/or */
415 /* instance being called, and a port list which must match */
416 /* the ports of the object being called (the port lists */
417 /* are not reflexive, as the caller does not have to call */
418 /* all of the instance's ports, but the instance must have */
419 /* a port defined for every connection being called). */
420 /* (see structure definitions in xcircuit.h). */
421 /*----------------------------------------------------------------------*/
423 void createnets(objinstptr thisinst
, Boolean quiet
)
425 objectptr thisobject
= thisinst
->thisobject
;
427 if (!setobjecttype(thisobject
)) {
429 /* New in 3.3.32: Generating a netlist from a symbol is */
430 /* okay if the symbol has an associated netlist. */
432 if (thisobject
->schemtype
== SYMBOL
&& thisobject
->symschem
!= NULL
)
433 thisobject
= thisobject
->symschem
;
436 Wprintf("Error: attempt to generate netlist for a symbol.");
442 /* Wprintf("Generating netlists"); */ /* Diagnostic */
443 gennetlist(thisinst
);
444 gencalls(thisobject
);
445 cleartraversed(thisobject
);
446 resolve_devnames(thisobject
);
447 /* Wprintf("Finished netlists"); */
451 /*----------------------------------------------------------------------*/
452 /* Free all memory associated with the netlists. */
453 /*----------------------------------------------------------------------*/
455 void destroynets(objectptr thisobject
)
459 pschem
= (thisobject
->schemtype
== SECONDARY
) ? thisobject
->symschem
:
462 freetemplabels(pschem
);
467 /*----------------------------------------------------------------------*/
468 /* Polygon types which are ignored when considering if a polygon */
469 /* belongs to a circuit network: */
470 /* Closed polygons (boxes) */
471 /* Bounding box polygons */
472 /* Filled polygons */
473 /* Dashed and dotted line-style polygons */
474 /*----------------------------------------------------------------------*/
476 Boolean
nonnetwork(polyptr cpoly
)
478 if (!(cpoly
->style
& UNCLOSED
)) return True
;
479 if (cpoly
->style
& (DASHED
| DOTTED
| FILLSOLID
| BBOX
))
484 /*----------------------------------------------------------------------*/
485 /* Return the largest (most negative) net number in the global netlist */
486 /*----------------------------------------------------------------------*/
495 for (gl
= global_labels
; gl
!= NULL
; gl
= gl
->next
) {
496 if (!(gl
->subnets
)) {
497 if (gl
->net
.id
< smin
)
501 for (bidx
= 0; bidx
< gl
->subnets
; bidx
++) {
502 lbus
= gl
->net
.list
+ bidx
;
512 /*----------------------------------------------------------------------*/
513 /* Return the largest net number in an object's netlist */
514 /*----------------------------------------------------------------------*/
516 int netmax(objectptr cschem
)
524 for (gp
= cschem
->polygons
; gp
!= NULL
; gp
= gp
->next
) {
525 if (!(gp
->subnets
)) {
526 if (gp
->net
.id
> smax
)
530 for (bidx
= 0; bidx
< gp
->subnets
; bidx
++) {
531 lbus
= gp
->net
.list
+ bidx
;
538 for (gl
= cschem
->labels
; gl
!= NULL
; gl
= gl
->next
) {
539 if (!(gl
->subnets
)) {
540 if (gl
->net
.id
> smax
)
544 for (bidx
= 0; bidx
< gl
->subnets
; bidx
++) {
545 lbus
= gl
->net
.list
+ bidx
;
555 /*----------------------------------------------------------------------*/
556 /* Resolve nets and pins for the indicated object */
558 /* When encountering object instances, call gennetlist() on the object */
559 /* if it does not have a valid netlist, then recursively call */
560 /* gennetlist(). Ignore "info" labels, which are not part of the */
563 /*----------------------------------------------------------------------*/
565 void gennetlist(objinstptr thisinst
)
568 labelptr olabel
, clab
;
569 polyptr cpoly
, tpoly
;
570 objectptr thisobject
, callobj
, cschem
, pschem
;
571 objinstptr cinst
, labinst
;
572 int old_parts
; /* netid, tmpid, sub_bus, (jdk) */
576 XPoint
*tpt
, *tpt2
, *endpt
, *endpt2
;
577 int i
, j
, n
, nextnet
, lbus
;
581 Genericlist
*netlist
, *tmplist
, *buspins
, *resolved_net
, newlist
;
586 /* Determine the type of object being netlisted */
587 thisobject
= thisinst
->thisobject
;
588 setobjecttype(thisobject
);
590 if (thisobject
->schemtype
== NONETWORK
) return;
592 /* Has this object been visited before? */
593 visited
= ((thisobject
->labels
!= NULL
) || (thisobject
->polygons
!= NULL
)) ?
596 if (!visited
&& (thisobject
->schemtype
== SYMBOL
)
597 && (thisobject
->symschem
!= NULL
)) {
599 /* Make sure that schematics are netlisted before their symbols */
601 if ((thisobject
->symschem
->polygons
== NULL
) &&
602 (thisobject
->symschem
->labels
== NULL
)) {
603 n
= is_page(thisobject
->symschem
);
605 Fprintf(stderr
, "Error: associated schematic is not a page!\n");
609 gennetlist(xobjs
.pagelist
[n
]->pageinst
);
612 /* Sanity check on symbols with schematics: Are there any pins? */
614 for (i
= 0; i
< thisobject
->parts
; i
++) {
615 cgen
= thisobject
->plist
+ i
;
616 if (IS_LABEL(*cgen
)) {
617 clab
= TOLABEL(cgen
);
618 if (clab
->pin
!= False
&& clab
->pin
!= INFO
)
622 if (i
== thisobject
->parts
)
623 /* Don't warn if schematic has infolabels */
624 if (thisobject
->symschem
== NULL
|| thisobject
->symschem
->infolabels
== 0)
625 Fprintf(stderr
, "Warning: Symbol %s has no pins!\n", thisobject
->name
);
628 /* If this is a secondary schematic, run on the primary (master) */
629 pschem
= (thisobject
->schemtype
== SECONDARY
) ? thisobject
->symschem
:
632 nextnet
= netmax(pschem
) + 1;
634 /* We start the loop for schematics but will modify the loop */
635 /* variable to execute just once in the case of a symbol. */
636 /* It's just not worth the trouble to turn this into a */
637 /* separate subroutine. . . */
639 for (j
= 0; j
< xobjs
.pages
; j
++) {
640 if (pschem
->schemtype
!= PRIMARY
) {
646 cinst
= xobjs
.pagelist
[j
]->pageinst
;
647 if ((cinst
== NULL
) ||
648 ((cinst
->thisobject
!= pschem
) &&
649 ((cinst
->thisobject
->schemtype
!= SECONDARY
) ||
650 (cinst
->thisobject
->symschem
!= pschem
)))) continue;
651 cschem
= cinst
->thisobject
;
654 /* Determine the existing number of parts. We do not want to */
655 /* search over elements that we create in this routine. */
657 old_parts
= cschem
->parts
;
659 /* Part 1: Recursion */
660 /* Schematic pages and symbols acting as their own schematics are the */
661 /* two types on which we recurse to find all sub-schematics. */
663 if ((!visited
) && (cschem
->schemtype
== PRIMARY
||
664 cschem
->schemtype
== SECONDARY
||
665 (cschem
->schemtype
== SYMBOL
&& cschem
->symschem
== NULL
))) {
667 for (i
= 0; i
< old_parts
; i
++) {
668 cgen
= cschem
->plist
+ i
;
669 if (IS_OBJINST(*cgen
)) {
670 objinstptr geninst
, callinst
;
671 geninst
= TOOBJINST(cgen
);
673 if (geninst
->thisobject
->symschem
!= NULL
) {
674 callobj
= geninst
->thisobject
->symschem
;
675 n
= is_page(callobj
);
677 Fprintf(stderr
, "Error: associated schematic is not a page!\n");
681 callinst
= xobjs
.pagelist
[n
]->pageinst
;
684 callobj
= geninst
->thisobject
;
688 /* object on its own schematic */
689 if (callobj
== pschem
) continue;
691 gennetlist(callinst
);
693 /* Also generate netlist for pins in the corresponding symbol */
694 if (geninst
->thisobject
->symschem
!= NULL
)
700 /* Part 2: Match pin labels to nets, and add to list of globals */
701 /* if appropriate. We do all pins first, before ennumerating */
702 /* polygons, so that buses can be handled correctly, generating */
703 /* overlapping subnets. */
705 for (i
= 0; i
< old_parts
; i
++) {
706 cgen
= cschem
->plist
+ i
;
707 if (IS_LABEL(*cgen
)) {
708 clab
= TOLABEL(cgen
);
709 if (clab
->pin
!= False
&& clab
->pin
!= INFO
) {
711 /* Check if the label has a non-default parameter. */
712 /* If so, we want to record the instance along */
713 /* the other netlist information about the pin. */
716 for (cstr
= clab
->string
; cstr
!= NULL
; cstr
= cstr
->nextpart
)
717 if (cstr
->type
== PARAM_START
)
718 if (match_instance_param(cinst
, cstr
->data
.string
) != NULL
) {
723 /* If we have netlisted this object before, and the */
724 /* label is already in the netlist, then ignore it. */
725 /* This only happens for labels without instanced */
726 /* parameter values. */
728 if (visited
&& (labinst
== NULL
)) {
729 for (lseek
= pschem
->labels
; lseek
!= NULL
; lseek
= lseek
->next
)
730 if ((lseek
->label
== clab
) && (lseek
->cinst
== NULL
))
732 if (lseek
!= NULL
) continue;
737 /* Note any overlapping labels. */
738 netlist
= pointtonet(cschem
, cinst
, &clab
->position
);
740 if (pschem
->symschem
!= NULL
&& pschem
->schemtype
== SYMBOL
) {
742 /* For symbols: Check that this pin has a */
743 /* corresponding pin in the schematic. The schematic */
744 /* is netlisted before the symbol, so the netlist */
745 /* should be there. */
747 tmplist
= pintonet(pschem
->symschem
, cinst
, clab
);
749 /* There is always the possibility that the symbol */
750 /* pin does not correspond to anything in the */
751 /* schematic. If so, it gets its own unique net */
752 /* number. HOWEVER, this situation usually indicates */
753 /* an error in the schematic, so output a warning */
756 if (tmplist
== NULL
) {
758 snew
= textprint(clab
->string
, NULL
),
759 Fprintf(stderr
, "Warning: Pin \"%s\" in symbol %s has no "
760 "connection in schematic %s\n",
762 pschem
->symschem
->name
);
764 newlist
.net
.id
= nextnet
++;
769 /* For schematics: Relate the pin to a network */
770 tmplist
= pintonet(pschem
, cinst
, clab
);
772 /* If only part of a bus has been identified, generate */
773 /* the net ID's of the parts that haven't been. */
775 if ((tmplist
!= NULL
) && (tmplist
->subnets
> 0)) {
776 for (lbus
= 0; lbus
< tmplist
->subnets
; lbus
++) {
777 sbus
= tmplist
->net
.list
+ lbus
;
778 if (sbus
->netid
== 0)
779 sbus
->netid
= nextnet
++;
784 if (clab
->pin
== LOCAL
) {
785 if (tmplist
!= NULL
) {
786 addpin(cschem
, labinst
, clab
, tmplist
);
788 mergenets(pschem
, netlist
, tmplist
);
791 if (netlist
== NULL
) {
793 netlist
->net
.id
= nextnet
++;
794 buspins
= break_up_bus(clab
, cinst
, netlist
);
795 if (buspins
!= NULL
) {
796 buslist
*sbus
= buspins
->net
.list
+ buspins
->subnets
- 1;
797 nextnet
= sbus
->netid
+ 1;
798 netlist
= addpin(cschem
, labinst
, clab
, buspins
);
801 tmplist
= addpin(cschem
, labinst
, clab
, netlist
);
806 tmplist
= addpin(cschem
, labinst
, clab
, netlist
);
811 else if (clab
->pin
== GLOBAL
) {
812 if (tmplist
== NULL
) {
814 tmplist
->net
.id
= globalmax() - 1;
816 addglobalpin(cschem
, cinst
, clab
, tmplist
);
817 addpin(cschem
, labinst
, clab
, tmplist
);
819 mergenets(pschem
, netlist
, tmplist
);
822 else if (clab
->pin
== INFO
) {
823 /* Note the presence of info labels in the */
824 /* subcircuit, indicating that it needs to be */
825 /* called because it will generate output. */
826 cschem
->infolabels
= TRUE
;
831 /* Part 3: Polygon enumeration */
832 /* Assign network numbers to all polygons in the object. */
833 /* (Ignore symbols, as we only consider pins on symbols) */
834 /* Where multiple pins occur at a point (bus notation), */
835 /* polygons will be duplicated in each network. */
837 if ((!visited
) && (cschem
->schemtype
== PRIMARY
||
838 cschem
->schemtype
== SECONDARY
||
839 (cschem
->schemtype
== SYMBOL
&& cschem
->symschem
== NULL
))) {
841 for (i
= 0; i
< old_parts
; i
++) {
842 cgen
= cschem
->plist
+ i
;
843 if (IS_POLYGON(*cgen
)) {
844 cpoly
= TOPOLY(cgen
);
846 /* Ignore non-network (closed, bbox, filled) polygons */
847 if (nonnetwork(cpoly
)) continue;
849 resolved_net
= (Genericlist
*)NULL
;
851 /* Check for attachment of each segment of this polygon */
852 /* to position of every recorded pin label. */
854 for (lseek
= pschem
->labels
; lseek
!= NULL
; lseek
= lseek
->next
) {
855 if (lseek
->cschem
!= cschem
) continue;
856 else if ((lseek
->cinst
!= NULL
) && (lseek
->cinst
!= cinst
))
858 olabel
= lseek
->label
;
859 tmplist
= (Genericlist
*)lseek
;
860 for (endpt
= cpoly
->points
; endpt
< cpoly
->points
861 + EndPoint(cpoly
->number
); endpt
++) {
862 endpt2
= endpt
+ NextPoint(cpoly
->number
);
863 if (onsegment(endpt
, endpt2
, &olabel
->position
)) {
865 if (resolved_net
!= NULL
) {
866 if (mergenets(pschem
, resolved_net
, tmplist
))
867 resolved_net
= tmplist
;
869 if (resolved_net
== NULL
) {
870 addpoly(cschem
, cpoly
, tmplist
);
871 resolved_net
= tmplist
;
875 /* if we've encountered a unique instance, then con- */
876 /* tinue past all other instances using this label. */
877 if (lseek
->cinst
!= NULL
)
878 while (lseek
->next
&& (lseek
->next
->label
== lseek
->label
))
882 /* Check for attachment of each segment of this polygon */
883 /* to endpoints of every recorded network polygon. */
885 for (plist
= pschem
->polygons
; plist
!= NULL
; plist
= plist
->next
) {
886 if (plist
->cschem
!= cschem
) continue;
887 else if ((tpoly
= plist
->poly
) == cpoly
) continue;
889 tpt2
= tpoly
->points
+ tpoly
->number
- 1;
890 tmplist
= (Genericlist
*)plist
;
892 for (endpt
= cpoly
->points
; endpt
< cpoly
->points
893 + EndPoint(cpoly
->number
); endpt
++) {
894 endpt2
= endpt
+ NextPoint(cpoly
->number
);
896 if (onsegment(endpt
, endpt2
, tpt
) ||
897 onsegment(endpt
, endpt2
, tpt2
)) {
899 /* Nets previously counted distinct have */
900 /* been connected together by this polygon. */
901 if (resolved_net
!= NULL
) {
902 if (mergenets(pschem
, resolved_net
, tmplist
))
903 resolved_net
= tmplist
;
905 if (resolved_net
== NULL
) {
906 addpoly(cschem
, cpoly
, tmplist
);
907 resolved_net
= tmplist
;
912 /* Check for attachment of the endpoints of this polygon */
913 /* to each segment of every recorded network polygon. */
915 endpt
= cpoly
->points
;
916 endpt2
= cpoly
->points
+ cpoly
->number
- 1;
917 for (tpt
= tpoly
->points
; tpt
< tpoly
->points
918 + EndPoint(tpoly
->number
); tpt
++) {
919 tpt2
= tpt
+ NextPoint(tpoly
->number
);
921 if (onsegment(tpt
, tpt2
, endpt
) ||
922 onsegment(tpt
, tpt2
, endpt2
)) {
924 /* Nets previously counted distinct have */
925 /* been connected together by this polygon. */
926 if (resolved_net
!= 0) {
927 if (mergenets(pschem
, resolved_net
, tmplist
))
928 resolved_net
= tmplist
;
930 if (resolved_net
== 0) {
931 addpoly(cschem
, cpoly
, tmplist
);
932 resolved_net
= tmplist
;
937 if (resolved_net
== 0) {
939 /* This polygon belongs to an unvisited */
940 /* network. Give this polygon a new net */
941 /* number and add to the net list. */
943 newlist
.net
.id
= nextnet
++;
944 addpoly(cschem
, cpoly
, &newlist
);
952 /*--------------------------------------------------------------*/
953 /* Search a sibling of object instance "cinst" for connections */
954 /* between the two. Recurse through the schematic hierarchy of */
955 /* the sibling object. */
956 /*--------------------------------------------------------------*/
958 void search_on_siblings(objinstptr cinst
, objinstptr isib
, pushlistptr schemtop
,
959 short llx
, short lly
, short urx
, short ury
)
961 XPoint
*tmppts
, sbbox
[2];
969 objinstptr subsibinst
;
970 pushlistptr psearch
, newlist
;
971 objectptr sibling
= isib
->thisobject
;
973 tmppts
= (XPoint
*)malloc(sizeof(XPoint
));
975 /* If the sibling is a symbol or fundamental or trivial object, then */
976 /* we just look at pin labels from the parts list and return. */
978 if (sibling
->symschem
!= NULL
|| sibling
->schemtype
== FUNDAMENTAL
979 || sibling
->schemtype
== TRIVIAL
) {
980 for (lseek
= sibling
->labels
; lseek
!= NULL
; lseek
= lseek
->next
) {
981 olabel
= lseek
->label
;
983 tmppts
= (XPoint
*)realloc(tmppts
, sizeof(XPoint
));
984 UTransformPoints(&(olabel
->position
), tmppts
, 1,
985 isib
->position
, isib
->scale
, isib
->rotation
);
987 /* Transform all the way up to the level above cinst */
988 for (psearch
= schemtop
; psearch
!= NULL
; psearch
= psearch
->next
) {
989 subsibinst
= psearch
->thisinst
;
990 UTransformPoints(tmppts
, tmppts
, 1, subsibinst
->position
,
991 subsibinst
->scale
, subsibinst
->rotation
);
993 searchconnect(tmppts
, 1, cinst
, lseek
->subnets
);
997 /* If the sibling is a schematic, we look at connections to pins and */
998 /* polygons, and recursively search subschematics of the sibling. */
1002 /* Look for pins connecting to pins in the object */
1004 for (lseek
= sibling
->labels
; lseek
!= NULL
; lseek
= lseek
->next
) {
1005 olabel
= lseek
->label
;
1006 tmppts
= (XPoint
*)realloc(tmppts
, sizeof(XPoint
));
1007 UTransformPoints(&(olabel
->position
), tmppts
, 1,
1008 isib
->position
, isib
->scale
, isib
->rotation
);
1010 /* Transform all the way up to the level above cinst */
1011 for (psearch
= schemtop
; psearch
!= NULL
; psearch
= psearch
->next
) {
1012 subsibinst
= psearch
->thisinst
;
1013 UTransformPoints(tmppts
, tmppts
, 1, subsibinst
->position
,
1014 subsibinst
->scale
, subsibinst
->rotation
);
1016 searchconnect(tmppts
, 1, cinst
, lseek
->subnets
);
1019 /* Look for polygon ends connecting into the object */
1021 for (pseek
= sibling
->polygons
; pseek
!= NULL
; pseek
= pseek
->next
) {
1022 tpoly
= pseek
->poly
;
1023 tmppts
= (XPoint
*)realloc(tmppts
, tpoly
->number
* sizeof(XPoint
));
1024 UTransformPoints(tpoly
->points
, tmppts
, tpoly
->number
,
1025 isib
->position
, isib
->scale
, isib
->rotation
);
1027 /* Transform all the way up to the level above cinst */
1028 for (psearch
= schemtop
; psearch
!= NULL
; psearch
= psearch
->next
) {
1029 subsibinst
= psearch
->thisinst
;
1030 UTransformPoints(tmppts
, tmppts
, tpoly
->number
, subsibinst
->position
,
1031 subsibinst
->scale
, subsibinst
->rotation
);
1033 searchconnect(tmppts
, tpoly
->number
, cinst
, pseek
->subnets
);
1036 /* Recursively search all schematic children of the sibling */
1038 for (i
= 0; i
< sibling
->parts
; i
++) {
1039 iseek
= sibling
->plist
+ i
;
1040 if (IS_OBJINST(*iseek
)) {
1042 /* objinstptr iinst = (objinstptr)iseek; (jdk) */
1044 /* Don't search this instance unless the bounding box */
1045 /* overlaps the bounding box of the calling object. */
1047 calcinstbbox(iseek
, &sbbox
[0].x
, &sbbox
[0].y
, &sbbox
[1].x
, &sbbox
[1].y
);
1048 for (psearch
= schemtop
; psearch
!= NULL
; psearch
= psearch
->next
) {
1049 subsibinst
= psearch
->thisinst
;
1050 UTransformPoints(sbbox
, sbbox
, 2, subsibinst
->position
,
1051 subsibinst
->scale
, subsibinst
->rotation
);
1053 if ((llx
> sbbox
[1].x
) || (urx
< sbbox
[0].x
) || (lly
> sbbox
[1].y
)
1054 || (ury
< sbbox
[0].y
))
1057 subsibinst
= TOOBJINST(iseek
);
1060 newlist
= (pushlistptr
)malloc(sizeof(pushlist
));
1061 newlist
->thisinst
= isib
;
1062 newlist
->next
= schemtop
;
1065 search_on_siblings(cinst
, subsibinst
, schemtop
, llx
, lly
, urx
, ury
);
1070 schemtop
= schemtop
->next
;
1078 /*--------------------------------------------------------------*/
1079 /* Generate ports from pin labels for all objects: */
1080 /* For each pin-label in the subcircuit or symbol, generate */
1081 /* a port in the object or instance's object. */
1082 /* Translate the pin position to the level above and search */
1083 /* for & link in any connecting nets. */
1085 /* Generate calls to object instances. */
1086 /* Pick up any other nets which might be formed by */
1087 /* juxtaposition of object instances on different levels of the */
1088 /* schematic hierarchy (e.g., pin-to-pin connections). */
1089 /*--------------------------------------------------------------*/
1091 void gencalls(objectptr thisobject
)
1093 genericptr
*cgen
, *iseek
;
1095 objinstptr cinst
, isib
, callinst
;
1096 objectptr callobj
, callsymb
, cschem
, pschem
;
1098 short ibllx
, iblly
, iburx
, ibury
, sbllx
, sblly
, sburx
, sbury
;
1099 int i
, j
, k
; /* , lbus; (jdk) */
1100 /* buslist *sbus; (jdk) */
1104 /* CalllistPtr cseek; (jdk) */
1106 Genericlist
*netfrom
, *netto
; /* , *othernet; (jdk) */
1108 /* The netlist is always kept in the master schematic */
1109 pschem
= (thisobject
->schemtype
== SECONDARY
) ? thisobject
->symschem
:
1112 pschem
->traversed
= True
; /* This object has been dealt with */
1113 pschem
->valid
= True
; /* This object has a valid netlist */
1115 /* We start the loop for schematics but will modify the loop */
1116 /* variable to execute just once in the case of a symbol. */
1117 /* (see gennetlist(), where the same thing is done) */
1119 for (j
= 0; j
< xobjs
.pages
; j
++) {
1120 if (pschem
->schemtype
!= PRIMARY
) {
1122 cschem
= thisobject
;
1125 cinst
= xobjs
.pagelist
[j
]->pageinst
;
1126 if ((cinst
== NULL
) ||
1127 ((cinst
->thisobject
!= pschem
) &&
1128 ((cinst
->thisobject
->schemtype
!= SECONDARY
) ||
1129 (cinst
->thisobject
->symschem
!= pschem
)))) continue;
1130 cschem
= cinst
->thisobject
;
1133 for (i
= 0; i
< cschem
->parts
; i
++) {
1134 cgen
= cschem
->plist
+ i
;
1135 if (IS_OBJINST(*cgen
)) {
1136 callinst
= TOOBJINST(cgen
);
1138 /* Ignore any instance that is specifically marked non-netlistable */
1139 if (callinst
->style
& INST_NONETLIST
) continue;
1141 /* Determine where the hierarchy continues downward */
1143 if (callinst
->thisobject
->symschem
!= NULL
)
1144 callobj
= callinst
->thisobject
->symschem
;
1146 callobj
= callinst
->thisobject
;
1148 /* Always ignore any object on its own schematic */
1150 if (callobj
== pschem
) continue;
1152 callsymb
= callinst
->thisobject
;
1154 /* Note: callobj is the next schematic in the hierarchy. */
1155 /* callsymb is the next visible object in the hierarchy, */
1156 /* which may be either a schematic or a symbol. */
1158 /*--------------------------------------------------------------*/
1159 /* For object instances which are their own schematics (i.e., */
1160 /* have netlist elements), don't rely on any pin list but make */
1161 /* a survey of how polygons connect into the object. */
1162 /*--------------------------------------------------------------*/
1164 if (callsymb
->symschem
== NULL
1165 && callobj
->schemtype
!= FUNDAMENTAL
1166 && callobj
->schemtype
!= TRIVIAL
) {
1168 /* Fprintf(stdout, "*** Analyzing connections from %s"
1169 " to instance of %s\n", cschem->name,
1170 callinst->thisobject->name); */
1172 /* Look for pins connecting to pins in the object */
1174 for (lseek
= pschem
->labels
; lseek
!= NULL
; lseek
= lseek
->next
) {
1175 if (lseek
->cschem
!= cschem
) continue;
1176 else if ((lseek
->cinst
!= NULL
) && (lseek
->cinst
!= callinst
))
1178 olabel
= lseek
->label
;
1179 searchconnect(&(olabel
->position
), 1, callinst
, lseek
->subnets
);
1180 /* if we've encountered a unique instance, then con- */
1181 /* tinue past all other instances using this label. */
1182 if (lseek
->cinst
!= NULL
)
1183 while (lseek
->next
&& (lseek
->next
->label
== lseek
->label
))
1184 lseek
= lseek
->next
;
1187 /* Look for polygon ends connecting into the object */
1189 for (pseek
= pschem
->polygons
; pseek
!= NULL
; pseek
= pseek
->next
) {
1190 if (pseek
->cschem
!= cschem
) continue;
1191 tpoly
= pseek
->poly
;
1192 searchconnect(tpoly
->points
, tpoly
->number
, callinst
, pseek
->subnets
);
1195 /* For each call to a schematic or symbol which is NOT the */
1196 /* one under consideration, see if it touches or overlaps */
1197 /* the object under consideration. Search for connections */
1198 /* between the two objects. */
1200 calcinstbbox(cgen
, &ibllx
, &iblly
, &iburx
, &ibury
);
1202 /* Only need to look forward from the current position. */
1203 for (k
= i
+ 1; k
< cschem
->parts
; k
++) {
1205 iseek
= cschem
->plist
+ k
;
1206 if (IS_OBJINST(*iseek
)) {
1207 calcinstbbox(iseek
, &sbllx
, &sblly
, &sburx
, &sbury
);
1209 /* Check intersection of the two object instances; */
1210 /* don't do a search if they are disjoint. */
1212 if ((ibllx
<= sburx
) && (iburx
>= sbllx
) &&
1213 (iblly
<= sbury
) && (ibury
>= sblly
)) {
1214 isib
= TOOBJINST(iseek
);
1215 search_on_siblings(callinst
, isib
, NULL
,
1216 ibllx
, iblly
, iburx
, ibury
);
1222 /*----------------------------------------------------------*/
1223 /* Recursively call gencalls() on the schematic. */
1224 /*----------------------------------------------------------*/
1226 if (callobj
->traversed
== False
)
1229 /*----------------------------------------------------------*/
1230 /* Create a call to the object callsymb from object cschem */
1231 /*----------------------------------------------------------*/
1233 addcall(cschem
, callobj
, callinst
);
1235 /*----------------------------------------------------------*/
1236 /* Search again on symbol pins to generate calls to ports. */
1237 /*----------------------------------------------------------*/
1240 UPreMultCTM(&locctm
, callinst
->position
, callinst
->scale
,
1241 callinst
->rotation
);
1243 for (lseek
= callsymb
->labels
; lseek
!= NULL
; lseek
= lseek
->next
) {
1244 /* LabellistPtr slab; (jdk) */
1245 /* labelptr slabel; (jdk) */
1247 if (lseek
->cschem
!= callsymb
) continue;
1248 else if ((lseek
->cinst
!= NULL
) && (lseek
->cinst
!= callinst
))
1251 olabel
= lseek
->label
;
1252 netto
= (Genericlist
*)lseek
;
1254 /* Translate pin position back to object cschem */
1255 UTransformbyCTM(&locctm
, &(olabel
->position
), &xpos
, 1);
1257 /* What net in the calling object connects to this point? */
1258 netfrom
= pointtonet(cschem
, callinst
, &xpos
);
1260 /* If there's no net, we make one */
1261 if (netfrom
== NULL
)
1262 netfrom
= make_tmp_pin(cschem
, callinst
, &xpos
, netto
);
1264 /* Generate a port call for a global signal if the */
1265 /* global label appears in the symbol (9/29/04). This */
1266 /* is a change from previous behavior, which was to not */
1267 /* make the call. */
1269 if ((netto
->subnets
== 0) && (netto
->net
.id
< 0))
1270 mergenets(pschem
, netfrom
, netto
);
1272 /* Attempt to generate a port in the object. */
1273 addport(callobj
, netto
);
1275 /* Generate the call to the port */
1276 if (addportcall(pschem
, netfrom
, netto
) == FALSE
) {
1278 // If object is "dot" then copy the bus from the
1279 // net to the dot. The dot takes on whatever
1280 // dimension the bus is.
1282 if (strstr(callobj
->name
, "::dot") != NULL
) {
1283 copy_bus(netto
, netfrom
);
1286 Fprintf(stderr
, "Error: attempt to connect bus size "
1287 "%d in %s to bus size %d in %s\n",
1288 netfrom
->subnets
, cschem
->name
,
1289 netto
->subnets
, callobj
->name
);
1293 /* if we've encountered a unique instance, then continue */
1294 /* past all other instances using this label. */
1295 if (lseek
->cinst
!= NULL
)
1296 while (lseek
->next
&& (lseek
->next
->label
== lseek
->label
))
1297 lseek
= lseek
->next
;
1300 /*----------------------------------------------------------*/
1301 /* If after all that, no ports were called, then remove the */
1302 /* call to this object instance. However, we should check */
1303 /* for info labels, because the device may produce output */
1304 /* for the netlist even if it has no declared ports. This */
1305 /* is irrespective of the presence of pin labels---if the */
1306 /* symbol is "trivial", the netlist connections are */
1307 /* resolved in the level of the hierarchy above, and there */
1308 /* may be no ports, but the call list must retain the call */
1309 /* to ensure that the netlist output is generated. */
1310 /*----------------------------------------------------------*/
1312 if (pschem
->calls
->ports
== NULL
)
1313 if (pschem
->infolabels
== FALSE
)
1314 removecall(pschem
, pschem
->calls
); /* Remove the call */
1320 /*----------------------------------------------------------------------*/
1321 /* Translate a net number down in the calling hierarchy */
1322 /*----------------------------------------------------------------------*/
1324 int translatedown(int rnet
, int portid
, objectptr nextobj
)
1329 for (nport
= nextobj
->ports
; nport
!= NULL
; nport
= nport
->next
) {
1330 if (nport
->portid
== portid
) {
1331 downnet
= nport
->netid
;
1338 /*----------------------------------------------------------------------*/
1339 /* Translate a netlist up in the calling hierarchy */
1341 /* This routine creates a new netlist header which needs to be freed */
1342 /* by the calling routine. */
1344 /* Note that if the entire netlist cannot be translated up, then the */
1345 /* routine returns NULL. This could be modified to return the part of */
1346 /* the network that can be translated up. */
1347 /*----------------------------------------------------------------------*/
1349 Genericlist
*translateup(Genericlist
*rlist
, objectptr thisobj
,
1350 objectptr nextobj
, objinstptr nextinst
)
1358 Genericlist
*tmplist
;
1360 tmplist
= (Genericlist
*)malloc(sizeof(Genericlist
));
1361 tmplist
->subnets
= 0;
1362 tmplist
->net
.id
= 0;
1363 copy_bus(tmplist
, rlist
);
1366 if (rlist
->subnets
== 0)
1367 rnet
= rlist
->net
.id
;
1369 sbus
= rlist
->net
.list
+ lbus
;
1372 for (nport
= nextobj
->ports
; nport
!= NULL
; nport
= nport
->next
) {
1373 if (nport
->netid
== rnet
) {
1374 portid
= nport
->portid
;
1380 for (ccall
= thisobj
->calls
; ccall
!= NULL
; ccall
= ccall
->next
) {
1381 if (ccall
->callinst
== nextinst
) {
1382 for (nport
= ccall
->ports
; nport
!= NULL
; nport
= nport
->next
) {
1383 if (nport
->portid
== portid
) {
1384 upnet
= nport
->netid
;
1388 if (nport
!= NULL
) break;
1392 freegenlist(tmplist
);
1396 if (tmplist
->subnets
== 0) {
1397 tmplist
->net
.id
= upnet
;
1400 sbus
= tmplist
->net
.list
+ lbus
;
1401 sbus
->netid
= upnet
;
1402 sbus
->subnetid
= getsubnet(upnet
, thisobj
);
1405 if (++lbus
>= rlist
->subnets
) break;
1410 /*----------------------------------------------------------------------*/
1411 /* Check whether the indicated polygon is already resolved into the */
1412 /* netlist of the object hierarchy described by seltop. */
1413 /* Return the netlist if resolved, NULL otherwise. The netlist */
1414 /* returned is referred (translated) upward through the calling */
1415 /* hierarchy to the topmost object containing that net or those nets. */
1416 /* This topmost object is returned in parameter topobj. */
1417 /* Note that the netlist returned does not necessarily correspond to */
1418 /* any object in the top level. It is allocated and must be freed by */
1419 /* the calling routine. */
1420 /*----------------------------------------------------------------------*/
1422 Genericlist
*is_resolved(genericptr
*rgen
, pushlistptr seltop
, objectptr
*topobj
)
1424 objectptr thisobj
= seltop
->thisinst
->thisobject
;
1428 Genericlist
*rlist
= NULL
, *newlist
;
1430 pschem
= (thisobj
->schemtype
== SECONDARY
) ? thisobj
->symschem
: thisobj
;
1432 /* Recursively call self, since we have to back out from the bottom of */
1435 if (seltop
->next
!= NULL
) {
1436 rlist
= is_resolved(rgen
, seltop
->next
, topobj
);
1438 /* Translate network ID up the hierarchy to the topmost object in which */
1439 /* the network exists. */
1441 if (rlist
!= NULL
) {
1442 newlist
= translateup(rlist
, pschem
, seltop
->next
->thisinst
->thisobject
,
1443 seltop
->next
->thisinst
);
1444 if (newlist
== NULL
)
1445 /* Net does not exist upwards of this object. Pass net ID */
1446 /* upward with "topobj" unchanged. */
1456 /* Find the net ID for the listed object, which should be in the object */
1457 /* on the bottom of the pushlist stack. */
1459 if (IS_POLYGON(*rgen
)) {
1460 for (pseek
= pschem
->polygons
; pseek
!= NULL
; pseek
= pseek
->next
) {
1461 if (pseek
->poly
== TOPOLY(rgen
)) {
1462 rlist
= (Genericlist
*)pseek
;
1467 else if (IS_LABEL(*rgen
)) {
1468 for (lseek
= pschem
->labels
; lseek
!= NULL
; lseek
= lseek
->next
) {
1469 if (lseek
->label
== TOLABEL(rgen
)) {
1470 rlist
= (Genericlist
*)lseek
;
1476 if (rlist
!= NULL
) {
1477 /* Make a copy of the netlist header from this element */
1478 newlist
= (Genericlist
*)malloc(sizeof(Genericlist
));
1479 newlist
->subnets
= 0;
1480 copy_bus(newlist
, rlist
);
1486 *topobj
= (rlist
== NULL
) ? NULL
: seltop
->thisinst
->thisobject
;
1490 /*--------------------------------------------------------------*/
1491 /* Highlight all the polygons and pin labels in a network */
1492 /* (recursively, downward). Pin labels are drawn only on the */
1493 /* topmost schematic object. */
1494 /* Returns true if some part of the hierarchy declared a net to */
1495 /* be highlighted. */
1496 /* mode = 1 highlight, mode = 0 erase */
1497 /*--------------------------------------------------------------*/
1499 Boolean
highlightnet(objectptr cschem
, objinstptr cinst
, int netid
, u_char mode
)
1508 int netto
, locnetid
, lbus
;
1509 int curcolor
= AUXCOLOR
;
1510 Boolean rval
= FALSE
;
1513 SetForeground(dpy
, areawin
->gc
, curcolor
);
1515 pschem
= (cschem
->schemtype
== SECONDARY
) ? cschem
->symschem
: cschem
;
1517 for (plist
= pschem
->polygons
; plist
!= NULL
; plist
= plist
->next
) {
1518 if (plist
->cschem
!= cschem
) continue;
1519 cpoly
= plist
->poly
;
1521 if (plist
->subnets
== 0)
1522 locnetid
= plist
->net
.id
;
1524 locnetid
= (plist
->net
.list
+ lbus
)->netid
;
1525 if (locnetid
== netid
) {
1526 /* Fprintf(stdout, " >> Found polygon belonging to net %d at (%d, %d)\n",
1527 locnetid, cpoly->points[0].x, cpoly->points[0].y); */
1528 if (mode
== 0 && cpoly
->color
!= curcolor
) {
1529 curcolor
= cpoly
->color
;
1530 XTopSetForeground(curcolor
);
1532 UDrawPolygon(cpoly
, xobjs
.pagelist
[areawin
->page
]->wirewidth
);
1535 if (++lbus
>= plist
->subnets
) break;
1539 /* Highlight labels if they belong to the top-level object */
1541 if (cschem
== topobject
) {
1542 for (llist
= pschem
->labels
; llist
!= NULL
; llist
= llist
->next
) {
1543 if (llist
->cschem
!= cschem
) continue;
1544 else if ((llist
->cinst
!= NULL
) && (llist
->cinst
!= cinst
)) continue;
1545 clabel
= llist
->label
;
1547 if (llist
->subnets
== 0)
1548 locnetid
= llist
->net
.id
;
1550 locnetid
= (llist
->net
.list
+ lbus
)->netid
;
1551 if (locnetid
== netid
) {
1552 if (clabel
->string
->type
== FONT_NAME
) { /* don't draw temp labels */
1553 if ((mode
== 0) && (clabel
->color
!= curcolor
)) {
1554 curcolor
= clabel
->color
;
1555 UDrawString(clabel
, curcolor
, cinst
);
1558 UDrawString(clabel
, DOFORALL
, cinst
);
1559 /* Fprintf(stdout, " >> Found label belonging to net "
1561 locnetid, clabel->position.x,
1562 clabel->position.y); */
1567 if (++lbus
>= llist
->subnets
) break;
1569 /* if we've encountered a unique instance, then continue */
1570 /* past all other instances using this label. */
1571 if (llist
->cinst
!= NULL
)
1572 while (llist
->next
&& (llist
->next
->label
== llist
->label
))
1573 llist
= llist
->next
;
1576 /* Highlight all pins connecting this net to symbols */
1580 /* Connectivity recursion */
1582 for (calls
= pschem
->calls
; calls
!= NULL
; calls
= calls
->next
) {
1583 if (calls
->cschem
!= cschem
) continue;
1584 for (ports
= calls
->ports
; ports
!= NULL
; ports
= ports
->next
) {
1585 if (ports
->netid
== netid
) {
1586 ccinst
= calls
->callinst
;
1588 /* Recurse only on objects for which network polygons are visible */
1589 /* from the calling object: i.e., non-trivial, non-fundamental */
1590 /* objects acting as their own schematics. */
1593 UPreMultCTM(DCTM
, ccinst
->position
, ccinst
->scale
, ccinst
->rotation
);
1595 if (ccinst
->thisobject
->symschem
== NULL
&&
1596 ccinst
->thisobject
->schemtype
!= FUNDAMENTAL
&&
1597 ccinst
->thisobject
->schemtype
!= TRIVIAL
) {
1599 netto
= translatedown(netid
, ports
->portid
, calls
->callobj
);
1601 /* Fprintf(stdout, " > Calling object %s at (%d, %d)\n",
1602 calls->callobj->name, ccinst->position.x, ccinst->position.y); */
1603 /* Fprintf(stdout, " > Net translation from %d to %d (port %d)\n",
1604 netid, netto, ports->portid); */
1606 if (highlightnet(calls
->callobj
, calls
->callinst
, netto
, mode
))
1610 /* Otherwise (symbols, fundamental, trivial, etc., objects), we */
1611 /* highlight the pin position of the port. */
1612 if ((clabel
= PortToLabel(ccinst
, ports
->portid
)))
1622 /*----------------------------------------------------------------------*/
1623 /* Highlight whatever nets are listed in the current object instance, */
1625 /*----------------------------------------------------------------------*/
1627 void highlightnetlist(objectptr nettop
, objinstptr cinst
, u_char mode
)
1631 Genericlist
*netlist
= cinst
->thisobject
->highlight
.netlist
;
1632 objinstptr nextinst
= cinst
->thisobject
->highlight
.thisinst
;
1634 if (netlist
== NULL
) return;
1637 if (netlist
->subnets
== 0)
1638 netid
= netlist
->net
.id
;
1640 sbus
= netlist
->net
.list
+ lbus
;
1641 netid
= sbus
->netid
;
1643 highlightnet(nettop
, nextinst
, netid
, mode
);
1644 if (++lbus
>= netlist
->subnets
) break;
1647 /* If we are erasing, remove the netlist entry from the object */
1648 if (mode
== (u_char
)0) {
1649 freegenlist(netlist
);
1650 cinst
->thisobject
->highlight
.netlist
= NULL
;
1651 cinst
->thisobject
->highlight
.thisinst
= NULL
;
1655 /*----------------------------------------------------------------------*/
1656 /* Push the matrix stack for each object (instance) until the indicated */
1657 /* object is reached. This works similarly to highlightnet() above, */
1658 /* but makes calls according to the hierarchy described by the */
1659 /* pushlistptr parameter. */
1660 /* Returns the number of stack objects to pop after we're done. */
1661 /*----------------------------------------------------------------------*/
1663 int pushnetwork(pushlistptr seltop
, objectptr nettop
)
1665 pushlistptr cursel
= seltop
;
1669 while ((cursel
->thisinst
->thisobject
!= nettop
) && (cursel
->next
!= NULL
)) {
1670 cursel
= cursel
->next
;
1671 sinst
= cursel
->thisinst
;
1673 UPreMultCTM(DCTM
, sinst
->position
, sinst
->scale
, sinst
->rotation
);
1677 if (cursel
->thisinst
->thisobject
!= nettop
) {
1678 Fprintf(stderr
, "Error: object does not exist in calling stack!\n");
1685 /*----------------------------------------------------------------------*/
1686 /* Determine if two netlists match. If "mode" is MATCH_EXACT, the */
1687 /* net numbers and subnet numbers must all be the same. If */
1688 /* MATCH_SUBNETS, then the subnet numbers must be the same. If */
1689 /* MATCH_SIZE, then they need only have the same number of subnets. */
1690 /*----------------------------------------------------------------------*/
1692 Boolean
match_buses(Genericlist
*list1
, Genericlist
*list2
, int mode
)
1695 buslist
*bus1
, *bus2
;
1697 if (list1
->subnets
!= list2
->subnets
) {
1698 // A wire (no subnets) matches a bus of 1 subnet. All others
1699 // are non-matching.
1701 if (list1
->subnets
!= 0 && list2
->subnets
!= 0)
1703 else if (list1
->subnets
!= 1 && list2
->subnets
!= 1)
1707 if (mode
== MATCH_SIZE
) return TRUE
;
1709 if (list1
->subnets
== 0) {
1710 if (mode
== MATCH_SUBNETS
) return TRUE
;
1711 if (list2
->subnets
!= 0) {
1712 bus2
= list2
->net
.list
+ 0;
1713 if (list1
->net
.id
!= bus2
->netid
) return FALSE
;
1715 else if (list1
->net
.id
!= list2
->net
.id
) return FALSE
;
1717 else if (list2
->subnets
== 0) {
1718 if (mode
== MATCH_SUBNETS
) return TRUE
;
1719 bus1
= list1
->net
.list
+ 0;
1720 if (bus1
->netid
!= list2
->net
.id
) return FALSE
;
1723 for (i
= 0; i
< list1
->subnets
; i
++) {
1724 bus1
= list1
->net
.list
+ i
;
1725 bus2
= list2
->net
.list
+ i
;
1726 /* A subnetid of < 0 indicates an unassigned bus */
1727 if ((bus1
->subnetid
!= -1) && (bus1
->subnetid
!= bus2
->subnetid
))
1730 if (mode
== MATCH_SUBNETS
) return TRUE
;
1732 for (i
= 0; i
< list1
->subnets
; i
++) {
1733 bus1
= list1
->net
.list
+ i
;
1734 bus2
= list2
->net
.list
+ i
;
1735 if (bus1
->netid
!= bus2
->netid
)
1742 /*----------------------------------------------------------------------*/
1743 /* Copy the netlist structure from one netlist element to another */
1744 /*----------------------------------------------------------------------*/
1746 void copy_bus(Genericlist
*dest
, Genericlist
*source
)
1748 buslist
*sbus
, *dbus
;
1751 if (dest
->subnets
> 0)
1752 free(dest
->net
.list
);
1754 dest
->subnets
= source
->subnets
;
1755 if (source
->subnets
== 0)
1756 dest
->net
.id
= source
->net
.id
;
1758 dest
->net
.list
= (buslist
*)malloc(dest
->subnets
* sizeof(buslist
));
1759 for (i
= 0; i
< dest
->subnets
; i
++) {
1760 sbus
= source
->net
.list
+ i
;
1761 dbus
= dest
->net
.list
+ i
;
1762 dbus
->netid
= sbus
->netid
;
1763 dbus
->subnetid
= sbus
->subnetid
;
1768 /*------------------------------------------------------*/
1769 /* Create a new "temporary" label object for a pin */
1770 /* This type of label is never drawn, so it doesn't */
1771 /* need font info. It is identified as "temporary" by */
1772 /* this lack of a leading font record. */
1773 /*------------------------------------------------------*/
1775 Genericlist
*new_tmp_pin(objectptr cschem
, XPoint
*pinpt
, char *pinstring
,
1776 char *prefix
, Genericlist
*netlist
)
1781 if (pinpt
== NULL
) {
1782 Fprintf(stderr
, "NULL label location!\n");
1786 NEW_LABEL(newlabel
, cschem
);
1787 labeldefaults(*newlabel
, LOCAL
, pinpt
->x
, pinpt
->y
);
1788 (*newlabel
)->anchor
= 0;
1789 (*newlabel
)->color
= DEFAULTCOLOR
;
1790 strptr
= (*newlabel
)->string
;
1791 strptr
->type
= TEXT_STRING
;
1792 if (pinstring
!= NULL
) {
1793 strptr
->data
.string
= (char *)malloc(strlen(pinstring
));
1794 strcpy(strptr
->data
.string
, pinstring
);
1797 strptr
->data
.string
= textprintnet(prefix
, NULL
, netlist
);
1800 /* Add label to object's netlist and return a pointer to the */
1801 /* netlist entry. */
1803 return (addpin(cschem
, NULL
, *newlabel
, netlist
));
1806 /*------------------------------------------------------*/
1807 /* Create a label for use in the list of global nets. */
1808 /* This label is like a temporary label (new_tmp_pin) */
1809 /* except that it is not represented in any object. */
1810 /* The string contains the verbatim contents of any */
1811 /* parameter substitutions in the original label. */
1812 /*------------------------------------------------------*/
1814 labelptr
new_global_pin(labelptr clabel
, objinstptr cinst
)
1818 newlabel
= (labelptr
) malloc(sizeof(label
));
1819 newlabel
->type
= LABEL
;
1820 labeldefaults(newlabel
, GLOBAL
, 0, 0);
1821 newlabel
->anchor
= 0;
1822 newlabel
->color
= DEFAULTCOLOR
;
1823 free(newlabel
->string
);
1824 newlabel
->string
= stringcopyall(clabel
->string
, cinst
);
1826 /* Add label to the global netlist and return a pointer to */
1827 /* the netlist entry. */
1832 /*----------------------------------------------------------------------*/
1833 /* Create a temporary I/O pin (becomes part of netlist and also part of */
1834 /* the object itself). */
1835 /*----------------------------------------------------------------------*/
1837 Genericlist
*make_tmp_pin(objectptr cschem
, objinstptr cinst
, XPoint
*pinpt
,
1838 Genericlist
*sublist
)
1842 char *pinstring
= NULL
;
1843 /* buslist *sbus; (jdk) */
1844 /* int lbus; (jdk) */
1845 Genericlist
*netlist
, *tmplist
, newlist
;
1847 newlist
.subnets
= 0;
1850 /* Primary schematic (contains the netlist) */
1851 pschem
= (cschem
->schemtype
== SECONDARY
) ? cschem
->symschem
: cschem
;
1853 /* Determine a netlist for this pin */
1855 netlist
= pointtonet(cschem
, cinst
, pinpt
);
1856 if (netlist
== NULL
) {
1857 newlist
.net
.id
= netmax(pschem
) + 1;
1861 /* If there is any other pin at this location, don't make another */
1862 /* one. If there is already a temporary pin associated with the */
1863 /* net, use its name. */
1866 for (lseek
= pschem
->labels
; lseek
!= NULL
; lseek
= lseek
->next
) {
1867 if (lseek
->cschem
!= cschem
) continue;
1868 else if ((lseek
->cinst
!= NULL
) && (lseek
->cinst
!= cinst
)) continue;
1869 tmplist
= (Genericlist
*)lseek
;
1870 if (match_buses(netlist
, tmplist
, MATCH_EXACT
)) {
1871 if (proximity(&(lseek
->label
->position
), pinpt
))
1872 return (Genericlist
*)lseek
;
1873 else if (lseek
->label
->string
->type
== TEXT_STRING
)
1874 pinstring
= lseek
->label
->string
->data
.string
;
1876 /* if we've encountered a unique instance, then continue past */
1877 /* all other instances using this label. */
1878 if (lseek
->cinst
!= NULL
)
1879 while (lseek
->next
&& (lseek
->next
->label
== lseek
->label
))
1880 lseek
= lseek
->next
;
1883 return (new_tmp_pin(cschem
, pinpt
, pinstring
, "ext", netlist
));
1886 /*--------------------------------------------------------------*/
1887 /* Search for connections into a non-symbol subcircuit, based */
1888 /* on various combinations of polygon and pin label overlaps. */
1889 /*--------------------------------------------------------------*/
1891 int searchconnect(XPoint
*points
, int number
, objinstptr cinst
, int subnets
)
1893 XPoint
*tmppts
, *tpt
, *tpt2
, *endpt
, *endpt2
, *pinpt
, opinpt
;
1898 objectptr tobj
, cobj
= cinst
->thisobject
;
1901 int i
; /* , lbus, sub_bus; (jdk) */
1904 /* Generate temporary polygon in the coordinate system of */
1905 /* the object instance in question */
1907 tmppts
= (XPoint
*)malloc(number
* sizeof(XPoint
));
1908 InvTransformPoints(points
, tmppts
, number
,
1909 cinst
->position
, cinst
->scale
, cinst
->rotation
);
1910 /* Fprintf(stdout, "Info: translated polygon w.r.t. object %s\n", */
1911 /* cinst->thisobject->name); */
1913 /* Recursion on all appropriate sub-schematics. */
1914 /* (Use parts list, not call list, as call list may not have created yet) */
1916 for (i
= 0; i
< cobj
->parts
; i
++) {
1917 cgen
= cobj
->plist
+ i
;
1918 if (IS_OBJINST(*cgen
)) {
1919 tinst
= TOOBJINST(cgen
);
1920 if (tinst
->thisobject
->symschem
== NULL
) {
1921 tobj
= tinst
->thisobject
;
1922 if (tobj
->schemtype
!= FUNDAMENTAL
&& tobj
->schemtype
!= TRIVIAL
)
1923 found
+= searchconnect(tmppts
, number
, tinst
, subnets
);
1928 for (endpt
= tmppts
; endpt
< tmppts
+ EndPoint(number
); endpt
++) {
1929 endpt2
= endpt
+ NextPoint(number
);
1930 for (i
= 0; i
< cobj
->parts
; i
++) {
1931 cgen
= cobj
->plist
+ i
;
1932 if (!IS_OBJINST(*cgen
)) continue;
1933 tinst
= TOOBJINST(cgen
);
1935 /* Look at the object only (symbol, or schematic if it has no symbol) */
1936 tobj
= tinst
->thisobject
;
1938 /* Search for connections to pin labels */
1940 for (tseek
= tobj
->labels
; tseek
!= NULL
; tseek
= tseek
->next
) {
1941 tlab
= tseek
->label
;
1942 UTransformPoints(&(tlab
->position
), &opinpt
, 1, tinst
->position
,
1943 tinst
->scale
, tinst
->rotation
);
1944 if (onsegment(endpt2
, endpt
, &opinpt
)) {
1945 /* Fprintf(stdout, "%s connects to pin %s of %s in %s\n", */
1946 /* ((number > 1) ? "Polygon" : "Pin"), */
1947 /* tlab->string + 2, tinst->thisobject->name, */
1948 /* cinst->thisobject->name); */
1949 make_tmp_pin(cobj
, cinst
, &opinpt
, (Genericlist
*)tseek
);
1950 found
+= (tseek
->subnets
== 0) ? 1 : tseek
->subnets
;
1956 for (pseek
= cobj
->polygons
; pseek
!= NULL
; pseek
= pseek
->next
) {
1957 tpoly
= pseek
->poly
;
1959 /* Search for connections from segments passed to this */
1960 /* function to endpoints of polygons in the netlist. */
1963 tpt
= tpoly
->points
;
1964 tpt2
= tpoly
->points
+ tpoly
->number
- 1;
1965 if (onsegment(endpt2
, endpt
, tpt
)) pinpt
= tpt
;
1966 if (onsegment(endpt2
, endpt
, tpt2
)) pinpt
= tpt2
;
1968 /* Create new pinlabel (only if there is not one already there) */
1970 if (pinpt
!= NULL
) {
1971 make_tmp_pin(cobj
, cinst
, pinpt
, (Genericlist
*)pseek
);
1972 found
+= (pseek
->subnets
== 0) ? 1 : pseek
->subnets
;
1978 endpt2
= tmppts
+ EndPoint(number
) - 1;
1980 /* Search for connections from endpoints passed to this */
1981 /* function to segments of polygons in the netlist. */
1983 for (pseek
= cobj
->polygons
; pseek
!= NULL
; pseek
= pseek
->next
) {
1985 tpoly
= pseek
->poly
;
1986 for (tpt
= tpoly
->points
; tpt
< tpoly
->points
1987 + EndPoint(tpoly
->number
); tpt
++) {
1988 tpt2
= tpt
+ NextPoint(tpoly
->number
);
1991 if (onsegment(tpt2
, tpt
, endpt
)) pinpt
= endpt
;
1992 if (onsegment(tpt2
, tpt
, endpt2
)) pinpt
= endpt2
;
1994 /* Create new pinlabel (only if there is not one already there) */
1996 if (pinpt
!= NULL
) {
1997 make_tmp_pin(cobj
, cinst
, pinpt
, (Genericlist
*)pseek
);
1998 found
+= (pseek
->subnets
== 0) ? 1 : pseek
->subnets
;
2006 /*----------------------------------------------------------------------*/
2007 /* Associate polygon with given netlist and add to the object's list */
2008 /* of network polygons (i.e., wires). */
2009 /*----------------------------------------------------------------------*/
2011 Genericlist
*addpoly(objectptr cschem
, polyptr poly
, Genericlist
*netlist
)
2013 PolylistPtr newpoly
;
2015 /* buslist *sbus; (jdk) */
2016 /* int lbus, sub_bus; (jdk) */
2018 /* Netlist is in the master schematic */
2019 pschem
= (cschem
->schemtype
== SECONDARY
) ? cschem
->symschem
: cschem
;
2021 /* If this polygon is already in the list, then add an extra subnet */
2024 for (newpoly
= pschem
->polygons
; newpoly
!= NULL
; newpoly
= newpoly
->next
) {
2025 if (newpoly
->poly
== poly
) {
2026 if (!match_buses((Genericlist
*)newpoly
, netlist
, MATCH_EXACT
)) {
2027 Fprintf(stderr
, "addpoly: Error in bus assignment\n");
2030 return (Genericlist
*)newpoly
;
2034 /* Create a new entry and link to polygon list of this object */
2036 newpoly
= (PolylistPtr
) malloc(sizeof(Polylist
));
2037 newpoly
->cschem
= cschem
;
2038 newpoly
->poly
= poly
;
2039 newpoly
->subnets
= 0;
2040 copy_bus((Genericlist
*)newpoly
, netlist
);
2041 newpoly
->next
= pschem
->polygons
;
2042 pschem
->polygons
= newpoly
;
2044 return (Genericlist
*)newpoly
;
2047 /*-------------------------------------------------------------------------*/
2049 long zsign(long a
, long b
)
2051 if (a
> b
) return 1;
2052 else if (a
< b
) return -1;
2056 /*----------------------------------------------------------------------*/
2057 /* Promote a single net to a bus. The bus size will be equal to the */
2058 /* value "subnets". */
2059 /*----------------------------------------------------------------------*/
2061 void promote_net(objectptr cschem
, Genericlist
*netfrom
, int subnets
)
2063 Genericlist
*netref
= NULL
;
2068 int netid
, firstid
, lbus
; /* curid, (jdk) */
2072 /* If no promotion is required, don't do anything */
2073 if (netfrom
->subnets
== subnets
) return;
2075 /* It "netfrom" is already a bus, but of different size than */
2076 /* subnets, then it cannot be changed. */
2078 if (netfrom
->subnets
!= 0) {
2079 Fprintf(stderr
, "Attempt to change the size of a bus!\n");
2083 netid
= netfrom
->net
.id
;
2085 /* If "subnets" is 1, then "netfrom" can be promoted regardless. */
2086 /* Otherwise, if the "netfrom" net is used in any calls, then it */
2087 /* cannot be promoted. */
2090 for (calls
= cschem
->calls
; calls
!= NULL
; calls
= calls
->next
)
2091 for (ports
= calls
->ports
; ports
!= NULL
; ports
= ports
->next
)
2092 if (ports
->netid
== netid
) {
2093 Fprintf(stderr
, "Cannot promote net to bus: Net already connected"
2094 " to single-wire port\n");
2097 firstid
= netmax(cschem
) + 1;
2100 for (plist
= cschem
->polygons
; plist
!= NULL
; plist
= plist
->next
)
2101 if ((plist
->subnets
== 0) && (plist
->net
.id
== netid
)) {
2102 plist
->subnets
= subnets
;
2103 plist
->net
.list
= (buslist
*)malloc(subnets
* sizeof(buslist
));
2104 for (lbus
= 0; lbus
< subnets
; lbus
++) {
2105 sbus
= plist
->net
.list
+ lbus
;
2106 sbus
->netid
= (lbus
== 0) ? netid
: firstid
+ lbus
;
2107 sbus
->subnetid
= lbus
; /* By default, number from zero */
2109 netref
= (Genericlist
*)plist
;
2112 /* It's possible for a label without bus notation to be attached */
2116 for (llist
= cschem
->labels
; llist
!= NULL
; llist
= llist
->next
)
2117 if ((llist
->subnets
== 0) && (llist
->net
.id
== netid
)) {
2118 llist
->subnets
= subnets
;
2119 llist
->net
.list
= (buslist
*)malloc(subnets
* sizeof(buslist
));
2120 for (lbus
= 0; lbus
< subnets
; lbus
++) {
2121 sbus
= llist
->net
.list
+ lbus
;
2122 sbus
->netid
= (lbus
== 0) ? netid
: firstid
+ lbus
;
2123 sbus
->subnetid
= lbus
; /* By default, number from zero */
2125 netref
= (Genericlist
*)llist
;
2129 /* We need to create a temp label associated with this net to */
2130 /* encompass the promoted bus size. If this bus is later attached */
2131 /* to a known bus, that bus name will be canonical. If no bus name */
2132 /* is ever assigned to the bus, this temp one will be used. */
2136 pinpos
= NetToPosition(netid
, cschem
);
2137 new_tmp_pin(cschem
, pinpos
, NULL
, "int", netref
);
2141 /*----------------------------------------------------------------------*/
2142 /* Change any part of the netlist "testlist" that matches the net IDs */
2143 /* of "orignet" to the net IDs of "newnet". It is assumed that the */
2144 /* lengths and sub-bus numbers of "orignet" and "newnet" match. */
2145 /*----------------------------------------------------------------------*/
2147 Boolean
mergenetlist(objectptr cschem
, Genericlist
*testlist
,
2148 Genericlist
*orignet
, Genericlist
*newnet
)
2150 int obus
, onetid
, osub
, nsub
, nnetid
, tbus
;
2152 Boolean rval
= FALSE
;
2155 if (orignet
->subnets
== 0) {
2156 onetid
= orignet
->net
.id
;
2160 sbus
= orignet
->net
.list
+ obus
;
2161 onetid
= sbus
->netid
;
2162 osub
= sbus
->subnetid
;
2165 if (newnet
->subnets
== 0) {
2166 nnetid
= newnet
->net
.id
;
2170 sbus
= newnet
->net
.list
+ obus
;
2171 nnetid
= sbus
->netid
;
2172 nsub
= sbus
->subnetid
;
2175 if (testlist
->subnets
== 0) {
2176 if (testlist
->net
.id
== onetid
) {
2178 if (orignet
->subnets
== 0) {
2179 testlist
->net
.id
= nnetid
;
2183 /* Promote testlist to a bus subnet of size 1 */
2184 testlist
->subnets
= 1;
2185 testlist
->net
.list
= (buslist
*)malloc(sizeof(buslist
));
2186 sbus
= testlist
->net
.list
;
2187 sbus
->netid
= nnetid
;
2188 sbus
->subnetid
= nsub
;
2194 for (tbus
= 0; tbus
< testlist
->subnets
; tbus
++) {
2195 /* If the sub-bus numbers match, then change the net */
2196 /* ID to the new net number. If the sub-bus is */
2197 /* unnamed (has no associated bus-notation label), */
2198 /* then it can take on the net and subnet numbers. */
2200 sbus
= testlist
->net
.list
+ tbus
;
2202 if (sbus
->netid
== onetid
) {
2203 if (sbus
->subnetid
== osub
) {
2204 sbus
->netid
= nnetid
;
2205 sbus
->subnetid
= nsub
;
2209 labelptr blab
= NetToLabel(nnetid
, cschem
);
2211 Fprintf(stderr
, "Warning: isolated subnet?\n");
2212 sbus
->netid
= nnetid
;
2213 /* Keep subnetid---but, does newnet need to be promoted? */
2216 else if (blab
->string
->type
!= FONT_NAME
) {
2217 sbus
->netid
= nnetid
;
2218 sbus
->subnetid
= nsub
;
2220 Fprintf(stderr
, "Warning: Unexpected subnet value in mergenetlist!\n");
2225 if (++obus
>= orignet
->subnets
) break;
2230 /*----------------------------------------------------------------------*/
2231 /* Combine two networks in an object's linked-list Netlist */
2232 /* Parameters: cschem - pointer to object containing netlist */
2233 /* orignet - original netlist to be changed */
2234 /* newnet - new netlist to be changed to */
2236 /* Attempts to merge different subnets in a bus are thwarted. */
2237 /*----------------------------------------------------------------------*/
2239 Boolean
netmerge(objectptr cschem
, Genericlist
*orignet
, Genericlist
*newnet
)
2245 Genericlist savenet
;
2247 buslist
*obus
, *nbus
;
2250 /* Trivial case; do nothing */
2251 if (match_buses(orignet
, newnet
, MATCH_EXACT
)) return TRUE
;
2253 /* Disallow an attempt to convert a global net to a local net: */
2254 /* The global net ID always dominates! */
2256 if ((orignet
->subnets
== 0) && (newnet
->subnets
== 0) &&
2257 (orignet
->net
.id
< 0) && (newnet
->net
.id
> 0)) {
2258 int globnet
= orignet
->net
.id
;
2259 orignet
->net
.id
= newnet
->net
.id
;
2260 newnet
->net
.id
= globnet
;
2263 /* Check that the lists of changes are compatible. It appears to be */
2264 /* okay to have non-matching buses (although they should not be */
2265 /* merged), as this is a valid style in which buses do not have taps */
2266 /* but the sub-buses are explicitly called out with labels. In such */
2267 /* case, the polygons of different sub-buses touch, and this routine */
2268 /* rejects them as being incompatible. */
2270 if (!match_buses(orignet
, newnet
, MATCH_SUBNETS
)) {
2271 if (match_buses(orignet
, newnet
, MATCH_SIZE
)) {
2273 /* If only the subnet numbers don't match up, check if */
2274 /* "orignet" has a temp label. */
2275 nbus
= orignet
->net
.list
;
2276 if ((nlab
= NetToLabel(nbus
->netid
, cschem
)) != NULL
) {
2277 if (nlab
->string
->type
!= FONT_NAME
)
2282 Fprintf(stderr
, "netmerge warning: non-matching bus subnets touching.\n");
2288 /* If orignet is a bus size 1 and newnet is a wire, then promote */
2289 /* newnet to a bus size 1. */
2291 if (orignet
->subnets
== 1 && newnet
->subnets
== 0) {
2292 net
= newnet
->net
.id
;
2293 newnet
->subnets
= 1;
2294 newnet
->net
.list
= (buslist
*)malloc(sizeof(buslist
));
2295 obus
= orignet
->net
.list
;
2296 nbus
= newnet
->net
.list
;
2297 nbus
->subnetid
= obus
->subnetid
;
2301 /* Make a copy of the net so we don't overwrite it */
2302 savenet
.subnets
= 0;
2303 copy_bus(&savenet
, orignet
);
2306 for (plist
= cschem
->polygons
; plist
!= NULL
; plist
= plist
->next
)
2307 if (mergenetlist(cschem
, (Genericlist
*)plist
, &savenet
, newnet
))
2310 for (llist
= cschem
->labels
; llist
!= NULL
; llist
= llist
->next
)
2311 if (mergenetlist(cschem
, (Genericlist
*)llist
, &savenet
, newnet
)) {
2316 /* Because nets that have been merged away may be re-used later, */
2317 /* change the name of any temporary labels to the new net number */
2319 if (llist
->label
->string
->type
!= FONT_NAME
) {
2320 newtext
= llist
->label
->string
->data
.string
;
2321 if (sscanf(newtext
+ 3, "%d", &pinnet
) == 1) {
2322 if (pinnet
== savenet
.net
.id
) {
2323 *(newtext
+ 3) = '\0';
2324 llist
->label
->string
->data
.string
= textprintnet(newtext
,
2334 /* Reflect the net change in the object's call list, if it has one. */
2336 for (calls
= cschem
->calls
; calls
!= NULL
; calls
= calls
->next
) {
2337 for (ports
= calls
->ports
; ports
!= NULL
; ports
= ports
->next
) {
2338 if (newnet
->subnets
== 0) {
2339 if (ports
->netid
== savenet
.net
.id
)
2340 ports
->netid
= newnet
->net
.id
;
2343 for (i
= 0; i
< newnet
->subnets
; i
++) {
2344 obus
= savenet
.net
.list
+ i
;
2345 nbus
= newnet
->net
.list
+ i
;
2346 if (ports
->netid
== obus
->netid
)
2347 ports
->netid
= nbus
->netid
;
2354 /* Free the copy of the bus that we made, if we made one */
2355 if (savenet
.subnets
> 0) free(savenet
.net
.list
);
2360 /*----------------------------------------------------------------------*/
2361 /* Wrapper to netmerge() to make sure change is made both to the symbol */
2362 /* and schematic, if both exist. */
2363 /*----------------------------------------------------------------------*/
2365 Boolean
mergenets(objectptr cschem
, Genericlist
*orignet
, Genericlist
*newnet
)
2369 if (cschem
->symschem
!= NULL
)
2370 merged
= netmerge(cschem
->symschem
, orignet
, newnet
);
2371 if (netmerge(cschem
, orignet
, newnet
))
2377 /*----------------------------------------------------------------------*/
2378 /* Remove a call to an object instance from the call list of cschem */
2379 /*----------------------------------------------------------------------*/
2381 void removecall(objectptr cschem
, CalllistPtr dontcallme
)
2383 CalllistPtr lastcall
, seeklist
;
2384 PortlistPtr ports
, savelist
;
2386 /* find the instance call before this one and link it to the one following */
2389 for (seeklist
= cschem
->calls
; seeklist
!= NULL
; seeklist
= seeklist
->next
) {
2390 if (seeklist
== dontcallme
)
2392 lastcall
= seeklist
;
2395 if (seeklist
== NULL
) {
2396 Fprintf(stderr
, "Error in removecall(): Call does not exist!\n");
2400 if (lastcall
== NULL
)
2401 cschem
->calls
= dontcallme
->next
;
2403 lastcall
->next
= dontcallme
->next
;
2405 ports
= dontcallme
->ports
;
2406 while (ports
!= NULL
) {
2408 ports
= ports
->next
;
2414 /*----------------------------------------------------------------------*/
2415 /* Add a pin label to the netlist */
2416 /* If cschem == NULL, add the pin to the list of global pins. */
2417 /* The new label entry in the netlist gets a copy of the netlist */
2419 /*----------------------------------------------------------------------*/
2421 Genericlist
*addpin(objectptr cschem
, objinstptr cinst
, labelptr pin
,
2422 Genericlist
*netlist
)
2424 LabellistPtr srchlab
, newlabel
, lastlabel
= NULL
;
2426 /* buslist *sbus; (jdk) */
2427 /* int lbus, sub_bus; (jdk) */
2429 pschem
= (cschem
->schemtype
== SECONDARY
) ? cschem
->symschem
: cschem
;
2431 for (srchlab
= pschem
->labels
; srchlab
!= NULL
; srchlab
= srchlab
->next
) {
2432 if (srchlab
->label
== pin
) {
2433 if (!match_buses(netlist
, (Genericlist
*)srchlab
, MATCH_EXACT
)) {
2434 if (srchlab
->cinst
== cinst
) {
2435 Fprintf(stderr
, "addpin: Error in bus assignment\n");
2439 else if (srchlab
->cinst
== NULL
)
2440 return (Genericlist
*)srchlab
;
2441 break; /* Stop at the first record for this label */
2443 lastlabel
= srchlab
;
2446 /* Create a new entry and link to label list of the object */
2448 newlabel
= (LabellistPtr
) malloc(sizeof(Labellist
));
2449 newlabel
->cschem
= cschem
;
2450 newlabel
->cinst
= cinst
;
2451 newlabel
->label
= pin
;
2452 newlabel
->subnets
= 0;
2453 copy_bus((Genericlist
*)newlabel
, netlist
);
2455 /* Always put the specific (instanced) cases in front of */
2456 /* generic cases for the same label. */
2458 /* Generic case---make it the last record for this label */
2459 if ((cinst
== NULL
) && (lastlabel
!= NULL
)) {
2460 while ((srchlab
!= NULL
) && (srchlab
->label
== pin
)) {
2461 lastlabel
= srchlab
;
2462 srchlab
= srchlab
->next
;
2465 if (lastlabel
!= NULL
) {
2466 newlabel
->next
= srchlab
;
2467 lastlabel
->next
= newlabel
;
2470 newlabel
->next
= pschem
->labels
;
2471 pschem
->labels
= newlabel
;
2473 return (Genericlist
*)newlabel
;
2476 /*----------------------------------------------------------------------*/
2477 /* Add a pin label to the list of global net names. */
2478 /* The new label entry in the netlist gets a copy of the netlist */
2479 /* "netlist" and a copy of label "pin" containing the *instance* value */
2481 /*----------------------------------------------------------------------*/
2483 Genericlist
*addglobalpin(objectptr cschem
, objinstptr cinst
, labelptr pin
,
2484 Genericlist
*netlist
)
2486 LabellistPtr srchlab
, newlabel
, lastlabel
= NULL
;
2488 if (cinst
== NULL
) {
2489 Fprintf(stderr
, "Error: Global pin does not have an associated instance!\n");
2493 for (srchlab
= global_labels
; srchlab
!= NULL
; srchlab
= srchlab
->next
) {
2494 if (srchlab
->label
== pin
) {
2495 if (!match_buses(netlist
, (Genericlist
*)srchlab
, MATCH_EXACT
)) {
2496 if (srchlab
->cinst
== cinst
) {
2497 Fprintf(stderr
, "addglobalpin: Error in bus assignment\n");
2501 else if (srchlab
->cinst
== NULL
)
2502 return (Genericlist
*)srchlab
;
2503 break; /* Stop at the first record for this label */
2505 lastlabel
= srchlab
;
2508 /* Create a new entry and link to label list of the object */
2510 newlabel
= (LabellistPtr
) malloc(sizeof(Labellist
));
2511 newlabel
->cschem
= cschem
;
2512 newlabel
->cinst
= cinst
;
2513 newlabel
->label
= new_global_pin(pin
, cinst
);
2514 newlabel
->subnets
= 0;
2515 copy_bus((Genericlist
*)newlabel
, netlist
);
2517 if (lastlabel
!= NULL
) {
2518 newlabel
->next
= srchlab
;
2519 lastlabel
->next
= newlabel
;
2522 newlabel
->next
= global_labels
;
2523 global_labels
= newlabel
;
2525 return (Genericlist
*)newlabel
;
2528 /*----------------------------------------------------------------------*/
2529 /* Allocate memory for the new call list element */
2530 /* Define the values for the new call list element */
2531 /* Insert new call into call list */
2532 /* The new call is at the beginning of the list. */
2533 /*----------------------------------------------------------------------*/
2535 void addcall(objectptr cschem
, objectptr callobj
, objinstptr callinst
)
2537 CalllistPtr newcall
;
2540 /* Netlist is on the master schematic */
2541 pschem
= (cschem
->schemtype
== SECONDARY
) ? cschem
->symschem
: cschem
;
2543 newcall
= (CalllistPtr
) malloc(sizeof(Calllist
));
2544 newcall
->cschem
= cschem
;
2545 newcall
->callobj
= callobj
;
2546 newcall
->callinst
= callinst
;
2547 newcall
->devindex
= -1;
2548 newcall
->devname
= NULL
;
2549 newcall
->ports
= NULL
;
2550 newcall
->next
= pschem
->calls
;
2551 pschem
->calls
= newcall
;
2554 /*----------------------------------------------------------------------*/
2555 /* Add a port to the object cschem which connects net "netto" to */
2556 /* the calling object. One port is created for each net ID in "netto" */
2557 /* (which may be a bus). The port contains the net ID in the called */
2558 /* object. The port may already exist, in which case this routine does */
2560 /*----------------------------------------------------------------------*/
2562 void addport(objectptr cschem
, Genericlist
*netto
)
2564 PortlistPtr newport
, seekport
;
2565 int portid
= 0, netid
, lbus
;
2571 if (netto
->subnets
== 0)
2572 netid
= netto
->net
.id
;
2574 sbus
= netto
->net
.list
+ lbus
;
2575 netid
= sbus
->netid
;
2578 /* If a port already exists for this net, don't add another one! */
2581 for (seekport
= cschem
->ports
; seekport
!= NULL
; seekport
= seekport
->next
) {
2582 if (seekport
->netid
!= netid
) {
2583 if (seekport
->portid
> portid
)
2584 portid
= seekport
->portid
;
2593 newport
= (PortlistPtr
)malloc(sizeof(Portlist
));
2594 newport
->netid
= netid
;
2595 newport
->portid
= portid
;
2597 if (cschem
->ports
!= NULL
)
2598 newport
->next
= cschem
->ports
;
2600 newport
->next
= NULL
;
2602 cschem
->ports
= newport
;
2604 if (++lbus
>= netto
->subnets
) break;
2608 /*----------------------------------------------------------------------*/
2609 /* Add a specific port connection from object cschem into the instance */
2610 /* cinst. This equates a net number in the calling object cschem */
2611 /* (netfrom) to a net number in the object instance being called */
2614 /* If we attempt to connect a bus of one size to a port of a different */
2615 /* size, return FALSE. Otherwise, add the call and return TRUE. */
2616 /*----------------------------------------------------------------------*/
2618 Boolean
addportcall(objectptr cschem
, Genericlist
*netfrom
, Genericlist
*netto
)
2621 PortlistPtr seekport
, sp
, newport
;
2624 int lbus
, netid_from
, netid_to
;
2625 buslist
*sbus
, *tbus
;
2628 /* The call that we need to add a port to is the first on */
2629 /* the list for cschem, as created by addcall(). */
2630 ccall
= cschem
->calls
;
2631 instobj
= ccall
->callobj
;
2632 cinst
= ccall
->callinst
;
2634 if (netfrom
->subnets
!= netto
->subnets
) {
2635 if (netfrom
->subnets
== 0) {
2636 /* It is possible that "netfrom" is an unlabeled polygon that */
2637 /* is implicitly declared a bus by its connection to this */
2638 /* port. If so, we promote "netfrom" to a bus but set the */
2639 /* subnet entries to negative values, since we don't know what */
2641 promote_net(cschem
, netfrom
, netto
->subnets
);
2644 /* Only other allowable condition is a bus size 1 connecting into */
2645 /* a single-wire port. However, one should consider promotion of */
2646 /* the pin in the target object to a bus on a per-instance basis. */
2647 /* This has not yet been done. . . */
2649 else if ((netfrom
->subnets
!= 1) || (netto
->subnets
!= 0)) {
2650 /* Let the caller report error information, because it knows more */
2656 buslist bsingf
, bsingo
;
2657 Genericlist subnet_from
, subnet_other
;
2659 if (netfrom
->subnets
== 0) {
2660 netid_from
= netfrom
->net
.id
;
2662 subnet_from
.subnets
= 0;
2663 subnet_from
.net
.id
= netid_from
;
2665 subnet_other
.subnets
= 0;
2668 sbus
= netfrom
->net
.list
+ lbus
;
2669 netid_from
= sbus
->netid
;
2671 subnet_from
.subnets
= 1;
2672 subnet_from
.net
.list
= &bsingf
;
2673 bsingf
.netid
= netid_from
;
2674 bsingf
.subnetid
= sbus
->subnetid
;
2676 bsingo
.subnetid
= lbus
;
2677 subnet_other
.subnets
= 1;
2678 subnet_other
.net
.list
= &bsingo
;
2680 if (netto
->subnets
== 0) {
2681 netid_to
= netto
->net
.id
;
2684 tbus
= netto
->net
.list
+ lbus
;
2685 netid_to
= tbus
->netid
;
2688 /* Check the ports of the instance's object for the one matching */
2689 /* the "netto" net ID. */
2692 for (seekport
= instobj
->ports
; seekport
!= NULL
;
2693 seekport
= seekport
->next
) {
2694 if (seekport
->netid
== netid_to
) {
2696 /* If there is already an entry for this port, then */
2697 /* we may need to merge nets in cschem. */
2699 for (sp
= ccall
->ports
; sp
!= NULL
; sp
= sp
->next
)
2700 if (sp
->portid
== seekport
->portid
) {
2701 if (sp
->netid
!= netid_from
) {
2702 if (netfrom
->subnets
== 0)
2703 subnet_other
.net
.id
= sp
->netid
;
2705 bsingo
.netid
= sp
->netid
;
2706 bsingo
.subnetid
= getsubnet(bsingo
.netid
, cschem
);
2708 if (!mergenets(cschem
, &subnet_other
, &subnet_from
)) {
2709 /* Upon failure, see if we can merge the other */
2711 if (!mergenets(cschem
, &subnet_from
, &subnet_other
))
2714 if (subnet_from
.subnets
== 0)
2715 subnet_from
.net
.id
= subnet_other
.net
.id
;
2717 bsingf
.netid
= bsingo
.netid
;
2718 bsingf
.subnetid
= bsingo
.subnetid
;
2727 newport
= (PortlistPtr
)malloc(sizeof(Portlist
));
2728 newport
->netid
= netid_from
;
2729 newport
->portid
= seekport
->portid
;
2730 newport
->next
= ccall
->ports
;
2731 ccall
->ports
= newport
;
2736 if (++lbus
>= netfrom
->subnets
) break;
2741 /*----------------------------------------------------------------------*/
2742 /* Find the net ID corresponding to the indicated port ID in the */
2743 /* indicated object. */
2744 /*----------------------------------------------------------------------*/
2746 int porttonet(objectptr cschem
, int portno
)
2750 for (plist
= cschem
->ports
; plist
!= NULL
; plist
= plist
->next
) {
2751 if (plist
->portid
== portno
)
2752 return plist
->netid
;
2757 /*----------------------------------------------------------------------*/
2758 /* Traverse netlist and return netid of polygon or pin on which the */
2759 /* indicated point is located. */
2760 /* If point is not on any polygon or does not match any pin position, */
2762 /* Labels which have a non-NULL "cinst" record are instance-dependent */
2763 /* and must match parameter "cinst". */
2765 /* This routine checks to see if more than one net crosses the point */
2766 /* of interest, and merges the nets if found. */
2767 /* (the method has been removed and must be reinstated, presumably) */
2768 /*----------------------------------------------------------------------*/
2770 Genericlist
*pointtonet(objectptr cschem
, objinstptr cinst
, XPoint
*testpoint
)
2775 Genericlist
*preturn
;
2776 objectptr pschem
; /* primary schematic */
2778 /* cschem is the object containing the point. However, if the object */
2779 /* is a secondary schematic, the netlist is located in the master. */
2781 pschem
= (cschem
->schemtype
== SECONDARY
) ? cschem
->symschem
: cschem
;
2783 for (plab
= pschem
->labels
; plab
!= NULL
; plab
= plab
->next
) {
2784 if (plab
->cschem
!= cschem
) continue;
2785 else if ((plab
->cinst
!= NULL
) && (plab
->cinst
!= cinst
)) continue;
2786 tpt
= &(plab
->label
->position
);
2787 if (proximity(tpt
, testpoint
))
2788 return (Genericlist
*)plab
;
2790 /* if we've encountered a unique instance, then continue past */
2791 /* all other instances using this label. */
2793 if (plab
->cinst
!= NULL
)
2794 while (plab
->next
&& (plab
->next
->label
== plab
->label
))
2798 /* Check against polygons. We use this part of the routine to see */
2799 /* if there are crossing wires on top of a port. If so, they are */
2800 /* merged together. */
2802 preturn
= (Genericlist
*)NULL
;
2803 for (ppoly
= pschem
->polygons
; ppoly
!= NULL
; ppoly
= ppoly
->next
) {
2804 if (ppoly
->cschem
!= cschem
) continue;
2805 for (tpt
= ppoly
->poly
->points
; tpt
< ppoly
->poly
->points
2806 + EndPoint(ppoly
->poly
->number
); tpt
++) {
2807 tpt2
= tpt
+ NextPoint(ppoly
->poly
->number
);
2809 if (onsegment(tpt
, tpt2
, testpoint
)) {
2810 if (preturn
== (Genericlist
*)NULL
)
2811 preturn
= (Genericlist
*)ppoly
;
2813 mergenets(pschem
, (Genericlist
*)ppoly
, preturn
);
2821 /*----------------------------------------------------------------------*/
2822 /* localpin keeps track of temporary pin labels when flattening the */
2823 /* hierarchy without destroying the original pin names. */
2824 /*----------------------------------------------------------------------*/
2826 void makelocalpins(objectptr cschem
, CalllistPtr clist
, char *prefix
)
2828 NetnamePtr netnames
;
2829 PortlistPtr ports
, plist
;
2831 int locnet
, callnet
;
2832 objectptr callobj
= clist
->callobj
;
2834 /* Copy all net names which are passed from above through ports */
2836 for (ports
= clist
->ports
; ports
!= NULL
; ports
= ports
->next
) {
2837 callnet
= ports
->netid
;
2838 for (plist
= callobj
->ports
; plist
!= NULL
; plist
= plist
->next
) {
2839 if (plist
->portid
== ports
->portid
) {
2840 locnet
= plist
->netid
;
2841 locpin
= nettopin(callnet
, cschem
, prefix
);
2846 for (netnames
= callobj
->netnames
; netnames
!= NULL
; netnames
= netnames
->next
)
2847 if (netnames
->netid
== locnet
)
2850 if (netnames
== NULL
) {
2851 netnames
= (NetnamePtr
)malloc(sizeof(Netname
));
2852 netnames
->netid
= locnet
;
2853 netnames
->localpin
= stringcopy(locpin
);
2854 netnames
->next
= callobj
->netnames
;
2855 callobj
->netnames
= netnames
;
2860 /*----------------------------------------------------------------------*/
2861 /* Find the first point associated with the net "netid" in the object */
2863 /*----------------------------------------------------------------------*/
2865 XPoint
*NetToPosition(int netid
, objectptr cschem
)
2870 int lbus
, locnetid
; /* sub_bus, (jdk) */
2872 plist
= cschem
->polygons
;
2873 for (; plist
!= NULL
; plist
= plist
->next
) {
2875 if (plist
->subnets
== 0) {
2876 locnetid
= plist
->net
.id
;
2879 sbus
= plist
->net
.list
+ lbus
;
2880 locnetid
= sbus
->netid
;
2882 if (locnetid
== netid
) {
2883 return plist
->poly
->points
;
2885 if (++lbus
>= plist
->subnets
) break;
2889 llist
= (netid
< 0) ? global_labels
: cschem
->labels
;
2890 for (; llist
!= NULL
; llist
= llist
->next
) {
2892 if (llist
->subnets
== 0) {
2893 locnetid
= llist
->net
.id
;
2896 sbus
= llist
->net
.list
+ lbus
;
2897 locnetid
= sbus
->netid
;
2899 if (locnetid
== netid
) {
2900 return (&(llist
->label
->position
));
2902 if (++lbus
>= llist
->subnets
) break;
2908 /*----------------------------------------------------------------------*/
2909 /* Find a label element for the given net number. In a symbol, this */
2910 /* will be the label representing the pin (or the first one found, if */
2911 /* the pin has multiple labels). If no label is found, return NULL. */
2912 /* Preferably choose a non-temporary label, if one exists */
2913 /*----------------------------------------------------------------------*/
2915 labelptr
NetToLabel(int netid
, objectptr cschem
)
2918 labelptr standby
= NULL
;
2922 llist
= (netid
< 0) ? global_labels
: cschem
->labels
;
2924 for (; llist
!= NULL
; llist
= llist
->next
) {
2926 if (llist
->subnets
== 0) {
2927 locnetid
= llist
->net
.id
;
2930 sbus
= llist
->net
.list
+ lbus
;
2931 locnetid
= sbus
->netid
;
2933 if (locnetid
== netid
) {
2934 if (llist
->label
->string
->type
== FONT_NAME
)
2935 return llist
->label
;
2936 else if (standby
== NULL
)
2937 standby
= llist
->label
;
2939 if (++lbus
>= llist
->subnets
) break;
2946 /*----------------------------------------------------------------------*/
2947 /* Find the subnet number of the given net. This routine should be */
2948 /* used only as a last resort in case the subnet number is not */
2949 /* available; it has to look through the polygon and label lists in */
2950 /* detail to find the specified net ID. */
2951 /*----------------------------------------------------------------------*/
2953 int getsubnet(int netid
, objectptr cschem
)
2958 int lbus
, sub_bus
, locnetid
;
2960 plist
= cschem
->polygons
;
2961 for (; plist
!= NULL
; plist
= plist
->next
) {
2963 if (plist
->subnets
== 0) {
2964 locnetid
= plist
->net
.id
;
2968 sbus
= plist
->net
.list
+ lbus
;
2969 locnetid
= sbus
->netid
;
2970 sub_bus
= sbus
->subnetid
;
2972 if (locnetid
== netid
) {
2975 if (++lbus
>= plist
->subnets
) break;
2979 llist
= (netid
< 0) ? global_labels
: cschem
->labels
;
2980 for (; llist
!= NULL
; llist
= llist
->next
) {
2982 if (llist
->subnets
== 0) {
2983 locnetid
= llist
->net
.id
;
2987 sbus
= llist
->net
.list
+ lbus
;
2988 locnetid
= sbus
->netid
;
2989 sub_bus
= sbus
->subnetid
;
2991 if (locnetid
== netid
) {
2994 if (++lbus
>= llist
->subnets
) break;
3000 /*----------------------------------------------------------------------*/
3001 /* Find a pin name for the given net number */
3002 /* Either take the last pin name with the net, or generate a new pin, */
3003 /* assigning it a net number for a string. */
3004 /* prefix = NULL indicates spice netlist, but is also used for PCB-type */
3005 /* netlists because the calling hierarchy is generated elsewhere. */
3006 /*----------------------------------------------------------------------*/
3008 stringpart
*nettopin(int netid
, objectptr cschem
, char *prefix
)
3012 LabellistPtr netlabel
;
3013 char *newtext
, *snew
= NULL
;
3015 int locnetid
; /* lbus, (jdk) */
3016 /* buslist *sbus; (jdk) */
3018 static stringpart
*newstring
= NULL
;
3020 /* prefix is NULL for hierarchical (spice) netlists and for */
3021 /* internal netlist manipulation. */
3023 if (prefix
== NULL
) {
3024 pinlab
= NetToLabel(netid
, cschem
);
3025 if (pinlab
!= NULL
) {
3027 /* If this is a "temp label", regenerate the name according to */
3028 /* the actual net number, if it does not match. This prevents */
3029 /* unrelated temp labels from getting the same name. */
3031 if (pinlab
->string
->type
!= FONT_NAME
) {
3032 if (sscanf(pinlab
->string
->data
.string
+ 3, "%d", &locnetid
) == 1) {
3033 if (locnetid
!= netid
) {
3034 newtext
= pinlab
->string
->data
.string
;
3037 newnet
.net
.id
= netid
;
3038 pinlab
->string
->data
.string
= textprintnet(newtext
, NULL
, &newnet
);
3043 return pinlab
->string
;
3046 /* If there's no label associated with this network, make one */
3047 /* called "intn" where n is the net number (netid). This is a */
3048 /* temp label (denoted by lack of a font specifier). */
3051 newnet
.net
.id
= netid
;
3052 pinpos
= NetToPosition(netid
, cschem
);
3053 netlabel
= (LabellistPtr
)new_tmp_pin(cschem
, pinpos
, NULL
, "int", &newnet
);
3054 return (netlabel
) ? netlabel
->label
->string
: NULL
;
3058 /* Flattened (e.g., sim) netlists */
3060 for (netname
= cschem
->netnames
; netname
!= NULL
; netname
= netname
->next
) {
3061 if (netname
->netid
== netid
) {
3062 if (netname
->localpin
!= NULL
)
3063 return netname
->localpin
;
3068 /* Generate the string for the local instantiation of this pin */
3069 /* If this node does not have a pin, create one using the current */
3070 /* hierarchy prefix as the string. */
3072 pinlab
= NetToLabel(netid
, cschem
);
3073 if (pinlab
!= NULL
) {
3074 stringpart
*tmpstring
= pinlab
->string
;
3075 snew
= textprint(tmpstring
, NULL
);
3078 snew
= (char *)malloc(12);
3079 sprintf(snew
, "int%d", netid
);
3086 newtext
= (char *)malloc(1 + strlen(snew
) + strlen(prefix
));
3087 sprintf(newtext
, "%s%s", prefix
, snew
);
3091 /* "newstring" is allocated only once and should not be free'd */
3092 /* by the calling routine. */
3094 if (newstring
== NULL
) {
3095 newstring
= (stringpart
*)malloc(sizeof(stringpart
));
3096 newstring
->nextpart
= NULL
;
3097 newstring
->type
= TEXT_STRING
;
3100 free(newstring
->data
.string
);
3102 newstring
->data
.string
= newtext
;
3106 /*----------------------------------------------------------------------*/
3107 /* Find the net which connects to the given pin label */
3108 /* Return NULL (no net) if no match was found. */
3109 /*----------------------------------------------------------------------*/
3111 Genericlist
*pintonet(objectptr cschem
, objinstptr cinst
, labelptr testpin
)
3113 LabellistPtr seeklabel
;
3115 buslist
*sbus
, *tbus
;
3116 Genericlist netlist
, *tmplist
;
3118 /* check against local pins, if this pin is declared local */
3120 seeklabel
= (testpin
->pin
== GLOBAL
) ? global_labels
: cschem
->labels
;
3122 netlist
.subnets
= 0;
3123 for (; seeklabel
!= NULL
; seeklabel
= seeklabel
->next
)
3124 if (!stringcomprelaxed(seeklabel
->label
->string
, testpin
->string
, cinst
))
3126 /* Quick simple case: no bus */
3127 if (seeklabel
->subnets
== 0)
3128 return (Genericlist
*)seeklabel
;
3130 tmplist
= break_up_bus(testpin
, cinst
, (Genericlist
*)seeklabel
);
3132 /* It is necessary to be able to put together a netlist from */
3133 /* partial sources none of which may be complete. */
3135 if (tmplist
!= NULL
) {
3136 if (netlist
.subnets
== 0) copy_bus(&netlist
, tmplist
);
3138 for (lbus
= 0; lbus
< tmplist
->subnets
; lbus
++) {
3139 sbus
= netlist
.net
.list
+ lbus
;
3140 tbus
= tmplist
->net
.list
+ lbus
;
3141 if (sbus
->netid
== 0)
3142 sbus
->netid
= tbus
->netid
; /* copy forward */
3143 else if (tbus
->netid
== 0)
3144 tbus
->netid
= sbus
->netid
; /* copy back */
3145 if (sbus
->netid
!= 0)
3148 if (matched
== netlist
.subnets
) {
3149 free(netlist
.net
.list
);
3155 if (netlist
.subnets
!= 0) {
3156 free(netlist
.net
.list
);
3157 return tmplist
; /* Returns list with partial entries */
3159 return NULL
; /* No matches found */
3164 /*----------------------------------------------------------------------*/
3165 /* Automatic Schematic Generation stuff--- */
3166 /* Blow away all polygons in the schematic and replace them with a */
3167 /* simple rat's-nest (point-to-point). */
3169 /* This routine is more of a proof-of-concept than a useful routine, */
3170 /* intended to be called only from the Tcl console. It is intended to */
3171 /* reveal most of the issues related to automatic schematic generation, */
3172 /* in which the netlist, or a portion of it, can be redrawn as objects */
3173 /* are moved around to maintain the relationships present in the */
3174 /* calls structure. */
3175 /*----------------------------------------------------------------------*/
3177 void ratsnest(objinstptr thisinst
)
3183 objectptr pschem
, cschem
;
3185 polyptr ppoly
, *newpoly
;
3187 int i
, netid
, points
, sub_bus
, lbus
;
3191 cschem
= thisinst
->thisobject
;
3192 pschem
= (cschem
->schemtype
== SECONDARY
) ? cschem
->symschem
: cschem
;
3194 /* Go through the netlist and remove all polygons. Remove */
3195 /* the polygons from the object as well as from the netlist. */
3197 for (plist
= pschem
->polygons
; plist
!= NULL
; plist
= plist
->next
) {
3198 ppoly
= plist
->poly
;
3199 ppoly
->type
+= REMOVE_TAG
; /* tag for removal */
3201 freepolylist(&pschem
->polygons
);
3203 /* for each schematic (PRIMARY or SECONDARY), remove the tagged */
3206 for (i
= 0; i
< xobjs
.pages
; i
++) {
3207 cinst
= xobjs
.pagelist
[i
]->pageinst
;
3208 if (cinst
&& (cinst
->thisobject
->schemtype
== SECONDARY
) &&
3209 (cinst
->thisobject
->symschem
== pschem
)) {
3210 delete_tagged(cinst
);
3212 else if (cinst
== thisinst
)
3213 delete_tagged(cinst
);
3216 /* Now, for each net ID in the label list, run through the calls and */
3217 /* find all points in the calls connecting to that net. Link */
3218 /* them with as many polygons as needed. These polygons are point- */
3219 /* to-point lines, turning the schematic representation into a */
3222 for (llist
= pschem
->labels
; llist
!= NULL
; llist
= llist
->next
) {
3224 if (llist
->subnets
== 0) {
3225 netid
= llist
->net
.id
;
3229 sbus
= llist
->net
.list
+ lbus
;
3230 netid
= sbus
->netid
;
3231 sub_bus
= sbus
->subnetid
;
3235 for (calls
= pschem
->calls
; calls
!= NULL
; calls
= calls
->next
) {
3237 /* Determine schematic object from the object called. Start a */
3238 /* new polygon any time we switch schematic pages. */
3240 if (calls
->cschem
!= cschem
)
3242 cschem
= calls
->cschem
;
3244 for (ports
= calls
->ports
; ports
!= NULL
; ports
= ports
->next
) {
3245 if (ports
->netid
== netid
) {
3247 /* Find the location of this port in the coordinates of cschem */
3249 result
= PortToPosition(calls
->callinst
, ports
->portid
, &portpos
);
3250 if (result
== True
) {
3253 NEW_POLY(newpoly
, cschem
);
3254 polydefaults(*newpoly
, 1, portpos
.x
, portpos
.y
);
3255 (*newpoly
)->style
|= UNCLOSED
;
3256 (*newpoly
)->color
= RATSNESTCOLOR
;
3257 addpoly(cschem
, *newpoly
, (Genericlist
*)llist
);
3260 poly_add_point(*newpoly
, &portpos
);
3263 Fprintf(stderr
, "Error: Cannot find pin connection in symbol!\n");
3264 /* Deal with error condition? */
3269 if (++lbus
>= llist
->subnets
) break;
3273 /* Now, move all the labels to reconnect to their networks */
3277 /* Refresh the screen */
3278 drawarea(NULL
, NULL
, NULL
);
3283 /*----------------------------------------------------------------------*/
3284 /* Find a net or netlist in object cschem with the indicated name. */
3286 /* This is the same routine as above, but finds the net with the given */
3287 /* name, or all nets which are a subset of the given name, if the name */
3288 /* is the name of a bus. Return NULL if no match was found. */
3289 /*----------------------------------------------------------------------*/
3291 Genericlist
*nametonet(objectptr cschem
, objinstptr cinst
, char *netname
)
3293 LabellistPtr seeklabel
;
3294 stringpart newstring
;
3296 /* Build a simple xcircuit string from "netname" (nothing malloc'd) */
3297 newstring
.type
= TEXT_STRING
;
3298 newstring
.nextpart
= NULL
;
3299 newstring
.data
.string
= netname
;
3301 /* Check against local networks */
3303 for (seeklabel
= cschem
->labels
; seeklabel
!= NULL
; seeklabel
= seeklabel
->next
)
3304 if (!stringcomprelaxed(seeklabel
->label
->string
, &newstring
, cinst
))
3305 return (Genericlist
*)seeklabel
;
3307 /* Check against global networks */
3309 for (seeklabel
= global_labels
; seeklabel
!= NULL
; seeklabel
= seeklabel
->next
)
3310 if (!stringcomprelaxed(seeklabel
->label
->string
, &newstring
, cinst
))
3311 return (Genericlist
*)seeklabel
;
3316 /*----------------------------------------------------------------------*/
3317 /* Check if two parts may have the same component index. This is true */
3318 /* for parts with parameterized pins, such as those in the "quadparts" */
3319 /* library. Compare the names of the ports in each instance. If none */
3320 /* match, then these are unique subparts of a single component, and we */
3321 /* should return FALSE. Otherwise, return TRUE. */
3322 /*----------------------------------------------------------------------*/
3324 Boolean
samepart(CalllistPtr clist1
, CalllistPtr clist2
)
3328 char *pinname1
, *pinname2
;
3331 if (clist1
->callobj
!= clist2
->callobj
) return FALSE
;
3334 for (port
= clist1
->ports
; port
!= NULL
; port
= port
->next
) {
3335 plab
= PortToLabel(clist1
->callinst
, port
->portid
);
3336 pinname1
= textprint(plab
->string
, clist1
->callinst
);
3337 pinname2
= textprint(plab
->string
, clist2
->callinst
);
3338 if (!strcmp(pinname1
, pinname2
)) rvalue
= TRUE
;
3345 /*----------------------------------------------------------------------*/
3346 /* Generate an index number for a device in a flat netlist format. */
3347 /* We ignore any values given to "index" (this is a to-do item, since */
3348 /* many schematics are only a single level of hierarchy, so it makes */
3349 /* sense to keep designated indices when possible), but do generate */
3350 /* independent index numbering for different device classes. */
3351 /*----------------------------------------------------------------------*/
3353 u_int
devflatindex(char *devname
)
3355 flatindex
*fp
= flatrecord
;
3356 while (fp
!= NULL
) {
3357 if (!strcmp(devname
, fp
->devname
)) {
3362 fp
= (flatindex
*)malloc(sizeof(flatindex
));
3363 fp
->next
= flatrecord
;
3366 fp
->devname
= devname
;
3370 /*----------------------------------------------------------------------*/
3371 /* Free the list of per-class flat device indices */
3372 /*----------------------------------------------------------------------*/
3374 void freeflatindex()
3376 flatindex
*fpnext
, *fp
= flatrecord
;
3377 while (fp
!= NULL
) {
3385 /*---------------------------------------------------------*/
3386 /* Convert a number (up to 99999) to its base-36 equivalent */
3387 /*---------------------------------------------------------*/
3389 int convert_to_b36(int number
)
3394 b36idx
= (tmpidx
/ 10000) * 1679616;
3396 b36idx
+= (tmpidx
/ 1000) * 46656;
3398 b36idx
+= (tmpidx
/ 100) * 1296;
3400 b36idx
+= ((tmpidx
/ 10) * 36) + (tmpidx
% 10);
3405 /*----------------------------------------------------------------------*/
3406 /* Generate an index number for this device. Count all devices having */
3407 /* the same device name (as printed in the netlist) in the calls of */
3408 /* the calling object (cfrom) */
3410 /* Update (9/29/04): Remove any leading whitespace from the device */
3411 /* name to prevent treating, for example, "J?" and " J?" as separate */
3414 /* Update (7/28/05): To allow SPICE device indices to include all */
3415 /* alphanumerics, we parse in base-36, and count in the subset of */
3416 /* base-36 that can be interpreted as decimal (1-9, 36-45, etc.) */
3417 /*----------------------------------------------------------------------*/
3419 u_int
devindex(objectptr cfrom
, CalllistPtr clist
)
3421 CalllistPtr cptr
, listfrom
= cfrom
->calls
;
3422 objectptr devobj
= clist
->callobj
;
3423 u_int
*occupied
, total
, objindex
, i
, b36idx
;
3424 char *devname
, *cname
;
3425 /* oparamptr ops; (jdk) */
3427 if (listfrom
== NULL
) return (u_int
)0;
3428 if (clist
->devindex
>= 0) return clist
->devindex
;
3430 devname
= (clist
->devname
== NULL
) ? devobj
->name
: clist
->devname
;
3431 while (isspace(*devname
)) devname
++;
3433 /* Count total number of devices */
3434 for (cptr
= listfrom
, total
= 0; cptr
!= NULL
; cptr
= cptr
->next
, total
++);
3435 occupied
= (u_int
*)malloc(total
* sizeof(u_int
));
3438 for (cptr
= listfrom
, total
= 0; cptr
!= NULL
; cptr
= cptr
->next
, total
++) {
3439 occupied
[total
] = 0;
3440 if (cptr
== clist
) continue;
3441 cname
= (cptr
->devname
== NULL
) ? cptr
->callobj
->name
: cptr
->devname
;
3442 while (isspace(*cname
)) cname
++;
3443 if (!strcmp(cname
, devname
)) {
3444 occupied
[total
] = cptr
->devindex
;
3445 if (cptr
->devindex
== objindex
) objindex
++;
3449 b36idx
= convert_to_b36(objindex
);
3450 for (; objindex
<= total
; objindex
++) {
3451 b36idx
= convert_to_b36(objindex
);
3452 for (i
= 0; i
< total
; i
++)
3453 if (occupied
[i
] == b36idx
)
3460 clist
->devindex
= b36idx
;
3464 /*----------------------------------------------------------------------*/
3465 /* Generate and return a list of all info label prefixes in a design */
3466 /* This does not depend on the netlist being generated (i.e., does not */
3467 /* use CalllistPtr) */
3468 /*----------------------------------------------------------------------*/
3470 void genprefixlist(objectptr cschem
, slistptr
*modelist
)
3479 for (pgen
= cschem
->plist
; pgen
< cschem
->plist
+ cschem
->parts
; pgen
++) {
3480 if (IS_LABEL(*pgen
)) {
3481 plabel
= TOLABEL(pgen
);
3482 if (plabel
->pin
== INFO
) {
3484 strptr
= findtextinstring(":", &locpos
, plabel
->string
, cinst
);
3485 if (locpos
<= 0 || strptr
== NULL
)
3486 continue; /* null after netlist type designator, don't count */
3488 for (modeptr
= *modelist
; modeptr
; modeptr
= modeptr
->next
)
3489 if (!strncmp(modeptr
->alias
, strptr
->data
.string
, locpos
))
3492 if (modeptr
== NULL
) { /* Mode has not been enumerated */
3493 modeptr
= (slistptr
)malloc(sizeof(stringlist
));
3494 modeptr
->alias
= (char *)malloc(locpos
+ 1);
3495 strncpy(modeptr
->alias
, strptr
->data
.string
, locpos
);
3496 modeptr
->next
= *modelist
;
3497 *modelist
= modeptr
;
3501 else if (IS_OBJINST(*pgen
)) {
3502 cinst
= TOOBJINST(pgen
);
3503 genprefixlist(cinst
->thisobject
, modelist
);
3504 if (cinst
->thisobject
->symschem
!= NULL
)
3505 genprefixlist(cinst
->thisobject
->symschem
, modelist
);
3510 /*----------------------------------------------------------------------*/
3511 /* Create and return an ordered list of info labels for the schematic */
3512 /* page cschem. A linked label list is returned, combining info labels */
3513 /* from all schematic pages related to cschem (master and slave pages). */
3514 /* It is the responsibility of the calling routine to free the linked */
3516 /*----------------------------------------------------------------------*/
3518 LabellistPtr
geninfolist(objectptr cschem
, objinstptr cinst
, char *mode
)
3524 LabellistPtr newllist
, listtop
, srchlist
;
3531 for (pgen
= cschem
->plist
; pgen
< cschem
->plist
+ cschem
->parts
; pgen
++) {
3532 if (IS_LABEL(*pgen
)) {
3533 plabel
= TOLABEL(pgen
);
3534 if ((plabel
->pin
== INFO
) && !textncomp(plabel
->string
, mode
, cinst
)) {
3536 if (mode
[0] == '\0') {
3537 strptr
= findtextinstring(":", &locpos
, plabel
->string
, cinst
);
3541 strptr
= findstringpart(strlen(mode
), &locpos
, plabel
->string
, cinst
);
3544 continue; /* null after netlist type designator */
3546 strt
= strptr
->data
.string
+ locpos
+ 1;
3549 if (sscanf(strt
, "%d", &j
) != 1) continue;
3551 /* Consider only positive-valued numbers. Negative */
3552 /* indices are handled by "writenet" by merging the */
3553 /* minus character into the mode name. */
3555 if (j
< 0) continue;
3556 if (j
>= vmax
) vmax
= j
+ 1;
3561 newllist
= (LabellistPtr
)malloc(sizeof(Labellist
));
3562 newllist
->label
= plabel
;
3563 newllist
->cschem
= cschem
;
3564 newllist
->cinst
= cinst
;
3565 newllist
->net
.id
= j
; /* use this to find the ordering */
3566 newllist
->subnets
= 0; /* so free() doesn't screw up */
3568 /* Order the linked list */
3570 if ((listtop
== NULL
) || (listtop
->net
.id
>= j
)) {
3571 newllist
->next
= listtop
;
3575 for (srchlist
= listtop
; srchlist
!= NULL
; srchlist
= srchlist
->next
) {
3576 if ((srchlist
->next
!= NULL
) && (srchlist
->next
->net
.id
>= j
)) {
3577 newllist
->next
= srchlist
->next
;
3578 srchlist
->next
= newllist
;
3581 else if (srchlist
->next
== NULL
) {
3582 srchlist
->next
= newllist
;
3583 newllist
->next
= NULL
;
3593 /*----------------------------------------------------------------------*/
3594 /* Trivial default pin name lookup. Parse an object's pin labels for */
3595 /* pin names. Return the text of the nth pin name, as counted by the */
3596 /* position in the object's parts list. If there are fewer than (n+1) */
3597 /* pin labels in the object, return NULL. Otherwise, return the pin */
3598 /* name in a malloc'd character string which the caller must free. */
3599 /*----------------------------------------------------------------------*/
3601 char *defaultpininfo(objinstptr cinst
, int pidx
)
3605 objectptr cschem
= cinst
->thisobject
;
3609 for (pgen
= cschem
->plist
; pgen
< cschem
->plist
+ cschem
->parts
; pgen
++) {
3610 if (IS_LABEL(*pgen
)) {
3611 plabel
= TOLABEL(pgen
);
3612 if (plabel
->pin
== LOCAL
) {
3613 if (count
== pidx
) {
3614 stxt
= textprint(plabel
->string
, cinst
);
3624 /*----------------------------------------------------------------------*/
3625 /* Parse an object's info labels for pin names. This is *not* a */
3626 /* netlist function. The nth pin name is returned, or NULL if not */
3627 /* found. Return value is a malloc'd string which the caller must */
3629 /*----------------------------------------------------------------------*/
3631 char *parsepininfo(objinstptr cinst
, char *mode
, int pidx
)
3635 u_char
*strt
, *fnsh
;
3636 int slen
, i
, locpos
;
3637 objectptr cschem
= cinst
->thisobject
;
3642 for (pgen
= cschem
->plist
; pgen
< cschem
->plist
+ cschem
->parts
; pgen
++) {
3643 if (IS_LABEL(*pgen
)) {
3644 plabel
= TOLABEL(pgen
);
3645 if (plabel
->pin
== INFO
) {
3646 slen
= stringlength(plabel
->string
, True
, cinst
);
3647 for (i
= 1; i
< slen
; i
++) {
3648 strptr
= findstringpart(i
, &locpos
, plabel
->string
, cinst
);
3649 if (locpos
>= 0 && *(strptr
->data
.string
+ locpos
) == ':') break;
3651 /* Currently we are not checking against "mode". . .*/
3652 /* interpret all characters after the colon */
3654 for (++i
; i
< slen
; i
++) {
3655 strptr
= findstringpart(i
, &locpos
, plabel
->string
, cinst
);
3658 /* Do for all text characters */
3659 strt
= strptr
->data
.string
+ locpos
;
3663 if (*strt
== 'p') { /* Pin found! */
3664 if (count
== pidx
) { /* Get pin text */
3667 while (*fnsh
!= ' ' && *fnsh
!= '\0') fnsh
++;
3668 sout
= malloc(fnsh
- strt
+ 1);
3669 strncpy(sout
, strt
, fnsh
- strt
);
3683 /*----------------------------------------------------------------------*/
3684 /* Look for information labels in the object parts list. Parse the */
3685 /* information labels and print results to specified output device. */
3686 /* (This is not very robust to errors---needs work!) */
3688 /* If "autonumber" is true, then the parsed info label is used to */
3689 /* auto-number devices. */
3690 /*----------------------------------------------------------------------*/
3692 char *parseinfo(objectptr cfrom
, objectptr cthis
, CalllistPtr clist
,
3693 char *prefix
, char *mode
, Boolean autonumber
, Boolean no_output
)
3695 /* genericptr *pgen; (jdk) */
3696 stringpart
*strptr
, *ppin
, *optr
;
3697 char *snew
, *sout
= NULL
, *pstring
;
3698 u_char
*strt
, *fnsh
;
3700 oparamptr ops
, instops
;
3701 int portid
, locpos
, i
, k
, subnet
, slen
; /* j, (jdk) */
3704 Boolean is_flat
= False
, is_symbol
= False
, is_iso
= False
, is_quoted
;
3705 Boolean do_update
= True
, include_once
= False
;
3706 char *locmode
, *b36str
, *sptr
;
3707 LabellistPtr infolist
, infoptr
;
3710 /* For flat netlists, prefix the mode with the word "flat". */
3711 /* As of 3/8/07, this includes the ".sim" format, which */
3712 /* should be called as mode "flatsim". */
3715 if (locmode
&& (!strncmp(mode
, "flat", 4) || !strncmp(mode
, "pseu", 4))) {
3720 /* mode == "" is passed when running resolve_devindex() and indicates */
3721 /* that the routine should be used to assign devindex to calls whose */
3722 /* devices have been manually assigned numbers. The preferred method */
3723 /* is to assign these values through the "index" parameter. Use of */
3724 /* parseinfo() ensures that objects that have no "index" parameter */
3725 /* but have valid info-labels for SPICE or PCB output will be */
3726 /* assigned the correct device index. */
3727 /* Sept. 3, 2006---The use of the prepended "@" character on */
3728 /* parameter names means that I can replace the cryptic "idx" with */
3729 /* the more obvious "index", which previously conflicted with the */
3730 /* PostScript command of the same name. Parameters "index" and "idx" */
3731 /* are treated interchangeably by the netlister. */
3733 if (locmode
[0] == '\0')
3736 /* 1st pass: look for valid labels; see if more than one applies. */
3737 /* If so, order them correctly. Labels may not be numbered in */
3738 /* sequence, and may begin with zero. We allow a lot of flexibility */
3739 /* but the general expectation is that sequences start at 0 or 1 and */
3740 /* increase by consecutive integers. */
3742 infolist
= geninfolist(cthis
, clist
->callinst
, locmode
);
3744 /* Now parse each label in sequence and output the result to */
3745 /* the return string. */
3747 sout
= (char *)malloc(1);
3750 for (infoptr
= infolist
; infoptr
!= NULL
; infoptr
= infoptr
->next
) {
3751 objectptr pschem
, cschem
= infoptr
->cschem
;
3752 labelptr plabel
= infoptr
->label
;
3753 objinstptr cinst
= infoptr
->cinst
;
3755 /* move to colon character */
3756 slen
= stringlength(plabel
->string
, True
, cinst
);
3757 for (i
= 1; i
< slen
; i
++) {
3758 strptr
= findstringpart(i
, &locpos
, plabel
->string
, cinst
);
3759 if (locpos
>= 0 && *(strptr
->data
.string
+ locpos
) == ':') break;
3762 /* interpret all characters after the colon */
3763 for (++i
; i
< slen
; i
++) {
3764 strptr
= findstringpart(i
, &locpos
, plabel
->string
, cinst
);
3767 /* Do for all text characters */
3768 strt
= strptr
->data
.string
+ locpos
;
3775 sout
= (char *)realloc(sout
, strlen(sout
) + 2);
3779 sout
= (char *)realloc(sout
, strlen(sout
) + 2);
3783 sout
= (char *)realloc(sout
, strlen(sout
) + 2);
3787 if (clist
->devname
== NULL
)
3788 clist
->devname
= strdup(sout
);
3791 newindex
= devflatindex(clist
->devname
);
3793 newindex
= devindex(cfrom
, clist
);
3794 b36str
= d36a(newindex
);
3795 sout
= (char *)realloc(sout
, strlen(sout
) + strlen(b36str
) + 1);
3796 sprintf(sout
+ strlen(sout
), "%s", b36str
);
3800 sout
= (char *)realloc(sout
, strlen(sout
)
3801 + strlen(cschem
->name
) + 1);
3802 strcat(sout
, cschem
->name
);
3805 sptr
= strstr(cschem
->name
, "::");
3807 sptr
= cschem
->name
;
3810 sout
= (char *)realloc(sout
, strlen(sout
)
3811 + strlen(sptr
) + 1);
3815 sout
= (char *)realloc(sout
, strlen(sout
) + 7);
3816 sprintf(sout
+ strlen(sout
), "%d",
3820 sout
= (char *)realloc(sout
, strlen(sout
) + 7);
3821 sprintf(sout
+ strlen(sout
), "%d",
3825 if (no_output
) break;
3826 include_once
= True
;
3829 if (no_output
) break;
3831 /* Followed by a filename to include verbatim into */
3832 /* the output. Filename either has no spaces or */
3835 /* Use textprint to catch any embedded parameters */
3837 snew
= textprint(strptr
, cinst
);
3839 while (*strt
!= '\0') {
3841 if (include_once
&& *(strt
+ 1) == 'F')
3843 else if (!include_once
&& *(strt
+ 1) == 'f')
3849 if (*strt
== '\0') {
3850 /* No filename; print verbatim */
3852 include_once
= False
;
3857 if (*strt
== '"') strt
++;
3858 if (*strt
== '"' || *strt
== '\0') break;
3860 while (*fnsh
!= '\0' && !isspace(*fnsh
) && *fnsh
!= '"')
3862 strncpy(_STR
, strt
, (int)(fnsh
- strt
));
3863 _STR
[(int)(fnsh
- strt
)] = '\0';
3867 /* Do variable and tilde expansion on the filename */
3868 xc_tilde_expand(_STR
, 149);
3869 xc_variable_expand(_STR
, 149);
3871 /* Check if this file has been included already */
3873 if (check_included(_STR
)) {
3874 include_once
= False
;
3877 append_included(_STR
);
3880 /* Open the indicated file and dump to the output */
3881 finclude
= fopen(_STR
, "r");
3882 if (finclude
!= NULL
) {
3885 int stlen
= strlen(sout
);
3886 while (fgets(_STR
, 149, finclude
)) {
3887 nlen
= strlen(_STR
);
3888 sout
= (char *)realloc(sout
, stlen
+ nlen
+ 1);
3889 sptr
= sout
+ stlen
;
3896 Wprintf("No file named %s found", _STR
);
3898 include_once
= False
;
3902 /* Pin name either has no spaces or is in quotes */
3909 if (*strt
== '"' || *strt
== '\0') break;
3911 while (*fnsh
!= '\0' && !isspace(*fnsh
) && *fnsh
!= '"')
3913 strncpy(_STR2
, strt
, (int)(fnsh
- strt
));
3914 _STR2
[(int)(fnsh
- strt
)] = '\0';
3916 /* if (is_quoted || *fnsh == '\0') i++; */
3919 /* Find the port which corresponds to this pin name */
3920 /* in the called object (cschem). If this is a */
3921 /* linked symbol/schematic, then the port list will */
3922 /* be in the schematic view, not in the symbol view */
3925 if (cschem
->ports
== NULL
&& cschem
->symschem
!= NULL
&&
3926 cschem
->symschem
->ports
!= NULL
)
3927 pschem
= cschem
->symschem
;
3929 for (ports
= pschem
->ports
; ports
!= NULL
;
3930 ports
= ports
->next
) {
3932 subnet
= getsubnet(ports
->netid
, pschem
);
3933 ppin
= nettopin(ports
->netid
, pschem
, NULL
);
3934 // NOTE: _STR is used inside textprintsubnet()
3935 pstring
= textprintsubnet(ppin
, NULL
, subnet
);
3936 if (!strcmp(pstring
, _STR2
)) {
3937 portid
= ports
->portid
;
3944 if (ports
!= NULL
) {
3946 /* Find the matching port in the calling object instance */
3948 for (ports
= clist
->ports
; ports
!= NULL
;
3949 ports
= ports
->next
)
3950 if (ports
->portid
== portid
) break;
3952 if (ports
!= NULL
) {
3954 ppin
= nettopin(ports
->netid
, cfrom
, prefix
);
3955 subnet
= getsubnet(ports
->netid
, cfrom
);
3956 snew
= textprintsubnet(ppin
, cinst
, subnet
);
3957 sout
= (char *)realloc(sout
, strlen(sout
) +
3964 Fprintf(stderr
, "Error: called non-existant port\n");
3968 Wprintf("No pin named %s in device %s", _STR
, cschem
->name
);
3972 /* Parameter name either has no spaces or is in quotes */
3979 if (*strt
== '"' || *strt
== '\0') break;
3981 while (*fnsh
!= '\0' && !isspace(*fnsh
) && *fnsh
!= '"')
3983 strncpy(_STR
, strt
, (int)(fnsh
- strt
));
3984 _STR
[(int)(fnsh
- strt
)] = '\0';
3986 /* if (is_quoted || *fnsh == '\0') i++; */
3989 /* Compare this name against the parameter keys */
3990 ops
= match_param(cschem
, _STR
);
3992 /* For backwards compatibility, also try matching against */
3993 /* the parameter default value (method used before */
3994 /* implementing parameters as key:value pairs). */
3997 for (ops
= cschem
->params
; ops
!= NULL
; ops
= ops
->next
) {
3998 if (ops
->type
== XC_STRING
) {
3999 if (!textcomp(ops
->parameter
.string
, _STR
, NULL
)) {
4000 /* substitute the parameter or default */
4001 instops
= find_param(cinst
, ops
->key
);
4002 optr
= instops
->parameter
.string
;
4003 if (stringlength(optr
, True
, cinst
) > 0) {
4004 snew
= textprint(optr
, cinst
);
4005 sout
= (char *)realloc(sout
, strlen(sout
)
4006 + strlen(snew
) + 1);
4017 Wprintf("No parameter named %s in device %s",
4018 _STR
, cschem
->name
);
4023 /* Presence of ".ends" statement forces xcircuit */
4024 /* not to write ".end" at the end of the netlist. */
4027 if (!strncmp(strt
+ 1, "ends", 4))
4030 sout
= (char *)realloc(sout
, strlen(sout
) + 2);
4031 *(sout
+ strlen(sout
) - 1) = *strt
;
4032 *(sout
+ strlen(sout
)) = '\0';
4037 if (clist
->devname
== NULL
)
4038 clist
->devname
= strdup(sout
);
4040 /* Parameters with unresolved question marks are treated */
4041 /* like a "%i" string. */
4043 if ((key
!= NULL
) && !textncomp(strptr
, "?", cinst
)) {
4044 if (do_update
|| autonumber
) {
4045 if (is_flat
|| (cfrom
== NULL
))
4046 newindex
= devflatindex(clist
->devname
);
4048 newindex
= devindex(cfrom
, clist
);
4050 b36str
= d36a(newindex
);
4051 sout
= (char *)realloc(sout
, strlen(sout
) + strlen(b36str
) + 1);
4052 sprintf(sout
+ k
, "%s", b36str
);
4055 /* When called with autonumber = TRUE, generate a parameter */
4056 /* instance, replacing the question mark with the new index */
4060 copyparams(cinst
, cinst
);
4061 ops
= match_instance_param(cinst
, key
);
4062 optr
= ops
->parameter
.string
;
4063 if (!textncomp(optr
, "?", cinst
)) {
4064 optr
->data
.string
= (char *)realloc(optr
->data
.string
,
4065 strlen(sout
+ k
) + 1);
4066 strcpy(optr
->data
.string
, sout
+ k
);
4068 else Wprintf("Error while auto-numbering parameters");
4069 resolveparams(cinst
);
4073 /* A "?" default parameter that has a (different) */
4074 /* instance value becomes the device number. */
4076 if ((key
!= NULL
) && (clist
->devindex
< 0)) {
4077 ops
= match_param(cschem
, key
);
4078 if (ops
->type
== XC_STRING
) {
4080 if (!textcomp(ops
->parameter
.string
, "?", NULL
)) {
4082 /* Ignore the value and generate one instead */
4083 newindex
= devflatindex(clist
->devname
);
4084 b36str
= d36a(newindex
);
4086 sout
= (char *)realloc(sout
, strlen(sout
)
4087 + strlen(b36str
) + 1);
4088 sprintf(sout
+ k
, "%s", b36str
);
4089 continue; /* go on to next stringpart */
4091 else if (cfrom
!= NULL
) {
4093 /* Interpret parameter string as a component */
4094 /* number so we can check for duplicates. Assume */
4095 /* a base-36 number, which includes all alphabet */
4096 /* characters. This will disambiguate, e.g., "1" */
4097 /* and "1R", but flag case-sensitivity, e.g., */
4098 /* "1R" and "1r". Thanks to Carsten Thomas for */
4099 /* pointing out the problem with assuming */
4100 /* numerical component values. */
4103 newindex
= (u_int
) strtol(strt
, &endptr
, 36);
4104 if (*endptr
!= '\0') {
4105 Fprintf(stderr
, "Warning: Use of non-alphanumeric"
4106 " characters in component number \"%s\"\n", strt
);
4108 clist
->devindex
= newindex
;
4109 for (plist
= cfrom
->calls
; plist
; plist
= plist
->next
) {
4110 if ((plist
== clist
) ||
4111 (plist
->callobj
!= clist
->callobj
)) continue;
4113 /* Two parts have been named the same. Flag */
4114 /* it, but don't try to do anything about it. */
4115 /* 11/22/06---additionally check part numbers, */
4116 /* in case the symbol is a component sub-part. */
4118 if (plist
->devindex
== newindex
) {
4119 if (samepart(plist
, clist
)) {
4120 Fprintf(stderr
, "Warning: duplicate part number"
4121 " %s%s and %s%s\n", sout
, strt
, sout
, strt
);
4130 stlen
= strlen(sout
);
4131 sout
= (char *)realloc(sout
, stlen
+ 2);
4133 /* By convention, greek "mu" becomes ASCII "u", NOT "m", */
4134 /* otherwise we get, e.g., millifarads instead of microfarads */
4136 if ((is_symbol
&& (*strt
== 'm')) || (is_iso
&& (*strt
== 0265)))
4137 *(sout
+ stlen
) = 'u';
4139 *(sout
+ stlen
) = *strt
;
4140 *(sout
+ stlen
+ 1) = '\0';
4145 /* Some label controls are interpreted. Most are ignored */
4147 switch(strptr
->type
) {
4149 key
= strptr
->data
.string
;
4155 sout
= (char *)realloc(sout
, strlen(sout
) + 2);
4159 sout
= (char *)realloc(sout
, strlen(sout
) + 2);
4163 is_symbol
= issymbolfont(strptr
->data
.font
);
4164 is_iso
= isisolatin1(strptr
->data
.font
);
4170 /* Insert a newline between multiple valid info labels */
4171 if (infoptr
->next
!= NULL
) {
4172 sout
= (char *)realloc(sout
, strlen(sout
) + 2);
4176 freelabellist(&infoptr
);
4178 if (*sout
== '\0') {
4185 /*----------------------------------------------------------------------*/
4186 /* Write a low-level device */
4187 /*----------------------------------------------------------------------*/
4189 int writedevice(FILE *fp
, char *mode
, objectptr cfrom
, CalllistPtr clist
,
4195 if (clist
== NULL
) {
4196 if (fp
!= NULL
) fprintf(fp
, "error: null device\n");
4200 /* Devices are always symbols. If the call indicates a schematic */
4201 /* and a separate associated symbol, then we want the symbol. */
4202 /* If we're writing a flat netlist, then return -1 to indicate that */
4203 /* the symbol instance needs to be flattened. */
4205 cthis
= clist
->callobj
;
4206 if (clist
->callobj
->schemtype
== PRIMARY
|| clist
->callobj
->schemtype
==
4208 if (clist
->callobj
->symschem
!= NULL
) {
4209 if (!strncmp(mode
, "flat", 4))
4212 cthis
= clist
->callobj
->symschem
;
4215 /* Look for information labels in the object parts list. */
4217 if ((sout
= parseinfo(cfrom
, cthis
, clist
, prefix
, mode
, FALSE
, FALSE
)) != NULL
) {
4226 /* Information labels do not necessarily exist. */
4232 /*----------------------------------------------------------------------*/
4233 /* Translate a hierarchical net name into an object and instance. */
4234 /* Return TRUE if found, FALSE if not. If found, object and instance */
4235 /* are returned in the argument pointers. */
4236 /*----------------------------------------------------------------------*/
4238 Boolean
HierNameToObject(objinstptr cinst
, char *hiername
, pushlistptr
*stack
)
4241 char *nexttoken
, *hptr
, *pptr
;
4242 objectptr cschem
, curobj
, newobj
;
4244 int devindex
, devlen
;
4245 /* pushlistptr stackentry; (jdk) */
4247 cschem
= cinst
->thisobject
;
4248 curobj
= (cschem
->schemtype
== SECONDARY
) ? cschem
->symschem
: cschem
;
4250 if (curobj
->calls
== NULL
) {
4251 if ((updatenets(cinst
, FALSE
) <= 0) || (curobj
->calls
== NULL
)) {
4252 Wprintf("Error in generating netlists!");
4258 while (hptr
!= NULL
) {
4259 nexttoken
= strchr(hptr
, '/');
4260 if (nexttoken
!= NULL
) *nexttoken
= '\0';
4261 pptr
= strrchr(hptr
, '(');
4263 if (sscanf(pptr
+ 1, "%d", &devindex
) == 0) {
4272 /* check to make sure that the netlist and device indices have been generated */
4273 for (calls
= curobj
->calls
; calls
!= NULL
; calls
= calls
->next
) {
4274 if (calls
->devindex
== -1) {
4275 cleartraversed(curobj
);
4276 resolve_indices(curobj
, FALSE
);
4280 /* hptr is now the object name, and devindex is the instance's call index */
4281 /* find the object corresponding to the name. */
4283 newobj
= NameToObject(hptr
, &newinst
, TRUE
);
4285 if (newobj
== NULL
) {
4287 /* Try device names (for netlist output) instead of object names */
4289 for (calls
= curobj
->calls
; calls
!= NULL
; calls
= calls
->next
) {
4290 if (calls
->devname
!= NULL
) {
4291 devlen
= strlen(calls
->devname
);
4292 if (!strncmp(hptr
, calls
->devname
, devlen
)) {
4293 if (devindex
== -1) {
4294 if (sscanf(hptr
+ devlen
, "%d", &devindex
) == 0)
4297 if (calls
->devindex
== devindex
) {
4298 newobj
= calls
->callinst
->thisobject
;
4306 for (calls
= curobj
->calls
; calls
!= NULL
; calls
= calls
->next
)
4307 if ((calls
->callobj
== newobj
) && (calls
->devindex
== devindex
))
4310 if (newobj
== NULL
|| calls
== NULL
) {
4311 Fprintf(stderr
, "object %s in hierarchy not found in schematic.\n", hptr
);
4316 /* Diagnostic information */
4317 /* fprintf(stderr, "object %s(%d) = %s\n", newobj->name, devindex, hptr); */
4319 curobj
= calls
->callobj
;
4320 push_stack(stack
, calls
->callinst
, NULL
);
4322 if (pptr
!= NULL
) *pptr
= '(';
4323 if (nexttoken
== NULL
) break;
4325 hptr
= nexttoken
+ 1;
4332 /*----------------------------------------------------------------------*/
4333 /* Save netlist into a flattened sim or spice file */
4334 /*----------------------------------------------------------------------*/
4336 void writeflat(objectptr cschem
, CalllistPtr cfrom
, char *prefix
, FILE *fp
, char *mode
)
4338 CalllistPtr calls
= cschem
->calls
;
4339 char *newprefix
= (char *)malloc(sizeof(char));
4341 /* reset device indexes */
4343 for (calls
= cschem
->calls
; calls
!= NULL
; calls
= calls
->next
)
4344 calls
->devindex
= -1;
4346 /* The naming convention for nodes below the top level uses a */
4347 /* slash-separated list of hierarchical names. Thus the call to */
4348 /* the hierarchical resolve_indices(). Indices used by bottom-most */
4349 /* symbols (e.g., flattened spice) will be generated by a separate */
4350 /* routine devflatindex(), unrelated to what is generated here, */
4351 /* which only affects the hierarchical naming of nodes. */
4353 resolve_indices(cschem
, FALSE
);
4355 /* write all the subcircuits */
4357 for (calls
= cschem
->calls
; calls
!= NULL
; calls
= calls
->next
) {
4359 makelocalpins(cschem
, calls
, prefix
);
4360 if (writedevice(fp
, mode
, cschem
, calls
, prefix
) < 0) {
4361 sprintf(_STR
, "%s_%u", calls
->callobj
->name
,
4362 devindex(cschem
, calls
));
4363 newprefix
= (char *)realloc(newprefix
, sizeof(char) * (strlen(prefix
)
4364 + strlen(_STR
) + 2));
4365 sprintf(newprefix
, "%s%s/", prefix
, _STR
);
4366 /* Allow cross-referenced parameters between symbols and schematics */
4367 /* by substituting into a schematic from its corresponding symbol */
4368 opsubstitute(calls
->callobj
, calls
->callinst
);
4369 /* psubstitute(calls->callinst); */
4370 writeflat(calls
->callobj
, calls
, newprefix
, fp
, mode
);
4372 clearlocalpins(calls
->callobj
);
4377 /*----------------------------------------------------------------------*/
4378 /* Topmost call to write a flattened netlist */
4379 /*----------------------------------------------------------------------*/
4381 void topflat(objectptr cschem
, objinstptr thisinst
, CalllistPtr cfrom
,
4382 char *prefix
, FILE *fp
, char *mode
)
4384 char *locmode
, *stsave
= NULL
;
4388 /* Set up local call list for parsing info labels in the top-level schematic */
4389 loccalls
.cschem
= NULL
;
4390 loccalls
.callobj
= cschem
;
4391 loccalls
.callinst
= thisinst
;
4392 loccalls
.devindex
= -1;
4393 loccalls
.ports
= NULL
;
4394 loccalls
.next
= NULL
;
4396 modlen
= strlen(mode
);
4397 locmode
= malloc(2 + modlen
);
4398 strcpy(locmode
, mode
);
4399 locmode
[modlen
+ 1] = '\0';
4401 /* "<mode>@" lines go in front */
4403 locmode
[modlen
] = '@';
4404 if (fp
!= NULL
) stsave
= parseinfo(NULL
, cschem
, &loccalls
, NULL
, locmode
, FALSE
,
4406 if (stsave
!= NULL
) {
4413 writeflat(cschem
, cfrom
, prefix
, fp
, mode
);
4416 /* Check for negative-numbered info labels, indicated output that */
4417 /* should be processed after everything else. */
4419 locmode
[modlen
] = '-';
4420 stsave
= parseinfo(NULL
, cschem
, &loccalls
, NULL
, locmode
, FALSE
, FALSE
);
4421 if (stsave
!= NULL
) {
4430 /*----------------------------------------------------------------------*/
4431 /* Write out the list of global nets and their pin names */
4432 /*----------------------------------------------------------------------*/
4434 void writeglobals(objectptr cschem
, FILE *fp
)
4440 if (fp
== NULL
) return;
4442 for (llist
= global_labels
; llist
!= NULL
; llist
= llist
->next
) {
4443 gpin
= llist
->label
;
4444 snew
= textprint(gpin
->string
, NULL
);
4445 fprintf(fp
, ".GLOBAL %s\n", snew
); /* hspice format */
4446 /* fprintf(fp, "%s = %d\n", snew, -gptr->netid); */ /* generic format */
4452 /*----------------------------------------------------------------------*/
4453 /* Write a SPICE subcircuit entry. */
4454 /*----------------------------------------------------------------------*/
4456 void writesubcircuit(FILE *fp
, objectptr cschem
)
4461 int netid
, length
, plen
, subnet
; /* portid, (jdk) */
4463 /* Objects which have no ports are not written */
4464 if ((cschem
->ports
!= NULL
) && (fp
!= NULL
)) {
4466 fprintf(fp
, ".subckt %s", cschem
->name
);
4467 length
= 9 + strlen(cschem
->name
);
4469 /* List of parameters in subcircuit. */
4470 /* Each parameter connects to a net which may have multiple */
4471 /* names, so find the net associated with the parameter */
4472 /* and convert it back into a pin name in the usual manner */
4473 /* using nettopin(). */
4475 for (ports
= cschem
->ports
; ports
!= NULL
;
4476 ports
= ports
->next
) {
4477 netid
= ports
->netid
;
4478 subnet
= getsubnet(netid
, cschem
);
4479 ppin
= nettopin(netid
, cschem
, NULL
);
4480 pstring
= textprintsubnet(ppin
, NULL
, subnet
);
4481 plen
= strlen(pstring
) + 1;
4482 if (length
+ plen
> 78) {
4483 fprintf(fp
, "\n+ "); /* SPICE line break & continuation */
4486 else length
+= plen
;
4487 fprintf(fp
, " %s", pstring
);
4494 /*----------------------------------------------------------------------*/
4495 /* Resolve device names (fill calllist structure member "devname") */
4496 /*----------------------------------------------------------------------*/
4498 void resolve_devnames(objectptr cschem
)
4504 for (calls
= cschem
->calls
; calls
!= NULL
; calls
= calls
->next
) {
4505 if (calls
->callobj
->traversed
== False
) {
4506 calls
->callobj
->traversed
= True
;
4507 resolve_devnames(calls
->callobj
);
4510 if (calls
->devname
== NULL
) {
4512 /* Check for "class" parameter. Note that although this */
4513 /* parameter may take a different instance value, the */
4514 /* device class is determined by the default value. */
4516 ops
= find_param(calls
->callinst
, "class");
4517 if (ops
&& (ops
->type
== XC_STRING
))
4518 calls
->devname
= textprint(ops
->parameter
.string
, NULL
);
4520 /* The slow way---parse info labels for any device information */
4521 if ((stmp
= parseinfo(cschem
, calls
->callinst
->thisobject
, calls
,
4522 NULL
, "", FALSE
, TRUE
)) != NULL
)
4529 /*----------------------------------------------------------------------*/
4530 /* Resolve (hierarchical) component numbering. If "autonumber" is TRUE */
4531 /* then this routine does auto-numbering. Otherwise, it auto-generates */
4532 /* device indices internally (in the "calllist" structure) but does not */
4533 /* copy them into parameter space. */
4535 /* Note: resolve_devindex() only operates on a single object. Use */
4536 /* resolve_indices() to operate on the entire hierarchy. */
4537 /*----------------------------------------------------------------------*/
4539 void resolve_devindex(objectptr cschem
, Boolean autonumber
)
4542 char *stmp
, *endptr
;
4543 char *idxtype
[] = {"index", "idx", NULL
};
4549 for (calls
= cschem
->calls
; calls
!= NULL
; calls
= calls
->next
) {
4551 /* Check if there is an "index" parameter set to "?" in */
4552 /* the object with no existing instance value. */
4554 for (j
= 0; idxtype
[j
] != NULL
; j
++)
4555 if ((ops
= match_param(calls
->callinst
->thisobject
, idxtype
[j
])) != NULL
)
4558 if (ops
&& (ops
->type
== XC_STRING
)) {
4559 if (!textcomp(ops
->parameter
.string
, "?", NULL
)) {
4560 cinst
= calls
->callinst
;
4561 ips
= match_instance_param(cinst
, idxtype
[j
]);
4562 if ((autonumber
== TRUE
) && (ips
== NULL
)) {
4563 copyparams(cinst
, cinst
);
4564 ops
= match_instance_param(cinst
, idxtype
[j
]);
4565 optr
= ops
->parameter
.string
;
4566 newindex
= devindex(cschem
, calls
);
4567 stmp
= d36a(newindex
);
4568 optr
->data
.string
= (char *)realloc(optr
->data
.string
, strlen(stmp
) + 1);
4569 sprintf(optr
->data
.string
, "%s", stmp
);
4571 else if (calls
->devindex
< 0) {
4573 optr
= ips
->parameter
.string
;
4574 if (optr
->type
!= TEXT_STRING
) {
4575 /* Not a simple string. Dump the text. */
4577 snew
= textprint(optr
, NULL
),
4578 newindex
= (u_int
) strtol(snew
, &endptr
, 36);
4582 newindex
= (u_int
) strtol(optr
->data
.string
, &endptr
, 36);
4584 if (*endptr
!= '\0') {
4585 /* It is possible to get an instance value that is */
4586 /* the same as the default, although this normally */
4587 /* doesn't happen. If it does, quietly remove the */
4588 /* unneeded instance value. */
4590 if (!stringcomp(ops
->parameter
.string
, ips
->parameter
.string
))
4591 resolveparams(cinst
);
4593 Fprintf(stderr
, "Warning: Use of non-alphanumeric"
4594 " characters in component \"%s%s\" (instance"
4595 " of %s)\n", (calls
->devname
) ? calls
->devname
4596 : calls
->callobj
->name
, optr
->data
.string
,
4597 calls
->callobj
->name
);
4600 calls
->devindex
= newindex
;
4602 else /* if (autonumber) */
4603 devindex(cschem
, calls
);
4608 /* The slow way---parse info labels for any index information */
4609 if ((stmp
= parseinfo(cschem
, calls
->callinst
->thisobject
, calls
,
4610 NULL
, "", autonumber
, TRUE
)) != NULL
)
4616 /*----------------------------------------------------------------------*/
4617 /* Recursive call to resolve_devindex() through the circuit hierarchy */
4618 /*----------------------------------------------------------------------*/
4620 void resolve_indices(objectptr cschem
, Boolean autonumber
) {
4623 for (calls
= cschem
->calls
; calls
!= NULL
; calls
= calls
->next
) {
4624 if (calls
->callobj
->traversed
== False
) {
4625 calls
->callobj
->traversed
= True
;
4626 resolve_indices(calls
->callobj
, autonumber
);
4629 resolve_devindex(cschem
, autonumber
);
4632 /*----------------------------------------------------------------------*/
4633 /* Recursive call to clear all generated device numbers. */
4634 /*----------------------------------------------------------------------*/
4636 void clear_indices(objectptr cschem
) {
4639 for (calls
= cschem
->calls
; calls
!= NULL
; calls
= calls
->next
) {
4640 if (calls
->callobj
->traversed
== False
) {
4641 calls
->callobj
->traversed
= True
;
4642 clear_indices(calls
->callobj
);
4644 calls
->devindex
= -1;
4648 /*----------------------------------------------------------------------*/
4649 /* Recursive call to clear all device indexes (parameter "index") */
4650 /*----------------------------------------------------------------------*/
4652 void unnumber(objectptr cschem
) {
4655 char *idxtype
[] = {"index", "idx", NULL
};
4658 for (calls
= cschem
->calls
; calls
!= NULL
; calls
= calls
->next
) {
4659 if (calls
->callobj
->traversed
== False
) {
4660 calls
->callobj
->traversed
= True
;
4661 unnumber(calls
->callobj
);
4664 for (j
= 0; idxtype
[j
] != NULL
; j
++)
4665 if ((ops
= match_param(calls
->callobj
, idxtype
[j
])) != NULL
) break;
4667 if (ops
&& (ops
->type
== XC_STRING
)) {
4668 if (!textcomp(ops
->parameter
.string
, "?", NULL
)) {
4669 ips
= match_instance_param(calls
->callinst
, idxtype
[j
]);
4671 free_instance_param(calls
->callinst
, ips
);
4677 /*----------------------------------------------------------------------*/
4678 /* Save netlist into a hierarchical file */
4679 /*----------------------------------------------------------------------*/
4681 void writehierarchy(objectptr cschem
, objinstptr thisinst
, CalllistPtr cfrom
,
4682 FILE *fp
, char *mode
)
4684 CalllistPtr calls
= cschem
->calls
;
4685 PortlistPtr ports
, plist
;
4686 int pnet
, portid
, length
, plen
, subnet
, modlen
; /* netid, (jdk) */
4687 char *locmode
= mode
, *stsave
= NULL
, *pstring
;
4691 if (cschem
->traversed
== True
) return;
4693 /* Set up local call list for parsing info labels in this schematic */
4694 loccalls
.cschem
= NULL
;
4695 loccalls
.callobj
= cschem
;
4696 loccalls
.callinst
= thisinst
;
4697 loccalls
.devindex
= -1;
4698 loccalls
.ports
= NULL
;
4699 loccalls
.next
= NULL
;
4701 modlen
= strlen(mode
);
4702 locmode
= malloc(2 + modlen
);
4703 strcpy(locmode
, mode
);
4704 locmode
[modlen
+ 1] = '\0';
4706 /* "<mode>@" lines go before any subcircuit calls */
4708 locmode
[modlen
] = '@';
4709 if (fp
!= NULL
) stsave
= parseinfo(NULL
, cschem
, &loccalls
, NULL
, locmode
, FALSE
,
4711 if (stsave
!= NULL
) {
4718 /* Subcircuits which make no calls or have no devices do not get written */
4720 if (calls
!= NULL
) {
4722 /* Make sure that all the subcircuits have been written first */
4724 for (; calls
!= NULL
; calls
= calls
->next
) {
4725 if (calls
->callobj
->traversed
== False
) {
4726 psubstitute(calls
->callinst
);
4727 writehierarchy(calls
->callobj
, calls
->callinst
, calls
, fp
, mode
);
4728 calls
->callobj
->traversed
= True
;
4731 if (cschem
->schemtype
== FUNDAMENTAL
) {
4737 /* Info-labels on a schematic (if any) get printed out first */
4739 if ((fp
!= NULL
) && (cschem
->calls
!= NULL
)) {
4740 stsave
= parseinfo(NULL
, cschem
, &loccalls
, NULL
, mode
, FALSE
, FALSE
);
4741 if (stsave
!= NULL
) {
4743 /* Check stsave for embedded SPICE subcircuit syntax */
4745 if (!strcmp(mode
, "spice"))
4746 if (strstr(stsave
, ".subckt ") == NULL
)
4747 writesubcircuit(fp
, cschem
);
4754 else if (cschem
->calls
!= NULL
)
4755 /* top-level schematics will be ignored because they have no ports */
4756 writesubcircuit(fp
, cschem
);
4759 /* Resolve all fixed part assignments (devindex) */
4760 resolve_devindex(cschem
, FALSE
);
4762 /* If the output file is NULL, then we're done */
4769 for (calls
= cschem
->calls
; calls
!= NULL
; calls
= calls
->next
) {
4771 /* writedevice() is just another call to parseinfo() */
4772 if (writedevice(fp
, mode
, cschem
, calls
, NULL
) < 0) {
4774 /* If the device did not produce any output in writedevice(), but */
4775 /* does not make any calls itself, then it is implicitly a TRIVIAL */
4778 if ((calls
->callobj
->schemtype
== TRIVIAL
) || (calls
->callobj
->calls
== NULL
))
4781 /* No syntax indicating how to write this call. Use SPICE "X" */
4782 /* format and arrange the parameters according to the structure. */
4784 calls
->devname
= strdup(spice_devname
);
4785 fprintf(fp
, "X%s", d36a(devindex(cschem
, calls
)));
4786 stsave
= calls
->callobj
->name
;
4789 /* The object's definition lists calls in the order of the object's */
4790 /* port list. Therefore, use this order to find the port list. */
4791 /* This will also deal with the fact that not every port has to be */
4792 /* called by the instance (ports may be left disconnected). */
4794 for (ports
= calls
->callobj
->ports
; ports
!= NULL
;
4795 ports
= ports
->next
) {
4796 portid
= ports
->portid
;
4797 for (plist
= calls
->ports
; plist
!= NULL
; plist
= plist
->next
)
4798 if (plist
->portid
== ports
->portid
)
4801 pnet
= (plist
== NULL
) ? netmax(cschem
) + 1 : plist
->netid
;
4802 subnet
= getsubnet(pnet
, cschem
);
4803 ppin
= nettopin(pnet
, cschem
, NULL
);
4804 pstring
= textprintsubnet(ppin
, NULL
, subnet
);
4805 plen
= strlen(pstring
) + 1;
4806 if (length
+ plen
> 78) {
4807 fprintf(fp
, "\n+ "); /* SPICE line continuation */
4810 else length
+= plen
;
4811 fprintf(fp
, " %s", pstring
);
4814 plen
= 1 + strlen(stsave
);
4815 if (length
+ plen
> 78) fprintf(fp
, "\n+ "); /* SPICE line cont. */
4816 fprintf(fp
, " %s\n", stsave
);
4820 /* Check for negative-numbered info labels, indicated output that */
4821 /* should be processed after everything else. If we're processing */
4822 /* SPICE output but the schematic does not provide a ".ends" */
4823 /* statement, then add it to the end of the deck. */
4825 if (cschem
->calls
!= NULL
) {
4826 locmode
[modlen
] = '-';
4827 stsave
= parseinfo(NULL
, cschem
, &loccalls
, NULL
, locmode
, FALSE
, FALSE
);
4828 if (stsave
!= NULL
) {
4832 if (!strcmp(mode
, "spice"))
4833 if (strstr(stsave
, ".ends") == NULL
)
4834 fprintf(fp
, ".ends\n");
4837 else if (cfrom
!= NULL
)
4838 fprintf(fp
, ".ends\n");
4846 /*----------------------------------------------------------------------*/
4847 /* Create generic netlist in the Tcl interpreter variable space */
4848 /*----------------------------------------------------------------------*/
4852 static Tcl_Obj
*tclparseinfo(objectptr cschem
)
4857 Tcl_Obj
*rlist
= Tcl_NewListObj(0, NULL
);
4859 for (pgen
= cschem
->plist
; pgen
< cschem
->plist
+ cschem
->parts
; pgen
++) {
4860 if (IS_LABEL(*pgen
)) {
4861 plabel
= TOLABEL(pgen
);
4862 if (plabel
->pin
== INFO
) {
4863 Tcl_ListObjAppendElement(xcinterp
, rlist
,
4864 TclGetStringParts(plabel
->string
));
4871 /*----------------------------------------------------------------------*/
4872 /* Write global variables to Tcl list (in key-value pairs which can be */
4873 /* turned into an array variable using the "array set" command) */
4875 /* Note: argument "cinst" is unused, but it really should be. We */
4876 /* should not assume that different schematics have the same list of */
4878 /*----------------------------------------------------------------------*/
4880 Tcl_Obj
*tclglobals(objinstptr cinst
)
4884 Tcl_Obj
*gdict
; /*, *netnum; (jdk) */
4888 gdict
= Tcl_NewListObj(0, NULL
);
4889 for (llist
= global_labels
; llist
!= NULL
; llist
= llist
->next
) {
4890 gpin
= llist
->label
;
4891 Tcl_ListObjAppendElement(xcinterp
, gdict
, TclGetStringParts(gpin
->string
));
4893 if (llist
->subnets
== 0) {
4894 netid
= llist
->net
.id
;
4897 sbus
= llist
->net
.list
+ lbus
;
4898 netid
= sbus
->netid
;
4900 Tcl_ListObjAppendElement(xcinterp
, gdict
, Tcl_NewIntObj(netid
));
4901 if (++lbus
>= llist
->subnets
) break;
4907 /*----------------------------------------------------------------------*/
4908 /* Write a generic hierarchical netlist into Tcl list "subcircuits" */
4909 /*----------------------------------------------------------------------*/
4911 void tclhierarchy(objectptr cschem
, objinstptr cinst
, CalllistPtr cfrom
, Tcl_Obj
*cktlist
)
4913 CalllistPtr calls
= cschem
->calls
;
4914 PortlistPtr ports
, plist
;
4915 int netid
, pnet
, portid
; /* , length, plen, i; (jdk) */
4916 Tcl_Obj
*tclports
, *tclcalls
, *tclnewcall
, *tclnets
, *netnum
;
4917 Tcl_Obj
*tcldevs
, *tclparams
, *subckt
, *newdev
, *tcllabel
, *portnum
;
4918 oparamptr paramlist
; /* , locparam; (jdk) */
4921 /* Trivial objects are by definition those that are supposed */
4922 /* to be resolved by the netlist generation prior to output */
4923 /* and ignored by the output generator. */
4925 if (cschem
->schemtype
== TRIVIAL
) return;
4927 /* Make sure that all the subcircuits have been written first */
4929 for (; calls
!= NULL
; calls
= calls
->next
) {
4930 if (calls
->callobj
->traversed
== False
) {
4931 tclhierarchy(calls
->callobj
, calls
->callinst
, calls
, cktlist
);
4932 calls
->callobj
->traversed
= True
;
4936 /* Write own subcircuit netlist */
4937 subckt
= Tcl_NewListObj(0, NULL
);
4939 /* Prepare the list of network cross-references */
4940 tclnets
= Tcl_NewListObj(0, NULL
);
4942 /* Make list of the nets which have been written so we don't redundantly */
4943 /* list any entries (use of calloc() initializes all entries to FALSE). */
4944 /* (calloc() replaced by malloc() and bzero() because Tcl doesn't */
4945 /* have a calloc() function (2/6/04)) */
4947 netsdone
= (char *)malloc(2 + netmax(cschem
));
4949 memset((void *)netsdone
, 0, 2 + netmax(cschem
));
4951 bzero((void *)netsdone
, 2 + netmax(cschem
));
4954 /* Write the name (key value pair) */
4955 Tcl_ListObjAppendElement(xcinterp
, subckt
, Tcl_NewStringObj("name", 4));
4956 Tcl_ListObjAppendElement(xcinterp
, subckt
, Tcl_NewStringObj(cschem
->name
,
4957 strlen(cschem
->name
)));
4959 /* Write the handle of the object instance (key value pair) */
4960 Tcl_ListObjAppendElement(xcinterp
, subckt
, Tcl_NewStringObj("handle", 6));
4961 Tcl_ListObjAppendElement(xcinterp
, subckt
, Tcl_NewHandleObj(cinst
));
4963 /* Write the list of ports */
4964 if ((ports
= cschem
->ports
) != NULL
) {
4966 /* List of ports in subcircuit. */
4967 /* Each parameter connects to a net which may have multiple */
4968 /* names, so find the net associated with the parameter */
4969 /* and convert it back into a pin name in the usual manner */
4970 /* using nettopin(). */
4972 tclports
= Tcl_NewListObj(0, NULL
);
4973 for (; ports
!= NULL
; ports
= ports
->next
) {
4974 netid
= ports
->netid
;
4975 portid
= ports
->portid
;
4976 netnum
= Tcl_NewIntObj(netid
);
4977 portnum
= Tcl_NewIntObj(portid
);
4978 Tcl_ListObjAppendElement(xcinterp
, tclports
, portnum
);
4979 Tcl_ListObjAppendElement(xcinterp
, tclports
, netnum
);
4980 if ((netid
>= 0) && (netsdone
[netid
] == (char)0))
4982 Tcl_ListObjAppendElement(xcinterp
, tclnets
, netnum
);
4983 Tcl_ListObjAppendElement(xcinterp
, tclnets
,
4984 TclGetStringParts(nettopin(netid
, cschem
, NULL
)));
4985 /* record this net as having been added to the list */
4986 netsdone
[netid
] = (char)1;
4989 Tcl_ListObjAppendElement(xcinterp
, subckt
, Tcl_NewStringObj("ports", 5));
4990 Tcl_ListObjAppendElement(xcinterp
, subckt
, tclports
);
4993 /* Write the list of parameter defaults (key:value pairs) */
4995 if (cschem
->params
!= NULL
) {
4996 tclparams
= Tcl_NewListObj(0, NULL
);
4998 for (paramlist
= cschem
->params
; paramlist
!= NULL
; paramlist
= paramlist
->next
) {
4999 Tcl_ListObjAppendElement(xcinterp
, tclparams
,
5000 Tcl_NewStringObj(paramlist
->key
, strlen(paramlist
->key
)));
5001 switch(paramlist
->type
) {
5003 Tcl_ListObjAppendElement(xcinterp
, tclparams
,
5004 Tcl_NewIntObj((int)paramlist
->parameter
.ivalue
));
5007 Tcl_ListObjAppendElement(xcinterp
, tclparams
,
5008 Tcl_NewDoubleObj((double)paramlist
->parameter
.fvalue
));
5011 tcllabel
= TclGetStringParts(paramlist
->parameter
.string
);
5012 /* Should get rid of last entry, "End Parameter"; not needed */
5013 Tcl_ListObjAppendElement(xcinterp
, tclparams
, tcllabel
);
5016 Tcl_ListObjAppendElement(xcinterp
, tclparams
,
5017 evaluate_raw(cschem
, paramlist
, cinst
, NULL
));
5021 Tcl_ListObjAppendElement(xcinterp
, subckt
, Tcl_NewStringObj("parameters", 10));
5022 Tcl_ListObjAppendElement(xcinterp
, subckt
, tclparams
);
5025 /* Write the list of calls to subcircuits */
5027 if ((calls
= cschem
->calls
) != NULL
) {
5028 tclcalls
= Tcl_NewListObj(0, NULL
);
5029 for (; calls
!= NULL
; calls
= calls
->next
) {
5031 /* Don't write calls to non-functional subcircuits. */
5032 if (calls
->callobj
->schemtype
== TRIVIAL
) continue;
5034 tclnewcall
= Tcl_NewListObj(0, NULL
);
5035 Tcl_ListObjAppendElement(xcinterp
, tclnewcall
, Tcl_NewStringObj("name", 4));
5036 Tcl_ListObjAppendElement(xcinterp
, tclnewcall
,
5037 Tcl_NewStringObj(calls
->callobj
->name
,
5038 strlen(calls
->callobj
->name
)));
5041 /* Log any local parameter instances */
5042 if (calls
->callinst
->params
!= NULL
) {
5043 tclparams
= Tcl_NewListObj(0, NULL
);
5045 for (paramlist
= calls
->callinst
->params
; paramlist
!= NULL
;
5046 paramlist
= paramlist
->next
) {
5047 Tcl_ListObjAppendElement(xcinterp
, tclparams
,
5048 Tcl_NewStringObj(paramlist
->key
, strlen(paramlist
->key
)));
5049 switch(paramlist
->type
) {
5051 Tcl_ListObjAppendElement(xcinterp
, tclparams
,
5052 Tcl_NewIntObj((int)paramlist
->parameter
.ivalue
));
5055 Tcl_ListObjAppendElement(xcinterp
, tclparams
,
5056 Tcl_NewDoubleObj((double)paramlist
->parameter
.fvalue
));
5059 Tcl_ListObjAppendElement(xcinterp
, tclparams
,
5060 TclGetStringParts(paramlist
->parameter
.string
));
5063 Tcl_ListObjAppendElement(xcinterp
, tclparams
,
5064 evaluate_raw(cschem
, paramlist
, cinst
, NULL
));
5068 Tcl_ListObjAppendElement(xcinterp
, tclnewcall
,
5069 Tcl_NewStringObj("parameters", 10));
5070 Tcl_ListObjAppendElement(xcinterp
, tclnewcall
, tclparams
);
5073 /* Called ports are listed by key:value pair (port number: net id) */
5075 if (calls
->callobj
->ports
!= NULL
) {
5076 tclports
= Tcl_NewListObj(0, NULL
);
5077 for (ports
= calls
->callobj
->ports
; ports
!= NULL
;
5078 ports
= ports
->next
) {
5079 portid
= ports
->portid
;
5080 for (plist
= calls
->ports
; plist
!= NULL
; plist
= plist
->next
)
5081 if (plist
->portid
== ports
->portid
)
5084 pnet
= (plist
== NULL
) ? netmax(cschem
) + 1 : plist
->netid
;
5086 netnum
= Tcl_NewIntObj((int)pnet
);
5087 portnum
= Tcl_NewIntObj(portid
);
5088 Tcl_ListObjAppendElement(xcinterp
, tclports
, portnum
);
5089 Tcl_ListObjAppendElement(xcinterp
, tclports
, netnum
);
5090 if ((pnet
>= 0) && (netsdone
[pnet
] == (char)0))
5092 Tcl_ListObjAppendElement(xcinterp
, tclnets
, netnum
);
5093 Tcl_ListObjAppendElement(xcinterp
, tclnets
,
5094 TclGetStringParts(nettopin(pnet
, cschem
, NULL
)));
5095 /* record this net as having been added to the list */
5096 netsdone
[pnet
] = (char)1;
5099 Tcl_ListObjAppendElement(xcinterp
, tclnewcall
,
5100 Tcl_NewStringObj("ports", 5));
5101 Tcl_ListObjAppendElement(xcinterp
, tclnewcall
, tclports
);
5103 Tcl_ListObjAppendElement(xcinterp
, tclcalls
, tclnewcall
);
5105 Tcl_ListObjAppendElement(xcinterp
, subckt
, Tcl_NewStringObj("calls", 5));
5106 Tcl_ListObjAppendElement(xcinterp
, subckt
, tclcalls
);
5110 /* If the object has info labels, write a device list. */
5111 /* Check both the schematic and its symbol for info labels. */
5113 tcldevs
= Tcl_NewListObj(0, NULL
);
5114 if (cschem
->symschem
!= NULL
) {
5115 newdev
= tclparseinfo(cschem
->symschem
);
5116 Tcl_ListObjAppendElement(xcinterp
, tcldevs
, newdev
);
5118 newdev
= tclparseinfo(cschem
);
5119 Tcl_ListObjAppendElement(xcinterp
, tcldevs
, newdev
);
5120 Tcl_ListObjAppendElement(xcinterp
, subckt
, Tcl_NewStringObj("devices", 7));
5121 Tcl_ListObjAppendElement(xcinterp
, subckt
, tcldevs
);
5123 /* Write the network cross-reference dictionary */
5124 Tcl_ListObjAppendElement(xcinterp
, subckt
, Tcl_NewStringObj("nets", 4));
5125 Tcl_ListObjAppendElement(xcinterp
, subckt
, tclnets
);
5127 Tcl_ListObjAppendElement(xcinterp
, cktlist
, subckt
);
5130 /*----------------------------------------------------------------------*/
5132 Tcl_Obj
*tcltoplevel(objinstptr cinst
)
5135 objectptr cschem
= cinst
->thisobject
;
5137 cktlist
= Tcl_NewListObj(0, NULL
);
5138 cleartraversed(cschem
);
5139 tclhierarchy(cschem
, cinst
, NULL
, cktlist
);
5143 #endif /* TCL_WRAPPER */
5145 /*----------------------------------------------------------------------*/
5146 /* Create generic netlist in the Python interpreter variable space */
5147 /*----------------------------------------------------------------------*/
5151 static PyObject
*pyparseinfo(objectptr cschem
)
5156 PyObject
*rlist
= PyList_New(0);
5158 for (pgen
= cschem
->plist
; pgen
< cschem
->plist
+ cschem
->parts
; pgen
++) {
5159 if (IS_LABEL(*pgen
)) {
5160 plabel
= TOLABEL(pgen
);
5161 if (plabel
->pin
== INFO
)
5162 PyList_Append(rlist
, PyGetStringParts(plabel
->string
));
5168 /*----------------------------------------------------------------------*/
5169 /* Write global variables to Python dictionary */
5170 /*----------------------------------------------------------------------*/
5172 PyObject
*pyglobals(objectptr cschem
)
5176 PyObject
*gdict
, *netnum
;
5180 gdict
= PyDict_New();
5181 for (llist
= global_labels
; llist
!= NULL
; llist
= llist
->next
) {
5182 gpin
= llist
->label
;
5184 if (llist
->subnets
== 0)
5185 netid
= llist
->net
.id
;
5187 sbus
= llist
->net
.list
+ lbus
;
5188 netid
= sbus
->netid
;
5190 netnum
= PyInt_FromLong((long)(netid
));
5191 PyDict_SetItem(gdict
, netnum
, PyGetStringParts(gpin
->string
));
5192 if (++lbus
>= llist
->subnets
) break;
5198 /*----------------------------------------------------------------------*/
5199 /* Write a generic hierarchical netlist into Python list "subcircuits" */
5200 /*----------------------------------------------------------------------*/
5202 void pyhierarchy(objectptr cschem
, CalllistPtr cfrom
, PyObject
*cktlist
)
5204 CalllistPtr calls
= cschem
->calls
;
5205 PortlistPtr ports
, plist
;
5206 int netid
, pnet
, portid
, length
, plen
, i
;
5207 PyObject
*pyports
, *pycalls
, *pynewcall
, *pynets
, *netnum
;
5208 PyObject
*pydevs
, *pyparams
, *subckt
, *newdev
, *pylabel
;
5209 oparamptr paramlist
;
5211 /* Trivial objects are by definition those that are supposed */
5212 /* to be resolved by the netlist generation prior to output */
5213 /* and ignored by the output generator. */
5215 if (cschem
->schemtype
== TRIVIAL
) return;
5217 /* Make sure that all the subcircuits have been written first */
5219 for (; calls
!= NULL
; calls
= calls
->next
) {
5220 if (calls
->callobj
->traversed
== False
) {
5221 calls
->callobj
->traversed
= True
;
5222 pyhierarchy(calls
->callobj
, calls
, cktlist
);
5226 /* Write own subcircuit netlist */
5227 subckt
= PyDict_New();
5229 /* Prepare the dictionary of network cross-references */
5230 pynets
= PyDict_New();
5232 /* Write the name */
5233 PyDict_SetItem(subckt
, PyString_FromString("name"),
5234 PyString_FromString(cschem
->name
));
5236 /* Write the list of ports */
5237 if ((ports
= cschem
->ports
) != NULL
) {
5239 /* List of ports in subcircuit. */
5240 /* Each parameter connects to a net which may have multiple */
5241 /* names, so find the net associated with the parameter */
5242 /* and convert it back into a pin name in the usual manner */
5243 /* using nettopin(). */
5245 pyports
= PyList_New(0);
5246 for (; ports
!= NULL
; ports
= ports
->next
) {
5247 netid
= ports
->netid
;
5248 netnum
= PyInt_FromLong((long)netid
);
5249 PyList_Append(pyports
, netnum
);
5251 PyDict_SetItem(pynets
, netnum
,
5252 PyGetStringParts(nettopin(netid
, cschem
, NULL
)));
5254 PyDict_SetItem(subckt
, PyString_FromString("ports"), pyports
);
5257 /* Write the list of parameters */
5259 if (cschem
->params
!= NULL
) {
5260 pyparams
= PyList_New(0);
5262 for (paramlist
= cschem
->params
; paramlist
!= NULL
; paramlist
= paramlist
->next
) {
5263 if (paramlist
->type
== XC_INT
)
5264 PyList_Append(pyparams
,
5265 PyInt_FromLong((long)paramlist
->parameter
.ivalue
));
5266 if (paramlist
->type
== XC_FLOAT
)
5267 PyList_Append(pyparams
,
5268 PyFloat_FromDouble((double)paramlist
->parameter
.fvalue
));
5269 else if (paramlist
->type
== XC_STRING
) {
5270 pylabel
= PyGetStringParts(paramlist
->parameter
.string
);
5271 /* Should get rid of last entry, "End Parameter"; not needed */
5272 PyList_Append(pyparams
, pylabel
);
5275 PyDict_SetItem(subckt
, PyString_FromString("parameters"), pyparams
);
5278 /* Write the list of calls to subcircuits */
5280 if ((calls
= cschem
->calls
) != NULL
) {
5281 pycalls
= PyList_New(0);
5282 for (; calls
!= NULL
; calls
= calls
->next
) {
5284 /* Don't write calls to non-functional subcircuits. */
5285 if (calls
->callobj
->schemtype
== TRIVIAL
) continue;
5287 pynewcall
= PyDict_New();
5288 PyDict_SetItem(pynewcall
, PyString_FromString("name"),
5289 PyString_FromString(calls
->callobj
->name
));
5291 /* Log any local parameter instances */
5292 if (calls
->callinst
->params
!= NULL
) {
5293 pyparams
= PyList_New(0);
5295 for (paramlist
= cschem
->params
; paramlist
!= NULL
;
5296 paramlist
= paramlist
->next
) {
5297 if (paramlist
->type
== XC_INT
)
5298 PyList_Append(pyparams
,
5299 PyInt_FromLong((long)paramlist
->parameter
.ivalue
));
5300 else if (paramlist
->type
== XC_FLOAT
)
5301 PyList_Append(pyparams
,
5302 PyFloat_FromDouble((double)paramlist
->parameter
.fvalue
));
5303 else if (paramlist
->type
== XC_STRING
)
5304 PyList_Append(pyparams
,
5305 PyGetStringParts(paramlist
->parameter
.string
));
5307 PyDict_SetItem(pynewcall
, PyString_FromString("parameters"),
5311 /* The object's definition lists calls in the order of the object's */
5312 /* port list. Therefore, use this order to find the port list. */
5313 /* Unconnected ports will be NULL entries in the list (?). */
5315 if (calls
->callobj
->ports
!= NULL
) {
5316 pyports
= PyList_New(0);
5317 for (ports
= calls
->callobj
->ports
; ports
!= NULL
;
5318 ports
= ports
->next
) {
5319 portid
= ports
->portid
;
5320 for (plist
= calls
->ports
; plist
!= NULL
; plist
= plist
->next
)
5321 if (plist
->portid
== ports
->portid
)
5324 pnet
= (plist
== NULL
) ? netmax(cschem
) + 1 : plist
->netid
;
5326 netnum
= PyInt_FromLong((long)pnet
);
5327 PyList_Append(pyports
, netnum
);
5329 PyDict_SetItem(pynets
, netnum
,
5330 PyGetStringParts(nettopin(pnet
, cschem
, NULL
)));
5332 PyDict_SetItem(pynewcall
, PyString_FromString("ports"), pyports
);
5334 PyList_Append(pycalls
, pynewcall
);
5336 PyDict_SetItem(subckt
, PyString_FromString("calls"), pycalls
);
5339 /* If the object has info labels, write a device list. */
5340 /* Check both the schematic and its symbol for info labels. */
5342 pydevs
= PyList_New(0);
5343 if (cschem
->symschem
!= NULL
) {
5344 newdev
= pyparseinfo(cschem
->symschem
);
5345 PyList_Append(pydevs
, newdev
);
5347 newdev
= pyparseinfo(cschem
);
5348 PyList_Append(pydevs
, newdev
);
5349 PyDict_SetItem(subckt
, PyString_FromString("devices"), pydevs
);
5351 /* Write the network cross-reference dictionary */
5352 PyDict_SetItem(subckt
, PyString_FromString("nets"), pynets
);
5354 PyList_Append(cktlist
, subckt
);
5357 /*----------------------------------------------------------------------*/
5359 PyObject
*pytoplevel(objectptr cschem
)
5363 cktlist
= PyList_New(0);
5364 cleartraversed(cschem
);
5365 pyhierarchy(cschem
, NULL
, cktlist
);
5369 #endif /* HAVE_PYTHON */
5371 /*----------------------------------------------------------------------*/
5372 /* Update networks in an object by checking if the network is valid, */
5373 /* and destroying and recreating the network if necessary. */
5375 /* Run cleartraversed() on all types. The traversed flag allows a */
5376 /* check for infinite recursion when creating calls. */
5378 /* Returns -1 on discovery of infinite recursion, 0 on failure to */
5379 /* generate a net, and 1 on success. */
5380 /*----------------------------------------------------------------------*/
5382 int updatenets(objinstptr uinst
, Boolean quiet
) {
5383 objectptr thisobject
;
5384 objinstptr thisinst
;
5387 /* Never try to generate a netlist while a file is being read, as */
5388 /* can happen if an expression parameter attempts to query a netlist */
5391 if (load_in_progress
) return 0;
5393 if (uinst
->thisobject
->symschem
!= NULL
5394 && uinst
->thisobject
->schemtype
!= PRIMARY
) {
5395 thisobject
= uinst
->thisobject
->symschem
;
5396 if ((spage
= is_page(thisobject
)) >= 0)
5397 thisinst
= xobjs
.pagelist
[spage
]->pageinst
;
5400 thisobject
= uinst
->thisobject
;
5404 if (checkvalid(thisobject
) == -1) {
5407 if (cleartraversed(thisobject
) == -1) {
5408 Wprintf("Netlist error: Check for recursion in circuit!");
5412 /* Note: destroy/create nets messes up the part list. Why?? */
5414 if (areawin
->selects
> 0)
5415 ssave
= remember_selection(areawin
->topinstance
, areawin
->selectlist
,
5417 destroynets(thisobject
);
5418 createnets(thisinst
, quiet
);
5419 if (areawin
->selects
> 0) {
5420 areawin
->selectlist
= regen_selection(areawin
->topinstance
, ssave
);
5421 free_selection(ssave
);
5425 if (thisobject
->labels
== NULL
&& thisobject
->polygons
== NULL
) {
5427 Wprintf("Netlist error: No netlist elements in object %s",
5434 /*----------------------------------------------------------------------*/
5435 /* Generate netlist, write information according to mode, and then */
5436 /* destroy the netlist (this will be replaced eventually with a dynamic */
5437 /* netlist model in which the netlist changes according to editing of */
5438 /* individual elements, not created and destroyed wholesale) */
5439 /*----------------------------------------------------------------------*/
5441 void writenet(objectptr thisobject
, char *mode
, char *suffix
)
5444 objinstptr thisinst
;
5446 char *prefix
, *cpos
, *locmode
= mode
, *stsave
= NULL
;
5448 /* Calllist topcell; (jdk) */
5449 Boolean is_spice
= FALSE
, sp_end_save
= spice_end
;
5451 /* Always use the master schematic, if there is one. */
5453 if (thisobject
->schemtype
== SECONDARY
)
5454 cschem
= thisobject
->symschem
;
5456 cschem
= thisobject
;
5458 /* Update the netlist if this has not been done */
5460 if (NameToPageObject(cschem
->name
, &thisinst
, NULL
) == NULL
) {
5461 Wprintf("Not a schematic. . . cannot generate output!\n");
5464 if (updatenets(thisinst
, FALSE
) <= 0) {
5465 Wprintf("No file written!");
5469 prefix
= (char *)malloc(sizeof(char));
5472 if ((cpos
= strchr(cschem
->name
, ':')) != NULL
) *cpos
= '\0';
5473 sprintf(filename
, "%s.%s", cschem
->name
, suffix
);
5474 if (cpos
!= NULL
) *cpos
= ':';
5476 if (!strncmp(mode
, "index", 5)) { /* This mode generates no output */
5480 else if ((fp
= fopen(filename
, "w")) == NULL
) {
5481 Wprintf("Could not open file %s for writing.", filename
);
5486 /* Clear device indices from any previous netlist output */
5487 cleartraversed(cschem
);
5488 clear_indices(cschem
);
5490 /* Make sure list of include-once files is empty */
5494 /* Handle different netlist modes */
5496 if (!strcmp(mode
, "spice")) {
5498 if (thisobject
->schemtype
== SYMBOL
)
5499 cschem
= thisobject
->symschem
;
5502 fprintf(fp
, "*SPICE %scircuit <%s> from XCircuit v%s rev %s\n\n",
5503 (thisobject
->schemtype
== SYMBOL
) ? "sub" : "",
5504 cschem
->name
, PROG_VERSION
, PROG_REVISION
);
5506 /* writeglobals(cschem, fp); */
5507 cleartraversed(cschem
);
5508 writehierarchy(cschem
, thisinst
, NULL
, fp
, mode
);
5510 else if (!strcmp(mode
, "flatspice")) {
5512 fprintf(fp
, "*SPICE (flattened) circuit \"%s\" from XCircuit v%s rev %s\n\n",
5513 cschem
->name
, PROG_VERSION
, PROG_REVISION
);
5514 if (stsave
!= NULL
) {
5518 topflat(cschem
, thisinst
, NULL
, prefix
, fp
, mode
);
5520 else if (!strcmp(mode
, "pseuspice")) {
5522 fprintf(fp
, "*SPICE subcircuit \"%s\" from XCircuit v%s rev %s\n\n",
5523 cschem
->name
, PROG_VERSION
, PROG_REVISION
);
5524 if (stsave
!= NULL
) {
5528 writeflat(cschem
, NULL
, prefix
, fp
, mode
);
5531 else if (!strcmp(mode
, "flatsim") || !strcmp(mode
, "pseusim")) {
5532 fprintf(fp
, "| sim circuit \"%s\" from XCircuit v%s rev %s\n",
5533 cschem
->name
, PROG_VERSION
, PROG_REVISION
);
5534 if (stsave
!= NULL
) {
5538 topflat(cschem
, thisinst
, NULL
, prefix
, fp
, mode
);
5540 else if (!strcmp(locmode
, "pcb")) {
5541 struct Ptab
*ptable
= (struct Ptab
*)NULL
;
5542 writepcb(&ptable
, cschem
, NULL
, "", mode
);
5543 if (stsave
!= NULL
) {
5547 outputpcb(ptable
, fp
);
5550 else if (!strncmp(mode
, "flat", 4)) {
5551 /* User-defined modes beginning with the word "flat": */
5552 /* Assume a flattened netlist, and assume nothing else. */
5554 if (thisobject
->schemtype
== SYMBOL
)
5555 cschem
= thisobject
->symschem
;
5556 cleartraversed(cschem
);
5557 writeflat(cschem
, NULL
, prefix
, fp
, mode
);
5560 else if (!strncmp(mode
, "pseu", 4)) {
5561 /* User-defined modes beginning with the word "pseu": */
5562 /* Assume a flattened netlist for everything under the top level. */
5564 if (thisobject
->schemtype
== SYMBOL
)
5565 cschem
= thisobject
->symschem
;
5566 cleartraversed(cschem
);
5567 topflat(cschem
, thisinst
, NULL
, prefix
, fp
, mode
);
5570 /* All user-defined modes: Assume a hierarchical netlist, and */
5571 /* assume nothing else. */
5573 if (thisobject
->schemtype
== SYMBOL
)
5574 cschem
= thisobject
->symschem
;
5575 cleartraversed(cschem
);
5576 writehierarchy(cschem
, thisinst
, NULL
, fp
, mode
);
5579 /* Finish up SPICE files with a ".end" statement (if requested) */
5580 if (is_spice
&& (spice_end
== True
)) fprintf(fp
, ".end\n");
5581 spice_end
= sp_end_save
;
5587 Wprintf("%s netlist saved as %s", mode
, filename
);
5589 if (stsave
!= NULL
) free(stsave
);
5593 /*----------------------------------------------------------------------*/
5594 /* Flatten netlist and save into a table of pcb-style nets */
5595 /* The routine is recursive. Each call returns TRUE if some nested */
5596 /* call generated output; this is a reasonable way to tell if we have */
5597 /* reached the bottom of the hierarchy. */
5598 /*----------------------------------------------------------------------*/
5600 Boolean
writepcb(struct Ptab
**ptableptr
, objectptr cschem
, CalllistPtr cfrom
,
5601 char *prefix
, char *mode
)
5607 int i
, testnet
, tmplen
, subnet
;
5608 char *newprefix
= (char *)malloc(sizeof(char));
5610 struct Ptab
*hidx
, *htmp
;
5611 struct Pstr
*tmpstr
;
5612 struct Pnet
*tmpnet
;
5616 Boolean outputdone
= FALSE
;
5619 /* Step 1A: Go through the polygons of this object and add */
5620 /* any unvisited nets to the table. */
5622 for (plist
= cschem
->polygons
; plist
!= NULL
; plist
= plist
->next
) {
5624 if (plist
->subnets
== 0)
5625 testnet
= plist
->net
.id
;
5627 sbus
= plist
->net
.list
+ lbus
;
5628 testnet
= sbus
->netid
;
5632 while (hidx
!= NULL
) {
5633 if (hidx
->nets
!= NULL
) {
5634 for (i
= 0; i
< hidx
->nets
->numnets
; i
++)
5635 if (*(hidx
->nets
->netidx
+ i
) == testnet
) break;
5636 if (i
< hidx
->nets
->numnets
) break;
5640 if (hidx
== NULL
) { /* make new entry for net in table */
5641 htmp
= (struct Ptab
*)malloc(sizeof(struct Ptab
));
5642 tmpnet
= (struct Pnet
*)malloc(sizeof(struct Pnet
));
5643 tmpnet
->numnets
= 1;
5644 tmpnet
->netidx
= (int *)malloc(sizeof(int));
5645 *(tmpnet
->netidx
) = testnet
;
5646 tmpnet
->next
= NULL
;
5647 htmp
->cschem
= cschem
;
5648 htmp
->nets
= tmpnet
;
5650 htmp
->next
= *ptableptr
;
5652 /* Fprintf(stdout, "Added new index entry for net %d\n", testnet); */
5654 if (++lbus
>= plist
->subnets
) break;
5658 /* Step 1B: Do the same thing for labels. */
5660 for (llist
= cschem
->labels
; llist
!= NULL
; llist
= llist
->next
) {
5662 if (llist
->subnets
== 0)
5663 testnet
= llist
->net
.id
;
5665 sbus
= llist
->net
.list
+ lbus
;
5666 testnet
= sbus
->netid
;
5670 while (hidx
!= NULL
) {
5671 if (hidx
->nets
!= NULL
) {
5672 for (i
= 0; i
< hidx
->nets
->numnets
; i
++)
5673 if (*(hidx
->nets
->netidx
+ i
) == testnet
) break;
5674 if (i
< hidx
->nets
->numnets
) break;
5678 if (hidx
== NULL
) { /* make new entry for net in table */
5679 htmp
= (struct Ptab
*)malloc(sizeof(struct Ptab
));
5680 tmpnet
= (struct Pnet
*)malloc(sizeof(struct Pnet
));
5681 tmpnet
->numnets
= 1;
5682 tmpnet
->netidx
= (int *)malloc(sizeof(int));
5683 *(tmpnet
->netidx
) = testnet
;
5684 tmpnet
->next
= NULL
;
5685 htmp
->cschem
= cschem
;
5686 htmp
->nets
= tmpnet
;
5688 htmp
->next
= *ptableptr
;
5690 /* Fprintf(stdout, "Added new index entry for net %d\n", testnet); */
5692 if (++lbus
>= llist
->subnets
) break;
5696 /* Step 2: Resolve fixed device indices */
5697 resolve_devindex(cschem
, FALSE
);
5699 /* Step 3: Go through the list of calls to search for endpoints */
5701 for (calls
= cschem
->calls
; calls
!= NULL
; calls
= calls
->next
) {
5704 cinst
= calls
->callinst
;
5706 /* Trivial objects should have been dealt with already. */
5707 /* If we don't continue the loop here, you get netlist output for */
5708 /* objects like dots and circles. */
5709 if (calls
->callobj
->schemtype
== TRIVIAL
) continue;
5711 /* Step 4: If call is to a bottom-most schematic, output the device connections */
5712 /* Info-label can provide an alternate name or specify the instance number */
5714 cthis
= calls
->callobj
;
5715 if (calls
->callobj
->schemtype
== PRIMARY
|| calls
->callobj
->schemtype
==
5717 if (calls
->callobj
->symschem
!= NULL
)
5718 cthis
= calls
->callobj
->symschem
;
5720 if ((sout
= parseinfo(cschem
, cthis
, calls
, prefix
, mode
, FALSE
, TRUE
)) == NULL
) {
5721 if (calls
->devname
== NULL
)
5722 calls
->devname
= strdup(calls
->callinst
->thisobject
->name
);
5723 sprintf(_STR
, "%s_%s", calls
->devname
, d36a(devindex(cschem
, calls
)));
5726 sscanf(sout
, "%s", _STR
); /* Copy the first word out of sout */
5728 newprefix
= (char *)realloc(newprefix
, sizeof(char) * (strlen(prefix
)
5729 + strlen(_STR
) + 2));
5730 sprintf(newprefix
, "%s%s/", prefix
, _STR
);
5732 /*----------------------------------------------------------------*/
5733 /* Parsing of the "pcb:" info label--- */
5734 /* Find all <net>=<name> strings and create the appropriate nets */
5735 /*----------------------------------------------------------------*/
5738 char rsave
, *lhs
, *rhs
, *rend
, *sptr
= sout
, *tmppinname
;
5740 while ((rhs
= strchr(sptr
, '=')) != NULL
) {
5741 Genericlist
*implicit
, newlist
;
5742 struct Pstr
*psrch
= NULL
;
5745 while ((lhs
>= sptr
) && isspace(*lhs
)) lhs
--;
5746 while ((lhs
>= sptr
) && !isspace(*lhs
)) lhs
--;
5749 if (isspace(*lhs
)) lhs
++;
5750 while ((*rhs
) && isspace(*rhs
)) rhs
++;
5751 for (rend
= rhs
; (*rend
) && (!isspace(*rend
)); rend
++);
5755 /* Get the net from the equation RHS. If none exists, assume */
5756 /* the name is a global net and add it to the list of globals. */
5758 implicit
= nametonet(cschem
, cinst
, rhs
);
5759 if (implicit
== NULL
) {
5763 labeldefaults(&templabel
, GLOBAL
, 0, 0);
5764 strptr
= templabel
.string
;
5765 strptr
->type
= TEXT_STRING
;
5766 strptr
->data
.string
= strdup(rhs
);
5767 newlist
.subnets
= 0;
5768 newlist
.net
.id
= globalmax() - 1;
5769 addglobalpin(cschem
, cinst
, &templabel
, &newlist
);
5770 implicit
= &newlist
;
5771 free(strptr
->data
.string
);
5774 /* Get the name of the pin */
5775 tmppinname
= (char *)malloc(strlen(newprefix
) + strlen(lhs
) + 2);
5776 strcpy(tmppinname
, newprefix
);
5777 if ((tmplen
= strlen(newprefix
)) > 0) tmppinname
[tmplen
- 1] = '-';
5778 strcat(tmppinname
, lhs
);
5780 /* Find the net in the ptable, or create a new entry for it */
5783 while (hidx
!= NULL
) {
5784 if (hidx
->nets
!= NULL
) {
5785 for (i
= 0; i
< hidx
->nets
->numnets
; i
++)
5786 if (*(hidx
->nets
->netidx
+ i
) == implicit
->net
.id
)
5788 if (i
< hidx
->nets
->numnets
) break;
5793 htmp
= (struct Ptab
*)malloc(sizeof(struct Ptab
));
5794 tmpnet
= (struct Pnet
*)malloc(sizeof(struct Pnet
));
5795 tmpnet
->numnets
= 1;
5796 tmpnet
->netidx
= (int *)malloc(sizeof(int));
5797 *(tmpnet
->netidx
) = implicit
->net
.id
;
5798 tmpnet
->next
= NULL
;
5799 htmp
->cschem
= cschem
;
5800 htmp
->nets
= tmpnet
;
5802 htmp
->next
= *ptableptr
;
5807 /* Check if any entries are the same as tmppinname */
5808 for (psrch
= hidx
->pins
; psrch
!= NULL
; psrch
= psrch
->next
) {
5809 if (!strcmp(psrch
->string
->data
.string
, tmppinname
))
5814 /* Get the pin name from the equation LHS */
5815 if (psrch
== NULL
) {
5816 tmpstr
= (struct Pstr
*)malloc(sizeof(struct Pstr
));
5817 tmpstr
->string
= (stringpart
*)malloc(sizeof(stringpart
));
5818 tmpstr
->string
->type
= TEXT_STRING
;
5819 tmpstr
->string
->nextpart
= NULL
;
5820 tmpstr
->string
->data
.string
= tmppinname
;
5821 tmpstr
->next
= hidx
->pins
;
5822 hidx
->pins
= tmpstr
;
5828 /* Proceed to the next LHS=RHS pair */
5836 if (calls
->callobj
->calls
!= NULL
) {
5838 /* Step 4A: Push current net translations */
5839 /* (Don't push or pop global net numbers: no translation needed!) */
5842 while (hidx
!= NULL
) {
5843 if ((hidx
->nets
!= NULL
) && (((hidx
->nets
->numnets
> 0) &&
5844 (*(hidx
->nets
->netidx
) >= 0)) || (hidx
->nets
->numnets
== 0))) {
5845 tmpnet
= (struct Pnet
*)malloc(sizeof(struct Pnet
));
5846 tmpnet
->numnets
= 0;
5847 tmpnet
->netidx
= NULL
;
5848 tmpnet
->next
= hidx
->nets
;
5849 hidx
->nets
= tmpnet
;
5854 /* Step 4B: Generate net translation table for each subcircuit */
5856 for (ports
= calls
->ports
; ports
!= NULL
; ports
= ports
->next
) {
5857 for (hidx
= *ptableptr
; hidx
!= NULL
; hidx
= hidx
->next
) {
5858 if (hidx
->nets
!= NULL
) {
5859 if (hidx
->nets
->next
!= NULL
) {
5860 for (i
= 0; i
< hidx
->nets
->next
->numnets
; i
++)
5861 if (*(hidx
->nets
->next
->netidx
+ i
) == ports
->netid
)
5863 if (i
< hidx
->nets
->next
->numnets
) break;
5865 else if (ports
->netid
< 0) {
5866 if (hidx
->nets
->netidx
!= NULL
)
5867 if (*(hidx
->nets
->netidx
) == ports
->netid
)
5873 hidx
->nets
->numnets
++;
5874 if (hidx
->nets
->numnets
== 1)
5875 hidx
->nets
->netidx
= (int *)malloc(sizeof(int));
5877 hidx
->nets
->netidx
= (int *)realloc(hidx
->nets
->netidx
,
5878 hidx
->nets
->numnets
* sizeof(int));
5880 /* Translate net value */
5881 locnet
= translatedown(ports
->netid
, ports
->portid
,
5883 *(hidx
->nets
->netidx
+ hidx
->nets
->numnets
- 1) = locnet
;
5885 /* Fprintf(stdout, "Translation: net %d in object %s is net "
5886 "%d in object %s\n", ports->netid, cschem->name,
5887 locnet, calls->callobj->name); */
5891 /* Step 4C: Run routine recursively on the subcircuit */
5892 /* If it had a "pcb:" info label that was handled, then ignore */
5894 /* Fprintf(stdout, "Recursive call of writepcb() to %s\n",
5895 calls->callobj->name); */
5897 outputcall
= writepcb(ptableptr
, calls
->callobj
, calls
, newprefix
, mode
);
5899 /* Step 4D: Pop the translation table */
5900 /* (Don't pop global nets (designated by negative net number)) */
5903 while (hidx
!= NULL
) {
5904 if ((hidx
->nets
!= NULL
) && (((hidx
->nets
->numnets
> 0) &&
5905 (*(hidx
->nets
->netidx
) >= 0)) || (hidx
->nets
->numnets
== 0))) {
5906 tmpnet
= hidx
->nets
->next
;
5907 if (hidx
->nets
->numnets
> 0) free(hidx
->nets
->netidx
);
5909 hidx
->nets
= tmpnet
;
5918 /* Fprintf(stdout, "Reached lowest-level schematic: Finding connections\n"); */
5919 for (ports
= calls
->ports
; ports
!= NULL
; ports
= ports
->next
) {
5920 locnet
= translatedown(ports
->netid
, ports
->portid
, calls
->callobj
);
5921 /* Global pin names should probably be ignored, not just */
5922 /* when an object is declared to be "trivial". Not sure if */
5923 /* this breaks certain netlists. . . */
5924 if (locnet
< 0) continue;
5926 /* Get the name of the pin in the called object with no prefix. */
5927 subnet
= getsubnet(locnet
, calls
->callobj
);
5928 ppin
= nettopin(locnet
, calls
->callobj
, NULL
);
5930 while (hidx
!= NULL
) {
5931 if ((hidx
->nets
!= NULL
) && (hidx
->nets
->numnets
> 0)) {
5932 /* Global nets were not translated, do not iterate through list */
5933 if (*(hidx
->nets
->netidx
) >= 0) {
5934 for (i
= 0; i
< hidx
->nets
->numnets
; i
++)
5935 if (*(hidx
->nets
->netidx
+ i
) == ports
->netid
)
5937 if (i
< hidx
->nets
->numnets
) break;
5939 if (*(hidx
->nets
->netidx
) == ports
->netid
) break;
5945 snew
= textprintsubnet(ppin
, cinst
, subnet
);
5946 Fprintf(stdout
, "Warning: Unconnected pin %s%s\n", newprefix
, snew
);
5952 tmpstr
= (struct Pstr
*)malloc(sizeof(struct Pstr
));
5953 tmpstr
->string
= (stringpart
*)malloc(sizeof(stringpart
));
5954 tmpstr
->string
->type
= TEXT_STRING
;
5955 tmpstr
->string
->nextpart
= NULL
;
5956 snew
= textprintsubnet(ppin
, cinst
, subnet
);
5957 tmpstr
->string
->data
.string
= (char *)malloc(strlen(newprefix
)
5958 + strlen(snew
) + 2);
5959 strcpy(tmpstr
->string
->data
.string
, newprefix
);
5960 /* Replace slash '/' with dash '-' at bottommost level */
5961 if ((tmplen
= strlen(newprefix
)) > 0)
5962 tmpstr
->string
->data
.string
[tmplen
- 1] = '-';
5963 strcat(tmpstr
->string
->data
.string
, snew
);
5965 tmpstr
->next
= hidx
->pins
;
5966 hidx
->pins
= tmpstr
;
5968 /* diagnostic information */
5970 struct Pnet
*locnet
= hidx
->nets
;
5972 while (locnet
->next
!= NULL
) {
5973 locnet
= locnet
->next
;
5976 /* Fprintf(stdout, "Logged level-%d net %d (local net %d) pin %s\n",
5977 ctr, *(locnet->netidx), *(hidx->nets->netidx + i),
5985 /* Step 5: Cleanup */
5991 /*----------------------------------------------------------------------*/
5992 /* Save PCB table into pcb-style file */
5993 /*----------------------------------------------------------------------*/
5995 void outputpcb(struct Ptab
*ptable
, FILE *fp
)
5997 int netidx
= 1, ccol
, subnet
;
6003 if (fp
== NULL
) return;
6005 for (pseek
= ptable
; pseek
!= NULL
; pseek
= pseek
->next
) {
6006 if (pseek
->pins
!= NULL
) {
6007 if ((pseek
->nets
!= NULL
) && (pseek
->nets
->numnets
> 0)) {
6008 subnet
= getsubnet(*(pseek
->nets
->netidx
), pseek
->cschem
);
6009 ppin
= nettopin(*(pseek
->nets
->netidx
), pseek
->cschem
, "");
6010 snew
= textprintsubnet(ppin
, NULL
, subnet
);
6015 sprintf(_STR
, "NET%d ", netidx
++);
6016 fprintf(fp
, "%-11s ", _STR
);
6018 for (sseek
= pseek
->pins
; sseek
!= NULL
; sseek
= sseek
->next
) {
6019 ccol
+= stringlength(sseek
->string
, False
, NULL
) + 3;
6021 fprintf(fp
, "\\\n ");
6022 ccol
= 18 + stringlength(sseek
->string
, False
, NULL
);
6024 snew
= textprint(sseek
->string
, NULL
);
6025 fprintf(fp
, "%s ", snew
);
6030 /* else fprintf(fp, "NET%d *UNCONNECTED*\n", netidx++); */
6034 /*----------------------------------------------*/
6035 /* free memory allocated to PCB net tables */
6036 /*----------------------------------------------*/
6038 void freepcb(struct Ptab
*ptable
)
6040 struct Ptab
*pseek
, *pseek2
;
6041 struct Pstr
*sseek
, *sseek2
;
6042 struct Pnet
*nseek
, *nseek2
;
6047 while (pseek2
!= NULL
) {
6048 pseek
= pseek
->next
;
6050 sseek
= pseek2
->pins
;
6052 while (sseek2
!= NULL
) {
6053 sseek
= sseek
->next
;
6054 freelabel(sseek2
->string
);
6059 nseek
= pseek2
->nets
;
6061 while (nseek2
!= NULL
) {
6062 nseek
= nseek
->next
;
6063 if (nseek2
->numnets
> 0) free(nseek2
->netidx
);
6073 /*----------------------------------------------------------------------*/
6074 /* Remove an element from the netlist. This is necessary when an */
6075 /* element is deleted from the object, so that the netlist does not */
6076 /* refer to a nonexistant element, or try to perform netlist function */
6079 /* Return True or False depending on whether a pin was "orphaned" on */
6080 /* the corresponding schematic or symbol (if any), as this may cause */
6081 /* the class of the object (FUNDAMENTAL, TRIVIAL, etc.) to change. */
6082 /*----------------------------------------------------------------------*/
6084 Boolean
RemoveFromNetlist(objectptr thisobject
, genericptr thiselem
)
6086 Boolean pinchanged
= False
;
6092 PolylistPtr plist
, plast
;
6093 LabellistPtr llist
, llast
;
6094 CalllistPtr clist
, clast
;
6096 pschem
= (thisobject
->schemtype
== SECONDARY
) ? thisobject
->symschem
6099 switch (thiselem
->type
) {
6101 ninst
= (objinstptr
)thiselem
;
6102 /* If this is an object instance, remove it from the calls */
6104 for (clist
= pschem
->calls
; clist
!= NULL
; clist
= clist
->next
) {
6105 if (clist
->callinst
== ninst
) {
6107 pschem
->calls
= clist
->next
;
6109 clast
->next
= clist
->next
;
6111 clist
= (clast
) ? clast
: pschem
->calls
;
6120 npoly
= (polyptr
)thiselem
;
6121 if (nonnetwork(npoly
)) break;
6123 /* If this is a polygon, remove it from the netlist */
6125 for (plist
= pschem
->polygons
; plist
!= NULL
; plist
= plist
->next
) {
6126 if (plist
->poly
== npoly
) {
6128 pschem
->polygons
= plist
->next
;
6130 plast
->next
= plist
->next
;
6131 if (plist
->subnets
> 0)
6132 free(plist
->net
.list
);
6141 nlab
= (labelptr
)thiselem
;
6142 if ((nlab
->pin
!= LOCAL
) && (nlab
->pin
!= GLOBAL
)) break;
6144 /* If this is a label, remove it from the netlist */
6146 for (llist
= pschem
->labels
; llist
!= NULL
; llist
= llist
->next
) {
6147 if (llist
->label
== nlab
) {
6149 pschem
->labels
= llist
->next
;
6151 llast
->next
= llist
->next
;
6152 if (llist
->subnets
> 0)
6153 free(llist
->net
.list
);
6160 /* Mark pin label in corresponding schematic/symbol as "orphaned" */
6161 /* by changing designation from type "pin" to type "label". */
6163 if (findlabelcopy(nlab
, nlab
->string
) == NULL
) {
6164 changeotherpins(NULL
, nlab
->string
);
6165 if (nlab
->pin
== INFO
) pinchanged
= True
;
6171 /*----------------------------------------------------------------------*/
6172 /* Remove one element from the netlist */
6173 /*----------------------------------------------------------------------*/
6175 void remove_netlist_element(objectptr cschem
, genericptr genelem
) {
6178 CalllistPtr clist
, clast
, cnext
;
6179 LabellistPtr llist
, llast
, lnext
;
6180 PolylistPtr plist
, plast
, pnext
;
6181 Boolean found
= FALSE
;
6183 /* Always call on the primary schematic */
6184 pschem
= (cschem
->schemtype
== SECONDARY
) ? cschem
->symschem
: cschem
;
6186 switch (ELEMENTTYPE(genelem
)) {
6188 /* remove polygon from polygon list */
6190 for (plist
= pschem
->polygons
; plist
!= NULL
; ) {
6191 pnext
= plist
->next
;
6192 if ((genericptr
)plist
->poly
== genelem
) {
6194 if (plist
->subnets
> 0)
6195 free(plist
->net
.list
);
6198 plast
->next
= pnext
;
6200 pschem
->polygons
= pnext
;
6211 /* remove label from label list */
6213 for (llist
= pschem
->labels
; llist
!= NULL
; ) {
6214 lnext
= llist
->next
;
6215 if ((genericptr
)llist
->label
== genelem
) {
6217 if (llist
->subnets
> 0)
6218 free(llist
->net
.list
);
6221 llast
->next
= lnext
;
6223 pschem
->labels
= lnext
;
6231 /* also check the globals */
6233 for (llist
= global_labels
; llist
!= NULL
; ) {
6234 lnext
= llist
->next
;
6235 if ((genericptr
)llist
->label
== genelem
) {
6237 if (llist
->subnets
> 0)
6238 free(llist
->net
.list
);
6241 llast
->next
= lnext
;
6243 global_labels
= lnext
;
6254 /* remove instance from call list */
6256 for (clist
= pschem
->calls
; clist
!= NULL
; ) {
6257 cnext
= clist
->next
;
6258 if ((genericptr
)clist
->callinst
== genelem
) {
6262 clast
->next
= cnext
;
6264 pschem
->calls
= cnext
;
6273 pschem
->valid
= FALSE
;
6276 /*----------------------------------------------------------------------*/
6277 /* Free memory allocated for the ports in a calls. */
6278 /*----------------------------------------------------------------------*/
6280 void freecalls(CalllistPtr calls
)
6282 PortlistPtr ports
, pptr
;
6284 for (ports
= calls
->ports
; ports
!= NULL
;) {
6289 if (calls
->devname
!= NULL
) free(calls
->devname
);
6293 /*----------------------------------------------------------------------*/
6294 /* Free memory for a Genericlist structure (may also be a Labellist or */
6295 /* Polylist structure). */
6296 /*----------------------------------------------------------------------*/
6298 void freegenlist(Genericlist
*nets
)
6300 if (nets
== NULL
) return;
6301 if (nets
->subnets
> 0)
6302 free(nets
->net
.list
);
6306 /*----------------------------------------------------------------------*/
6307 /* Free memory allocated for the label list in a netlist. */
6308 /*----------------------------------------------------------------------*/
6310 void freelabellist(LabellistPtr
*listtop
)
6312 LabellistPtr labellist
, llist
;
6314 for (labellist
= *listtop
; labellist
!= NULL
;) {
6315 llist
= labellist
->next
;
6316 freegenlist((Genericlist
*)labellist
);
6322 /*----------------------------------------------------------------------*/
6323 /* Free memory allocated for the polygon list in a netlist. */
6324 /*----------------------------------------------------------------------*/
6326 void freepolylist(PolylistPtr
*listtop
)
6328 PolylistPtr polylist
, plist
;
6330 for (polylist
= *listtop
; polylist
!= NULL
;) {
6331 plist
= polylist
->next
;
6332 freegenlist((Genericlist
*)polylist
);
6338 /*----------------------------------------------------------------------*/
6339 /* Free memory allocated for netlist */
6340 /*----------------------------------------------------------------------*/
6342 void freenetlist(objectptr cschem
)
6345 LabellistPtr
*llist
;
6347 plist
= &cschem
->polygons
;
6348 freepolylist(plist
);
6349 llist
= &cschem
->labels
;
6350 freelabellist(llist
);
6353 /*----------------------------------------------------------------------*/
6354 /* Clear the "traversed" flag in all objects of the hierarchy. */
6355 /*----------------------------------------------------------------------*/
6357 int cleartraversed_level(objectptr cschem
, int level
)
6361 objectptr callobj
, pschem
;
6363 /* Always call on the primary schematic */
6364 pschem
= (cschem
->schemtype
== SECONDARY
) ? cschem
->symschem
: cschem
;
6366 /* Recursively call cleartraversed() on all subobjects, a la gennetlist() */
6367 /* Use the parts list of the object, not the calls, because calls */
6368 /* may have been removed. */
6370 if (level
== HIERARCHY_LIMIT
) return -1;
6372 for (cgen
= pschem
->plist
; cgen
< pschem
->plist
+ pschem
->parts
; cgen
++) {
6373 if (IS_OBJINST(*cgen
)) {
6374 cinst
= TOOBJINST(cgen
);
6376 if (cinst
->thisobject
->symschem
!= NULL
)
6377 callobj
= cinst
->thisobject
->symschem
;
6379 callobj
= cinst
->thisobject
;
6381 /* Don't infinitely recurse if object is on its own schematic */
6382 /* However, we need to take a stab at more subtle recursion, too */
6384 if (callobj
!= pschem
)
6385 if (cleartraversed_level(callobj
, level
+ 1) == -1)
6389 pschem
->traversed
= False
;
6394 /*----------------------------------------------------------------------*/
6395 /* This is the routine normally called, as it hides the "level" */
6396 /* argument tagging the level of recursion. */
6397 /*----------------------------------------------------------------------*/
6399 int cleartraversed(objectptr cschem
) {
6400 return cleartraversed_level(cschem
, 0);
6403 /*----------------------------------------------------------------------*/
6404 /* If any part of the netlist is invalid, destroy the entire netlist */
6405 /*----------------------------------------------------------------------*/
6407 int checkvalid(objectptr cschem
)
6411 objectptr callobj
, pschem
;
6413 /* If the object has been declared a non-network object, ignore it */
6414 if (cschem
->schemtype
== NONETWORK
) return 0;
6416 /* Always operate on the master schematic */
6417 pschem
= (cschem
->schemtype
== SECONDARY
) ? cschem
->symschem
: cschem
;
6419 /* Stop immediately if the netlist is invalid */
6420 if (pschem
->valid
== False
) return -1;
6422 /* Otherwise, recursively call checkvalid() on all subobjects. */
6423 /* Use the parts list of the object, not the calls, because calls */
6424 /* may have been removed. */
6426 for (cgen
= pschem
->plist
; cgen
< pschem
->plist
+ pschem
->parts
; cgen
++) {
6427 if (IS_OBJINST(*cgen
)) {
6428 cinst
= TOOBJINST(cgen
);
6430 if (cinst
->thisobject
->symschem
!= NULL
)
6431 callobj
= cinst
->thisobject
->symschem
;
6433 callobj
= cinst
->thisobject
;
6435 /* Don't infinitely recurse if object is on its own schematic */
6437 if (callobj
== pschem
) continue;
6439 /* If there is a symbol, don't check its parts, but check if */
6440 /* its netlist has been checkvalid. */
6442 if ((cinst
->thisobject
->symschem
!= NULL
) &&
6443 (cinst
->thisobject
->labels
== NULL
) &&
6444 (cinst
->thisobject
->polygons
== NULL
) &&
6445 (cinst
->thisobject
->valid
== False
))
6448 /* Recursive call on subschematic */
6449 if (checkvalid(callobj
) == -1)
6453 return 0; /* All subnetlists and own netlist are valid */
6456 /*----------------------------------------------------------------------*/
6457 /* Free memory allocated to temporary labels generated for the netlist */
6458 /*----------------------------------------------------------------------*/
6460 void freetemplabels(objectptr cschem
)
6466 /* Recursively call freetemplabels() on all subobjects, a la gennetlist() */
6467 /* Use the parts list of the object, not the calls, because calls */
6468 /* may have been removed. */
6470 for (cgen
= cschem
->plist
; cgen
< cschem
->plist
+ cschem
->parts
; cgen
++) {
6471 if (IS_OBJINST(*cgen
)) {
6473 cinst
= TOOBJINST(cgen
);
6474 if (cinst
->thisobject
->symschem
!= NULL
)
6475 callobj
= cinst
->thisobject
->symschem
;
6477 callobj
= cinst
->thisobject
;
6479 /* Don't infinitely recurse if object is on its own schematic */
6480 if (callobj
!= cschem
) freetemplabels(callobj
);
6482 /* Also free the temp labels of any associated symbol */
6483 if (cinst
->thisobject
->symschem
!= NULL
) freetemplabels(cinst
->thisobject
);
6486 /* Free any temporary labels which have been created */
6488 else if (IS_LABEL(*cgen
)) {
6489 labelptr clab
= TOLABEL(cgen
);
6490 /* int tmpval = (int)(cgen - cschem->plist); (jdk) */
6491 if (clab
->string
->type
!= FONT_NAME
) {
6494 clab
= TOLABEL(cgen
);
6495 freelabel(clab
->string
);
6497 for (tgen
= cgen
+ 1; tgen
< cschem
->plist
+ cschem
->parts
; tgen
++)
6498 *(tgen
- 1) = *tgen
;
6506 /*----------------------------------------------------------------------*/
6507 /* Free memory allocated for netlists, ports, and calls */
6508 /*----------------------------------------------------------------------*/
6510 void freenets(objectptr cschem
)
6512 CalllistPtr calls
, cptr
;
6513 PortlistPtr ports
, pptr
;
6518 /* Recursively call freenets() on all subobjects, a la gennetlist() */
6519 /* Use the parts list of the object, not the calls, because calls */
6520 /* may have been removed. */
6522 if (cschem
->schemtype
== PRIMARY
|| cschem
->schemtype
== SECONDARY
||
6523 (cschem
->schemtype
== SYMBOL
&& cschem
->symschem
== NULL
)) {
6524 for (cgen
= cschem
->plist
; cgen
< cschem
->plist
+ cschem
->parts
; cgen
++) {
6525 if (IS_OBJINST(*cgen
)) {
6527 cinst
= TOOBJINST(cgen
);
6528 if (cinst
->thisobject
->symschem
!= NULL
)
6529 callobj
= cinst
->thisobject
->symschem
;
6531 callobj
= cinst
->thisobject
;
6533 /* Don't infinitely recurse if object is on its own schematic */
6534 if (callobj
!= cschem
) freenets(callobj
);
6536 /* Also free the netlist of any associated symbol */
6537 if (cinst
->thisobject
->symschem
!= NULL
) freenets(cinst
->thisobject
);
6542 /* Free the allocated structures for this object */
6544 for (calls
= cschem
->calls
; calls
!= NULL
;) {
6549 cschem
->calls
= NULL
;
6551 for (ports
= cschem
->ports
; ports
!= NULL
;) {
6556 cschem
->ports
= NULL
;
6558 freenetlist(cschem
);
6560 cschem
->traversed
= False
;
6561 cschem
->valid
= False
;
6562 freegenlist(cschem
->highlight
.netlist
);
6563 cschem
->highlight
.netlist
= NULL
;
6564 cschem
->highlight
.thisinst
= NULL
;
6567 /*----------------------------------------------------------------------*/
6568 /* Free the global pin list */
6569 /*----------------------------------------------------------------------*/
6573 LabellistPtr labellist
, llist
;
6575 for (labellist
= global_labels
; labellist
!= NULL
;) {
6576 llist
= labellist
->next
;
6578 /* Labels in the global list are temporary and must be deallocated */
6579 freelabel(labellist
->label
->string
);
6580 free(labellist
->label
);
6582 freegenlist((Genericlist
*)labellist
);
6585 global_labels
= NULL
;
6588 /*----------------------------------------------------------------------*/
6589 /* Get rid of locally-defined pin names */
6590 /*----------------------------------------------------------------------*/
6592 void clearlocalpins(objectptr cschem
)
6594 NetnamePtr netnames
, nextname
;
6596 for (netnames
= cschem
->netnames
; netnames
!= NULL
; ) {
6597 nextname
= netnames
->next
;
6598 if (netnames
->localpin
!= NULL
) {
6599 freelabel(netnames
->localpin
);
6602 netnames
= nextname
;
6604 cschem
->netnames
= NULL
;
6607 /*----------------------------------------------------------------------*/
6608 /* Handle lists of included files */
6609 /*----------------------------------------------------------------------*/
6611 /*----------------------------------------------------------------------*/
6612 /* check_included() --- check if a file has already been included. */
6613 /* Check by inode instead of filename so that we cannot trick the */
6614 /* program by giving, e.g., one relative path and one full path. */
6615 /*----------------------------------------------------------------------*/
6617 Boolean
check_included(char *filename
)
6619 struct stat filestatus
;
6622 if (stat(filename
, &filestatus
) == 0) {
6623 if (included_files
== NULL
) return FALSE
;
6624 for (numi
= 0; *(included_files
+ numi
) != (ino_t
)NULL
; numi
++) {
6625 if (*(included_files
+ numi
) == filestatus
.st_ino
) return TRUE
;
6631 /*----------------------------------------------------------------------*/
6632 /* append_included() --- update the list of included files by adding */
6633 /* the inode of filename to the list. */
6634 /*----------------------------------------------------------------------*/
6636 void append_included(char *filename
)
6638 struct stat filestatus
;
6641 if (stat(filename
, &filestatus
) == 0) {
6643 if (included_files
== NULL
) {
6644 included_files
= (ino_t
*)malloc(2 * sizeof(ino_t
));
6645 *included_files
= filestatus
.st_ino
;
6646 *(included_files
+ 1) = (ino_t
)NULL
;
6649 for (numi
= 0; *(included_files
+ numi
) != (ino_t
)NULL
; numi
++);
6651 included_files
= (ino_t
*)realloc(included_files
,
6652 (++numi
+ 1) * sizeof(ino_t
));
6654 *(included_files
+ numi
- 1) = filestatus
.st_ino
;
6655 *(included_files
+ numi
) = (ino_t
)NULL
;
6659 Wprintf("Error: Cannot stat include file \"%s\"\n", filename
);
6663 /*----------------------------------------------------------------------*/
6665 void free_included()
6667 if (included_files
!= NULL
) {
6668 free(included_files
);
6669 included_files
= NULL
;
6673 /*-------------------------------------------------------------------------*/