1 /***************************************************************************
2 SCED - Schematic Capture Editor
3 JSPICE3 adaptation of Spice3e2 - Copyright (c) Stephen R. Whiteley 1992
4 Copyright 1990 Regents of the University of California.  All rights reserved.
5 Authors: 1981 Giles C. Billingsley  (parts of KIC layout editor)
6          1992 Stephen R. Whiteley
7 ****************************************************************************/
8 
9 /* SCED routines for manipulating the property tables to
10  * establish connectivity for netlist generation.
11  */
12 
13 #include "spice.h"
14 #include "sced.h"
15 #include "scedmacs.h"
16 
17 #define umalloc(u) (union u*)tmalloc(sizeof(union u))
18 
19 /***********************************************************************
20  *
21  * Routines to reflect circuit changes in internal element properties.
22  *
23  ***********************************************************************/
24 
25 
26 void
UpdateProperties(Pointer)27 UpdateProperties(Pointer)
28 
29 /* Replace master relative coordinates with coordinates relative to
30  * the current cell.  Called from CDEndMakeCall().
31  */
32 struct o *Pointer;
33 {
34     struct prpty *PDesc;
35     long X,Y;
36 
37     for (PDesc = Pointer->oPrptyList; PDesc; PDesc = PDesc->prpty_Succ) {
38         switch (PDesc->prpty_Value) {
39             case P_NODE:
40                 TPoint((long*)&PDesc->prpty_Data->p_node.x,
41                     (long*)&PDesc->prpty_Data->p_node.y);
42                 continue;
43             case P_MUT:
44                 TPoint((long*)&PDesc->prpty_Data->p_mut.x1,
45                     (long*)&PDesc->prpty_Data->p_mut.y1);
46                 TPoint((long*)&PDesc->prpty_Data->p_mut.x2,
47                     (long*)&PDesc->prpty_Data->p_mut.y2);
48                 continue;
49             case P_BRANCH:
50                 TPoint((long*)&PDesc->prpty_Data->p_branch.x,
51                     (long*)&PDesc->prpty_Data->p_branch.y);
52                 TPoint((long*)&PDesc->prpty_Data->p_branch.r1,
53                     (long*)&PDesc->prpty_Data->p_branch.r2);
54                 X = 0;
55                 Y = 0;
56                 TPoint(&X,&Y);
57                 PDesc->prpty_Data->p_branch.r1 -= X;
58                 PDesc->prpty_Data->p_branch.r2 -= Y;
59                 continue;
60         }
61     }
62 }
63 
64 
65 static void
update_device(odesc,refcnts)66 update_device(odesc, refcnts)
67 
68 /* New in p6.
69  * Set the device name index.  The refcnts arg is a pointer to an array
70  * of 128 ints, and should be cleared before starting the successive
71  * calls to this routine for each device or subcircuit.
72  * The key character of the name field indexes the array.
73  */
74 struct o *odesc;
75 int refcnts[];
76 {
77     struct prpty *pdesc;
78 
79     for (pdesc = odesc->oPrptyList; pdesc; pdesc = pdesc->prpty_Succ) {
80         if (pdesc->prpty_Value == P_NAME) {
81             if (pdesc->prpty_Data->p_name.subname == NULL) {
82                 /* a device */
83                 pdesc->prpty_Data->p_name.num =
84                     ++(refcnts[(*pdesc->prpty_Data->p_name.name & 0x7f)]);
85             }
86             else {
87                 /* a subcircuit */
88                 pdesc->prpty_Data->p_name.num = ++(refcnts['X']);
89                 return;
90             }
91             break;
92         }
93     }
94 }
95 
96 
97 void
AssignWireProperties(Pointer)98 AssignWireProperties(Pointer)
99 
100 /* Assign initial properties to newly created wire. Called from wires.c */
101 struct o *Pointer;
102 {
103     struct prpty *PDesc;
104 
105     PDesc = alloc(prpty);
106     PDesc->prpty_Data = umalloc(prp_data);
107     PDesc->prpty_Value = P_NODE;
108     PDesc->prpty_Succ = Pointer->oPrptyList;
109     Pointer->oPrptyList = PDesc;
110 }
111 
112 
113 
114 /***********************************************************************
115  *
116  * Routines to create a spice deck for the circuit.
117  *
118  ***********************************************************************/
119 
120 #ifdef __STDC__
121 static void spice_deck_sort(struct line*);
122 static int  lcomp(char**,char**);
123 #else
124 static void spice_deck_sort();
125 static int  lcomp();
126 #endif
127 
128 char *MenuSPICE = "spice";
129 
130 
131 void
DoSpiceList()132 DoSpiceList()
133 
134 /* Generate the complete SPICE listing */
135 {
136     FILE *fp;
137     char *c;
138     struct line *d,*d0;
139 
140     sprintf(TypeOut,"%s",Parameters.kpCellName);
141     if ((c = strchr(TypeOut,'.')) != NULL)
142         *c = '\0';
143     strcat(TypeOut,".ckt");
144     fp = fopen(TypeOut,"w");
145     if (fp == NULL) {
146         ShowPrompt("Can't open netlist file.");
147         return;
148     }
149     MenuSelect(MenuSPICE);
150     sprintf(TypeOut + 80,"Netlist is in file %s.",TypeOut);
151     ShowPrompt(TypeOut + 80);
152     d0 = MakeSpiceDeck();
153     for (d = d0; d; d = d->li_next)
154         fprintf(fp,"%s\n",d->li_line);
155     inp_deckfree(d0);
156     fclose(fp);
157     MenuDeselect(MenuSPICE);
158 }
159 
160 
161 void
DumpSpiceFile(fp)162 DumpSpiceFile(fp)
163 
164 /* Dump the complete spice listing to a file. */
165 FILE *fp;
166 {
167     struct line *d0,*d,*d1;
168 
169     d0 = MakeSpiceDeck();
170     for (d = d0; d; d = d->li_next) {
171         if (d->li_actual != NULL) {
172             for (d1 = d->li_actual; d1; d1 = d1->li_next)
173                 fprintf(fp,"%s\n",d1->li_line);
174         }
175         else
176             fprintf(fp,"%s\n",d->li_line);
177     }
178     inp_deckfree(d0);
179 }
180 
181 
182 struct line *
MakeSpiceDeck()183 MakeSpiceDeck()
184 
185 /* return a linked list of line structures representing the circuit */
186 {
187     struct line *line,*d;
188     int count;
189 
190     Connect(Parameters.kpCellDesc);
191     sprintf(TypeOut,"Generated by SCED from file %s",Parameters.kpCellName);
192     line = AllocateLine(TypeOut);
193     line->li_next = SpiceList(Parameters.kpCellDesc);
194     for (d = line; d->li_next; d = d->li_next) ;
195     d->li_next = AllocateLine(".end");
196     d->li_next->li_next = NULL;
197     count = 0;
198     for (d = line; d; d = d->li_next)
199         d->li_linenum = count++;
200     return (line);
201 }
202 
203 
204 struct line *
SpiceList(CellDesc)205 SpiceList(CellDesc)
206 
207 /* Return a SPICE deck for the circuit in CellDesc, and recursively add
208  * subcircuits.
209  */
210 struct s *CellDesc;
211 {
212     struct g *GenDesc;
213     struct o *Pointer;
214     struct s *Desc, *TmpD;
215     struct m *MDesc;
216     struct prpty *PDesc;
217     struct line *d,*d1,*d0 = NULL;
218     union prp_data *p_data;
219     int nodes[20];
220     int foundsc;
221     int i,maxn;
222     char *device, *subname;
223     char *value,*model, *extra;
224     char *name, *s;
225 
226     QueueModel(NULL);
227 
228     /* need this for hypertext */
229     TmpD = Parameters.kpCellDesc;
230     Parameters.kpCellDesc = CellDesc;
231     HYinit();
232 
233     /* first add device and subcircuit calls */
234     if (Not CDInitGen(CellDesc,0,-CDINFINITY,-CDINFINITY,CDINFINITY,
235         CDINFINITY,&GenDesc)) MallocFailed();
236 
237     loop {
238 
239         CDGen(CellDesc,GenDesc,&Pointer);
240         if (Pointer == NULL) break;
241         if (Pointer->oInfo == SQ_GONE) continue;
242         /* skip gnd */
243         name = ((struct c *)Pointer->oRep)->cMaster->mName;
244         if (cieq(name,"gnd")) continue;
245 
246         PDesc = Pointer->oPrptyList;
247 
248         for (i = 0; i < 20; i++)
249             nodes[i] = 0;
250         maxn = 0;
251         device = NULL;
252         subname = NULL;
253         model = NULL;
254         value = NULL;
255         extra = NULL;
256 
257         for (; PDesc; PDesc = PDesc->prpty_Succ) {
258             p_data = PDesc->prpty_Data;
259             switch (PDesc->prpty_Value) {
260                 case P_NODE:
261                     nodes[p_data->p_node.inode] = p_data->p_node.enode;
262                     if (maxn < p_data->p_node.inode)
263                         maxn = p_data->p_node.inode;
264                     continue;
265                 case P_NAME:
266                     device = tmalloc(strlen(p_data->p_name.name)+10);
267                     sprintf(device,"%s%d",
268                         p_data->p_name.name,p_data->p_name.num);
269                     if (p_data->p_name.subname) {
270                         subname = CopyString(p_data->p_name.subname);
271                     }
272                     continue;
273                 case P_MODEL:
274                     if (p_data) {
275                         model = HYtostr((struct hprlist*)p_data);
276                         QueueModel(model);
277                     }
278                     continue;
279                 case P_VALUE:
280                     if (p_data) {
281                         value = HYtostr((struct hprlist*)p_data);
282                     }
283                     continue;
284                 case P_INITC:
285                     if (p_data) {
286                         extra = HYtostr((struct hprlist*)p_data);
287                     }
288                     continue;
289             }
290         }
291         if (!device)
292             /* should never happen */
293             continue;
294 
295         for (s = TypeOut,i = 0; i <= maxn; i++) {
296             sprintf(s," %d",nodes[i]);
297             while (*s) s++;
298         }
299         i = strlen(device) + strlen(TypeOut) + 1;
300         if (subname)
301             i += strlen(subname) + 1;
302         if (model)
303             i += strlen(model) + 1;
304         if (value)
305             i += strlen(value) + 1;
306         if (extra)
307             i += strlen(extra) + 1;
308 
309         device = trealloc(device,i+1);
310         s = device;
311         while (*s) s++;
312         *s++ = ' ';
313         strcpy(s,TypeOut);
314         while (*s) s++;
315         if (subname) {
316             *s++ = ' ';
317             strcpy(s,subname);
318             free(subname);
319             while (*s) s++;
320         }
321         if (model) {
322             *s++ = ' ';
323             strcpy(s,model);
324             free(model);
325             while (*s) s++;
326         }
327         if (value) {
328             *s++ = ' ';
329             strcpy(s,value);
330             free(value);
331             while (*s) s++;
332         }
333         if (extra) {
334             *s++ = ' ';
335             strcpy(s,extra);
336             free(extra);
337             while (*s) s++;
338         }
339 
340         if (d0 == NULL)
341             d = d0 = AllocateLine(device);
342         else {
343             d->li_next = AllocateLine(device);
344             d = d->li_next;
345         }
346         txfree(device);
347     }
348 
349     d1 = PrintMutual(CellDesc);
350     if (d0 == NULL)
351         d = d0 = d1;
352     else {
353         d->li_next = d1;
354     }
355     for (; d->li_next; d = d->li_next) ;
356 
357     /* sort the element cards */
358     spice_deck_sort(d0);
359 
360     /* now expand the subcircuits */
361     MDesc = CellDesc->sMasterList;
362     for (; MDesc; MDesc = MDesc->mSucc) {
363         if (Not CDOpen(MDesc->mName,&Desc,'r')) continue;
364         if (CDStatusInt == CDNEWSYMBOL Or CDStatusInt == CDPARSEFAILED)
365             continue;
366         for (i = 0; i < 20; i++)
367             nodes[i] = 0;
368         maxn = 0;
369         subname = NULL;
370         PDesc = Desc->sPrptyList;
371         Connect(Desc);
372         foundsc = False;
373         for (; PDesc; PDesc = PDesc->prpty_Succ) {
374             p_data = PDesc->prpty_Data;
375             switch (PDesc->prpty_Value) {
376                 case P_NODE:
377                     nodes[p_data->p_node.inode] = p_data->p_node.enode;
378                     if (maxn < p_data->p_node.inode)
379                         maxn = p_data->p_node.inode;
380                     continue;
381                 case P_NAME:
382                     /* The third entry in the name field signifies
383                      * a subcircuit.  Devices from the library
384                      * have only two entries.
385                      */
386                     if (p_data->p_name.subname == NULL)
387                         goto next;
388                     subname = CopyString(p_data->p_name.subname);
389                     foundsc = True;
390                     continue;
391                 case P_MODEL:
392                 case P_VALUE:
393                 case P_INITC:
394                     continue;
395             }
396         }
397         if (foundsc) {
398             sprintf(TypeOut,".subckt %s",subname);
399             s = TypeOut;
400             while (*s) s++;
401             for (i = 0; i <= maxn; i++) {
402                 sprintf(s," %d",nodes[i]);
403                 while (*s) s++;
404             }
405             if (d0 == NULL)
406                 d = d0 = AllocateLine(TypeOut);
407             else {
408                 d->li_next = AllocateLine(TypeOut);
409                 d = d->li_next;
410             }
411             d->li_next = SpiceList(Desc);
412             sprintf(TypeOut,".ends %s",subname);
413             free(subname);
414             for (; d->li_next; d = d->li_next) ;
415             d->li_next = AllocateLine(TypeOut);
416             d = d->li_next;
417         }
418 next:
419         ;
420     }
421     d1 = PrintModels();
422 
423     if (d0 == NULL)
424         d0 = d1;
425     else
426         d->li_next = d1;
427 
428     Parameters.kpCellDesc = TmpD;
429     return (d0);
430 }
431 
432 
433 static void
spice_deck_sort(line)434 spice_deck_sort(line)
435 
436 struct line *line;
437 {
438     struct line *l;
439     char **stuff;
440     int i;
441 
442     for (i = 0,l = line; l; i++,l = l->li_next) ;
443     if (i < 2) return;
444     stuff = (char **)malloc(i*sizeof(char *));
445     if (stuff == NULL) MallocFailed();
446     for (i = 0, l = line; l; i++,l = l->li_next)
447         stuff[i] = l->li_line;
448     qsort((char *) stuff, i, sizeof (char *),
449 #if __STDC__
450         (int(*)(const void*,const void*))lcomp);
451 #else
452         lcomp);
453 #endif
454     for (i = 0, l = line; l; i++,l = l->li_next)
455         l->li_line = stuff[i];
456     free(stuff);
457     return;
458 }
459 
460 
461 static int
lcomp(s,t)462 lcomp(s, t)
463 
464 char **s, **t;
465 {
466     return (strcmp(*s,*t));
467 }
468 
469 
470 /***********************************************************************
471  *
472  * Routines to establish circuit connectivity.
473  *
474  ***********************************************************************/
475 
476 /* element list */
477 struct ww {
478     struct o *ww_ptr;
479     struct ww *ww_next;
480 };
481 
482 #ifdef __STDC__
483 static int  is_wire_grounded(struct o*,struct p*);
484 static void set_wire_node(struct o*,int);
485 static void connect_wires(struct ww*,struct o*,struct o*);
486 static void change_wire_node(struct ww*,int,int);
487 static void renumber_wires(struct ww*,int*);
488 static void connect_wire_to_device(struct o*,struct o*);
489 static void connect_ground_to_device(struct o*,struct p*);
490 static void connect_devices(struct o*,struct o*,int*);
491 static void set_device_node(struct o*,int*);
492 static int  find_node(struct ww*,struct ww*,long,long);
493 static void ww_free(struct ww*);
494 static void p_free(struct p*);
495 #else
496 static int  is_wire_grounded();
497 static void set_wire_node();
498 static void connect_wires();
499 static void change_wire_node();
500 static void renumber_wires();
501 static void connect_wire_to_device();
502 static void connect_ground_to_device();
503 static void connect_devices();
504 static void set_device_node();
505 static int  find_node();
506 static void ww_free();
507 static void p_free();
508 #endif
509 
510 
511 void
ConnectRecursive(CellDesc)512 ConnectRecursive(CellDesc)
513 
514 struct s *CellDesc;
515 {
516     struct s *Desc, *TmpD;
517     struct m *MDesc;
518 
519     Connect(CellDesc);
520 
521     /* need this for hypertext */
522     TmpD = Parameters.kpCellDesc;
523     Parameters.kpCellDesc = CellDesc;
524     HYinit();
525 
526     /* now expand the subcircuits */
527     MDesc = CellDesc->sMasterList;
528     for (; MDesc; MDesc = MDesc->mSucc) {
529         if (Not CDOpen(MDesc->mName,&Desc,'r')) continue;
530         if (CDStatusInt == CDNEWSYMBOL Or CDStatusInt == CDPARSEFAILED)
531             continue;
532         ConnectRecursive(Desc);
533     }
534     Parameters.kpCellDesc = TmpD;
535 }
536 
537 
538 void
Connect(CellDesc)539 Connect(CellDesc)
540 
541 /* Assign node numbers to the terminals and wires in CellDesc */
542 struct s *CellDesc;
543 {
544     struct g *GenDesc;
545     struct o *Pointer;
546     struct prpty *PDesc;
547     struct ww *w0 = NULL, *d0 = NULL;
548     struct p *g0 = NULL, *g;
549     struct ww *w, *wx;
550     struct m *MDesc;
551     char *name;
552     int i, count;
553     int refcnts[128];
554 
555     /* Make a list of wires, and set the node to 0. */
556 
557     if (Not CDInitGen(CellDesc,1,-CDINFINITY,-CDINFINITY,
558         CDINFINITY,CDINFINITY,&GenDesc)) MallocFailed();
559 
560     loop {
561         CDGen(CellDesc,GenDesc,&Pointer);
562         if (Pointer == NULL) break;
563         if (Pointer->oInfo == SQ_GONE Or Pointer->oInfo == SQ_INCMPLT)
564             continue;
565         if (Pointer->oType == CDWIRE) {
566             if (w0 == NULL)
567                 w = w0 = alloc(ww);
568             else {
569                 w->ww_next = alloc(ww);
570                 w = w->ww_next;
571             }
572             w->ww_ptr = Pointer;
573             PDesc = Pointer->oPrptyList;
574             for (; PDesc; PDesc = PDesc->prpty_Succ) {
575                 if (PDesc->prpty_Value != P_NODE) continue;
576                 PDesc->prpty_Data->p_node.enode = 0;
577                 break;
578             }
579         }
580     }
581     if (w0 != NULL)
582         w->ww_next = NULL;
583 
584     /* Set the reference counts to zero.  Entries are used as counters
585      * for naming devices.
586      */
587     for (i = 0; i < 128; i++)
588         refcnts[i] = 0;
589 
590     /* Make a list of devices, and a list of ground coordinates.
591      * Set the device terminal nodes to -1.
592      */
593 
594     if (Not CDInitGen(CellDesc,0,-CDINFINITY,-CDINFINITY,CDINFINITY,
595         CDINFINITY,&GenDesc)) MallocFailed();
596 
597     loop {
598         CDGen(CellDesc,GenDesc,&Pointer);
599         if (Pointer == NULL) break;
600         if (Pointer->oInfo == SQ_GONE) continue;
601 
602         name = ((struct c *)Pointer->oRep)->cMaster->mName;
603         if (cieq(name,"gnd")) {
604             /* ground device */
605             if (g0 == NULL)
606                 g = g0 = alloc(p);
607             else {
608                 g->pSucc = alloc(p);
609                 g = g->pSucc;
610             }
611             PDesc = Pointer->oPrptyList;
612             for (; PDesc; PDesc = PDesc->prpty_Succ) {
613                 if (PDesc->prpty_Value != P_NODE) continue;
614                 g->pX = PDesc->prpty_Data->p_node.x;
615                 g->pY = PDesc->prpty_Data->p_node.y;
616                 break;
617             }
618         }
619         else {
620             if (d0 == NULL)
621                 w = d0 = alloc(ww);
622             else {
623                 w->ww_next = alloc(ww);
624                 w = w->ww_next;
625             }
626             w->ww_ptr = Pointer;
627             PDesc = Pointer->oPrptyList;
628             for (; PDesc; PDesc = PDesc->prpty_Succ) {
629                 if (PDesc->prpty_Value != P_NODE) continue;
630                 PDesc->prpty_Data->p_node.enode = -1;
631             }
632         }
633         update_device(Pointer, refcnts);
634     }
635     if (d0 != NULL)
636         w->ww_next = NULL;
637     if (g0 != NULL)
638         g->pSucc = NULL;
639 
640     for (count = 0,w = w0; w; w = w->ww_next)
641         if (!is_wire_grounded(w->ww_ptr,g0)) {
642             count++;
643             set_wire_node(w->ww_ptr,count);
644         }
645 
646     for (w = w0; w; w = w->ww_next)
647         for (wx = w->ww_next; wx; wx = wx->ww_next)
648             connect_wires(w0,w->ww_ptr,wx->ww_ptr);
649 
650     renumber_wires(w0,&count);
651 
652     for (w = w0; w; w = w->ww_next)
653         for (wx = d0; wx; wx = wx->ww_next)
654             connect_wire_to_device(w->ww_ptr,wx->ww_ptr);
655 
656     for (w = d0; w; w = w->ww_next)
657         connect_ground_to_device(w->ww_ptr,g0);
658 
659     for (w = d0; w; w = w->ww_next)
660         for (wx = w->ww_next; wx; wx = wx->ww_next)
661             connect_devices(w->ww_ptr,wx->ww_ptr,&count);
662 
663     for (w = d0; w; w = w->ww_next)
664         set_device_node(w->ww_ptr,&count);
665 
666     /* now set the subckt connections */
667     PDesc = CellDesc->sPrptyList;
668     for (; PDesc; PDesc = PDesc->prpty_Succ) {
669         if (PDesc->prpty_Value != P_NODE) continue;
670         PDesc->prpty_Data->p_node.enode = find_node(w0,d0,
671             PDesc->prpty_Data->p_node.x,PDesc->prpty_Data->p_node.y);
672     }
673 
674     ww_free(w0);
675     ww_free(d0);
676     p_free(g0);
677 }
678 
679 
680 static int
is_wire_grounded(Pointer,Path)681 is_wire_grounded(Pointer,Path)
682 
683 /* Return True if any vertex of the wire in Pointer matches one of the
684  * coordinates in Path.
685  */
686 struct o *Pointer;
687 struct p *Path;
688 {
689     struct p *Wpath, *w;
690 
691     Wpath = ((struct w *)Pointer->oRep)->wPath;
692 
693     for (; Wpath; Wpath = Wpath->pSucc)
694         for  (w = Path; w; w = w->pSucc)
695             if (w->pX == Wpath->pX && w->pY == Wpath->pY)
696                 return (True);
697 
698     return (False);
699 }
700 
701 
702 static void
set_wire_node(Pointer,indx)703 set_wire_node(Pointer,indx)
704 
705 /* Set the node property value of the wire in Pointer to indx. */
706 struct o *Pointer;
707 int indx;
708 {
709     struct prpty *PDesc;
710 
711     PDesc = Pointer->oPrptyList;
712     for (; PDesc; PDesc = PDesc->prpty_Succ)
713         if (PDesc->prpty_Value == P_NODE) break;
714     if (PDesc == NULL) return;
715     PDesc->prpty_Data->p_node.enode = indx;
716 }
717 
718 
719 static void
connect_wires(WList,Pointer1,Pointer2)720 connect_wires(WList,Pointer1,Pointer2)
721 
722 /* If the wires in Pointer1 and Pointer 2 have a vertex in common,
723  * equate the node parameters of the two wires, setting the higher node
724  * number to the lower.
725  */
726 struct ww *WList;
727 struct o *Pointer1,*Pointer2;
728 {
729     struct p *p1,*p2,*pp;
730     struct prpty *PDesc1,*PDesc2;
731     int node1,node2;
732 
733     p1 = ((struct w *)Pointer1->oRep)->wPath;
734     p2 = ((struct w *)Pointer2->oRep)->wPath;
735 
736     for (; p1; p1 = p1->pSucc) {
737         for (pp = p2; pp; pp = pp->pSucc) {
738 
739             if (p1->pX == pp->pX && p1->pY == pp->pY) {
740 
741                 PDesc1 = Pointer1->oPrptyList;
742                 PDesc2 = Pointer2->oPrptyList;
743 
744                 node1 = node2 = -1;
745 
746                 for (; PDesc1; PDesc1 = PDesc1->prpty_Succ) {
747                     if (PDesc1->prpty_Value != P_NODE) continue;
748                     node1 = PDesc1->prpty_Data->p_node.enode;
749                     break;
750                 }
751                 for (; PDesc2; PDesc2 = PDesc2->prpty_Succ) {
752                     if (PDesc2->prpty_Value != P_NODE) continue;
753                     node2 = PDesc2->prpty_Data->p_node.enode;
754                     break;
755                 }
756                 if (node1 < 0 || node2 < 0)
757                     /* Things are foobar */
758                     return;
759 
760                 if (node1 == node2) return;
761 
762                 if (node1 < node2)
763                     change_wire_node(WList,node2,node1);
764                 else
765                     change_wire_node(WList,node1,node2);
766                 return;
767             }
768         }
769     }
770 }
771 
772 
773 static void
change_wire_node(WList,oldnode,newnode)774 change_wire_node(WList,oldnode,newnode)
775 
776 /* change wires with node oldnode to newnode */
777 struct ww *WList;
778 int oldnode,newnode;
779 {
780     struct prpty *PDesc;
781 
782     for (; WList; WList = WList->ww_next) {
783         PDesc = WList->ww_ptr->oPrptyList;
784         for (; PDesc; PDesc = PDesc->prpty_Succ) {
785             if (PDesc->prpty_Value != P_NODE) continue;
786             if (PDesc->prpty_Data->p_node.enode == oldnode)
787                 PDesc->prpty_Data->p_node.enode = newnode;
788             break;
789         }
790     }
791 }
792 
793 
794 static void
renumber_wires(Wlist,count)795 renumber_wires(Wlist,count)
796 
797 /* find a compact numbering for wire nodes */
798 struct ww *Wlist;
799 int *count;
800 {
801     struct ww *w;
802     struct prpty *PDesc;
803     int *itmp,i,sum;
804 
805     itmp = (int *) malloc((*count+1)*sizeof(int));
806     if (itmp == NULL) MallocFailed();
807 
808     for (i = 0; i <= *count; i++)
809         *(itmp+i) = 0;
810 
811     for (w = Wlist; w; w = w->ww_next) {
812         PDesc =  w->ww_ptr->oPrptyList;
813         for (; PDesc; PDesc = PDesc->prpty_Succ) {
814             if  (PDesc->prpty_Value != P_NODE) continue;
815             if (PDesc->prpty_Data->p_node.enode == 0) continue;
816             itmp[PDesc->prpty_Data->p_node.enode] = 1;
817         }
818     }
819 
820     for (sum = 0,i = 1; i <= *count; i++) {
821         sum += itmp[i];
822         itmp[i]  = sum;
823     }
824     *count = sum;
825 
826     for (w = Wlist; w; w = w->ww_next) {
827         PDesc =  w->ww_ptr->oPrptyList;
828         for (; PDesc; PDesc = PDesc->prpty_Succ) {
829             if  (PDesc->prpty_Value != P_NODE) continue;
830             if (PDesc->prpty_Data->p_node.enode == 0) continue;
831             PDesc->prpty_Data->p_node.enode =
832                 itmp[PDesc->prpty_Data->p_node.enode];
833         }
834     }
835     free(itmp);
836 }
837 
838 
839 static void
connect_wire_to_device(Pointer1,Pointer2)840 connect_wire_to_device(Pointer1,Pointer2)
841 
842 /* If a vertex of the wire in Pointer1 matches a terminal of the device in
843  * Pointer2, set the device node to match the wire node.
844  */
845 struct o *Pointer1,*Pointer2;
846 {
847     struct p *p1, *pp;
848     struct prpty *PDesc1,*PDesc2;
849     int node1;
850 
851     p1 = ((struct w *)Pointer1->oRep)->wPath;
852     PDesc1 = Pointer1->oPrptyList;
853     node1 = -1;
854     for (; PDesc1; PDesc1 = PDesc1->prpty_Succ) {
855         if (PDesc1->prpty_Value != P_NODE) continue;
856         node1 = PDesc1->prpty_Data->p_node.enode;
857         break;
858     }
859     if (node1 < 0)
860         /* trouble */
861         return;
862 
863     PDesc2 = Pointer2->oPrptyList;
864     for (; PDesc2; PDesc2 = PDesc2->prpty_Succ) {
865         if (PDesc2->prpty_Value != P_NODE) continue;
866         for (pp = p1; pp; pp = pp->pSucc) {
867             if (pp->pX == PDesc2->prpty_Data->p_node.x &&
868                 pp->pY == PDesc2->prpty_Data->p_node.y) {
869                 PDesc2->prpty_Data->p_node.enode = node1;
870             }
871         }
872     }
873 }
874 
875 
876 static void
connect_ground_to_device(Pointer,Path)877 connect_ground_to_device(Pointer,Path)
878 
879 /* If any coordinate in Path matches a device terminal coordinate from
880  * Pointer, ground the device node.
881  */
882 struct o *Pointer;
883 struct p *Path;
884 {
885     struct prpty *PDesc;
886     struct p *pp;
887 
888     for (PDesc = Pointer->oPrptyList; PDesc; PDesc = PDesc->prpty_Succ) {
889         if (PDesc->prpty_Value != P_NODE) continue;
890         for (pp = Path; pp; pp = pp->pSucc) {
891             if (pp->pX == PDesc->prpty_Data->p_node.x &&
892                 pp->pY == PDesc->prpty_Data->p_node.y) {
893                 PDesc->prpty_Data->p_node.enode = 0;
894             }
895         }
896     }
897 }
898 
899 
900 static void
connect_devices(Pointer1,Pointer2,count)901 connect_devices(Pointer1,Pointer2,count)
902 
903 /* If any terminals in the devices in Pointer1 and Pointer2 share a
904  * coordinate, make sure both node numbers are equal and valid.  Assign
905  * a new node number if necessary.
906  */
907 struct o *Pointer1,*Pointer2;
908 int *count;
909 {
910 
911     struct prpty *PDesc1,*PDesc2,*pd;
912     int int11,int21;
913     int X,Y;
914 
915     PDesc1 = Pointer1->oPrptyList;
916     PDesc2 = Pointer2->oPrptyList;
917 
918     for (; PDesc1; PDesc1 = PDesc1->prpty_Succ) {
919         if (PDesc1->prpty_Value != P_NODE) continue;
920 
921         X = PDesc1->prpty_Data->p_node.x;
922         Y = PDesc1->prpty_Data->p_node.y;
923         int11 = PDesc1->prpty_Data->p_node.enode;
924 
925         for (pd = PDesc2; pd; pd = pd->prpty_Succ) {
926             if (pd->prpty_Value != P_NODE) continue;
927 
928             if (X == pd->prpty_Data->p_node.x &&
929                 Y == pd->prpty_Data->p_node.y) {
930 
931                 int21 = pd->prpty_Data->p_node.enode;
932 
933                 if (int11 < 0 && int21 >= 0) {
934                     PDesc1->prpty_Data->p_node.enode = int21;
935                     int11 = int21;
936                 }
937                 else if (int21 < 0 && int11 >= 0) {
938                     pd->prpty_Data->p_node.enode = int11;
939                 }
940                 else if (int11 < 0 && int21 < 0) {
941                     (*count)++;
942                     PDesc1->prpty_Data->p_node.enode = *count;
943                     pd->prpty_Data->p_node.enode = *count;
944                     int11 = *count;
945                 }
946                 else if (int11 != int21) {
947                     /* trouble */
948 
949                 }
950             }
951         }
952     }
953 }
954 
955 
956 static void
set_device_node(Pointer,count)957 set_device_node(Pointer,count)
958 
959 /* Assign node numbers to unassigned device terminals */
960 struct o *Pointer;
961 int *count;
962 {
963     struct prpty *PDesc;
964 
965     PDesc = Pointer->oPrptyList;
966     for (; PDesc; PDesc = PDesc->prpty_Succ) {
967         if (PDesc->prpty_Value != P_NODE) continue;
968         if (PDesc->prpty_Data->p_node.enode >= 0) continue;
969         (*count)++;
970         PDesc->prpty_Data->p_node.enode = *count;
971     }
972 }
973 
974 
975 static int
find_node(Wlist,Dlist,X,Y)976 find_node(Wlist,Dlist,X,Y)
977 
978 /* Return the node number of the terminal or vertex at the given
979  * coordinates.  If not found, return -1.
980  */
981 struct ww *Wlist,*Dlist;
982 long X,Y;
983 {
984     struct ww *w;
985     struct prpty *PDesc;
986     struct p *Path;
987 
988     /* first look at device terminals */
989     for (w = Dlist; w; w = w->ww_next) {
990         PDesc = w->ww_ptr->oPrptyList;
991         for (; PDesc; PDesc = PDesc->prpty_Succ) {
992             if (PDesc->prpty_Value != P_NODE) continue;
993             if (X == PDesc->prpty_Data->p_node.x &&
994                 Y == PDesc->prpty_Data->p_node.y)
995                 return (PDesc->prpty_Data->p_node.enode);
996         }
997     }
998 
999     /* now check wire vertices */
1000     for (w = Wlist; w; w = w->ww_next) {
1001         Path = ((struct w *)w->ww_ptr->oRep)->wPath;
1002         for (; Path; Path = Path->pSucc) {
1003             if (X == Path->pX && Y == Path->pY) {
1004                 PDesc = w->ww_ptr->oPrptyList;
1005                 for (; PDesc; PDesc = PDesc->prpty_Succ) {
1006                     if (PDesc->prpty_Value != P_NODE) continue;
1007                     return (PDesc->prpty_Data->p_node.enode);
1008                 }
1009             }
1010         }
1011     }
1012     return (-1);
1013 }
1014 
1015 
1016 static void
ww_free(w)1017 ww_free(w)
1018 
1019 struct ww  *w;
1020 {
1021     struct ww *wn;
1022 
1023     for (; w; w = wn) {
1024         wn = w->ww_next;
1025         tfree(w);
1026     }
1027 }
1028 
1029 
1030 static void
p_free(w)1031 p_free(w)
1032 
1033 struct p  *w;
1034 {
1035     struct p *wn;
1036 
1037     for (; w; w = wn) {
1038         wn = w->pSucc;
1039         tfree(w);
1040     }
1041 }
1042 
1043 
1044 
1045 /***********************************************************************
1046  *
1047  * Routines to display and modify user specified element properties.
1048  *
1049  ***********************************************************************/
1050 
1051 extern char *MenuPRPTY;
1052 
1053 #ifdef __STDC__
1054 static int  prptyKB(struct o*,struct prpty*);
1055 static void global_modify(void);
1056 static int  pType(int);
1057 #else
1058 static int  prptyKB();
1059 static void global_modify();
1060 static int  pType();
1061 #endif
1062 
1063 
1064 void
ShowProperties(LookedAhead)1065 ShowProperties(LookedAhead)
1066 
1067 int *LookedAhead;
1068 {
1069     struct prpty *PDesc;
1070     struct ks *SQDesc;
1071     char Types[4], *TypeIn;
1072     int Pret;
1073     int GotOne = False;
1074     char *s;
1075 
1076     Types[0]= CDSYMBOLCALL;
1077     Types[1]= CDWIRE;
1078     Types[2] = '\0';
1079 
1080     MenuSelect(MenuPRPTY);
1081     ConnectRecursive(Parameters.kpCellDesc);
1082 
1083     if (AreTypesInQ(Types))
1084         GotOne = True;
1085 top:
1086     if (!GotOne) {
1087         ShowPrompt(
1088 "Select object, at \">\" hit ENTER or a (add/repl), d (delete), n (break).");
1089         switch (PointLoop(LookedAhead)) {
1090             case PL_ESC:
1091             case PL_CMD:
1092             case PL_UND:
1093                 goto quit;
1094             case PL_PCW:
1095                 SelectTypes(Types);
1096                 if (Not AreTypesInQ(Types))
1097                     goto top;
1098         }
1099     }
1100     else {
1101         ShowPrompt(
1102 "Hit * for global, at \">\" hit a (add/repl), d (delete), n (next), ENTER.");
1103 
1104         switch (FBGetchar(ERASE)) {
1105             case ESCAPE:
1106                 goto quit;
1107             case '*':
1108                 global_modify();
1109                 goto quit;
1110             default:
1111                 SQComputeBB();
1112                 Parameters.kpEnableSelectQRedisplay = False;
1113                 EraseBox(&SelectQBB);
1114                 Redisplay(&SelectQBB);
1115                 break;
1116         }
1117     }
1118 
1119     for (SQDesc = SelectQHead; SQDesc; SQDesc = SQDesc->ksSucc) {
1120         if (SQDesc->ksPointer->oType != CDSYMBOLCALL &&
1121             SQDesc->ksPointer->oType != CDWIRE) continue;
1122         ShowCurrentObject(SQDesc->ksPointer,DISPLAY);
1123         PDesc = SQDesc->ksPointer->oPrptyList;
1124         if (PDesc == NULL) {
1125             ShowPrompt("Object has no properties.  > ");
1126             if (prptyKB(SQDesc->ksPointer,NULL) == 0) goto quit;
1127             continue;
1128         }
1129         for (; PDesc; PDesc = PDesc->prpty_Succ) {
1130             if (SQDesc->ksPointer->oType == CDWIRE) {
1131                 if (PDesc->prpty_Value == P_NODE) {
1132                     sprintf(TypeOut,"Wire Node Number (internal): %d   > ",
1133                         PDesc->prpty_Data->p_node.enode);
1134                     ShowPrompt(TypeOut);
1135                 }
1136                 if ((Pret = prptyKB(SQDesc->ksPointer,NULL)) == 0)
1137                     goto quit;
1138                 if (Pret == -1) goto next;
1139                 continue;
1140             }
1141 
1142             switch (PDesc->prpty_Value) {
1143                 case P_MODEL:
1144                     sprintf(TypeOut,"Model: %s   > ",
1145                         s = HYtostr((struct hprlist*)PDesc->prpty_Data));
1146                     ShowPrompt(TypeOut);
1147                     txfree(s);
1148                     if ((Pret = prptyKB(SQDesc->ksPointer,PDesc)) == 0)
1149                         goto quit;
1150                     if (Pret == -1) goto next;
1151                     break;
1152                 case P_VALUE:
1153                     sprintf(TypeOut,"Value: %s   > ",
1154                         s = HYtostr((struct hprlist*)PDesc->prpty_Data));
1155                     ShowPrompt(TypeOut);
1156                     txfree(s);
1157                     if ((Pret = prptyKB(SQDesc->ksPointer,PDesc)) == 0)
1158                         goto quit;
1159                     if (Pret == -1) goto next;
1160                     break;
1161                 case P_INITC:
1162                     sprintf(TypeOut,"Initial Conditions: %s   > ",
1163                         s = HYtostr((struct hprlist*)PDesc->prpty_Data));
1164                     ShowPrompt(TypeOut);
1165                     txfree(s);
1166                     if ((Pret = prptyKB(SQDesc->ksPointer,PDesc)) == 0)
1167                         goto quit;
1168                     if (Pret == -1) goto next;
1169                     break;
1170                 case P_OTHER:
1171                     sprintf(TypeOut,"External Property: %s   > ",
1172                         s = HYtostr((struct hprlist*)PDesc->prpty_Data));
1173                     ShowPrompt(TypeOut);
1174                     txfree(s);
1175                     if ((Pret = prptyKB(SQDesc->ksPointer,PDesc)) == 0)
1176                         goto quit;
1177                     if (Pret == -1) goto next;
1178                     break;
1179                 case P_NAME:
1180                     sprintf(TypeOut,"Device Name (internal): %s%d   > ",
1181                         PDesc->prpty_Data->p_name.name,
1182                         PDesc->prpty_Data->p_name.num);
1183                     ShowPrompt(TypeOut);
1184                     if ((Pret = prptyKB(SQDesc->ksPointer,NULL)) == 0)
1185                         goto quit;
1186                     if (Pret == -1) goto next;
1187                     break;
1188                 case P_NODE:
1189                     sprintf(TypeOut,"Node Number (internal): %d   > ",
1190                         PDesc->prpty_Data->p_node.enode);
1191                     ShowPrompt(TypeOut);
1192                     if ((Pret = prptyKB(SQDesc->ksPointer,NULL)) == 0)
1193                         goto quit;
1194                     if (Pret == -1) goto next;
1195                     break;
1196                 case P_BRANCH:
1197                     sprintf(TypeOut,"Branch (internal)  > ");
1198                     ShowPrompt(TypeOut);
1199                     if ((Pret = prptyKB(SQDesc->ksPointer,NULL)) == 0)
1200                         goto quit;
1201                     if (Pret == -1) goto next;
1202                     break;
1203             }
1204         }
1205 next:
1206         ShowCurrentObject(SQDesc->ksPointer,ERASE);
1207     }
1208     if (!GotOne) {
1209         SQComputeBB();
1210         SQDesel(Types);
1211         EraseBox(&SelectQBB);
1212         Redisplay(&SelectQBB);
1213         goto top;
1214     }
1215 quit:
1216     ShowCurrentObject(NULL,ERASE);
1217     if (!GotOne) {
1218         if (AreTypesInQ(Types)) {
1219             SQComputeBB();
1220             SQDesel(Types);
1221             EraseBox(&SelectQBB);
1222             Redisplay(&SelectQBB);
1223         }
1224     }
1225     else {
1226         Parameters.kpEnableSelectQRedisplay = True;
1227         SQShow();
1228     }
1229     ErasePrompt();
1230     MenuDeselect(MenuPRPTY);
1231 }
1232 
1233 
1234 static int
prptyKB(Pointer,PDesc)1235 prptyKB(Pointer,PDesc)
1236 
1237 /* return values: 0 (ESCAPE entered), -1 ('n' entered), 1 (otherwise) */
1238 struct o *Pointer;
1239 struct prpty *PDesc;
1240 {
1241     struct prpty *pd;
1242     struct hprlist *ht;
1243     char InChar;
1244     int Value,pv;
1245 
1246     if ((InChar = FBGetchar(DISPLAY)) == ESCAPE)
1247         return (0);
1248 
1249     if (InChar == 'n' || InChar == 'N')
1250         return (-1);
1251 
1252     if (InChar == '\0' || InChar == '\n' || InChar == '\r')
1253         goto quit;
1254 
1255     if  (Pointer->oType == CDWIRE) {
1256         ShowPromptAndWait("Can't modify wire properties.");
1257         goto quit;
1258     }
1259 
1260     if (InChar == 'a' || InChar == 'A') {
1261         loop {
1262             Value = 0;
1263             ShowPrompt(
1264     "Enter property type to add (Model m  Value v  Init Cnd i  Other o): ");
1265             if ((InChar = FBGetchar(DISPLAY)) == ESCAPE)
1266                 return (0);
1267             if (InChar == '\n' || InChar == '\r') {
1268                 if (PDesc != NULL)
1269                     Value = PDesc->prpty_Value;
1270                 else
1271                     continue;
1272             }
1273             else
1274                 Value = pType(InChar);
1275             pv = Value;
1276             switch (Value) {
1277                 case P_MODEL:
1278                     ShowPrompt("Model name? ");
1279                     break;
1280                 case P_VALUE:
1281                     ShowPrompt("Value? ");
1282                     break;
1283                 case P_INITC:
1284                     ShowPrompt("Initial Conditions? ");
1285                     break;
1286                 case P_OTHER:
1287                     strcpy(TypeOut,"Load from? (");
1288                     pv = 0;
1289                     for (pd = Pointer->oPrptyList; pd; pd = pd->prpty_Succ)
1290                         if (pd->prpty_Value == P_MODEL) {
1291                             strcat(TypeOut,"Model m");
1292                             pv = 1;
1293                             break;
1294                         }
1295                     for (pd = Pointer->oPrptyList; pd; pd = pd->prpty_Succ)
1296                         if (pd->prpty_Value == P_VALUE) {
1297                             if (pv) strcat(TypeOut,"  ");
1298                             strcat(TypeOut,"Value v");
1299                             pv = 1;
1300                             break;
1301                         }
1302                     for (pd = Pointer->oPrptyList; pd; pd = pd->prpty_Succ)
1303                         if (pd->prpty_Value == P_INITC) {
1304                             if (pv) strcat(TypeOut,"  ");
1305                             strcat(TypeOut,"Init Cnd i");
1306                             pv = 1;
1307                             break;
1308                         }
1309                     if (pv) {
1310                         strcat(TypeOut,"): ");
1311                         ShowPrompt(TypeOut);
1312                         if ((InChar = FBGetchar(DISPLAY)) == ESCAPE)
1313                             goto quit;
1314                         pv = pType(InChar);
1315                     }
1316                     else
1317                         pv = P_OTHER;
1318                     ShowPrompt("Property String? ");
1319                     Value = P_OTHER;
1320                     break;
1321             }
1322             break;
1323         }
1324         if (PDesc && PDesc->prpty_Value == pv)
1325             pd = PDesc;
1326         else {
1327             if (pv == P_OTHER)
1328                 pd = NULL;
1329             else
1330                 for (pd = Pointer->oPrptyList; pd; pd = pd->prpty_Succ)
1331                     if (pd->prpty_Value == pv) break;
1332         }
1333         if (pd)
1334             ht = FBHyEdit((struct hprlist*)pd->prpty_Data);
1335         else
1336             ht = FBHyEdit(NULL);
1337         if (ht == NULL)
1338             return (0);
1339 
1340         if (Value == P_OTHER) {
1341             ShowPrompt("Also store in? (Model m  Value v  Inid Cnd i): ");
1342             if ((InChar = FBGetchar(DISPLAY)) == ESCAPE)
1343                 goto quit;
1344             pv = pType(InChar);
1345             if (pv != P_OTHER) {
1346                 for (pd = Pointer->oPrptyList; pd; pd = pd->prpty_Succ)
1347                     if (pd->prpty_Value == pv) break;
1348                 if (pd) {
1349                     HYfree((struct hprlist*)pd->prpty_Data);
1350                     pd->prpty_Data = (union prp_data*)ht;
1351                 }
1352                 else {
1353                     pd = alloc(prpty);
1354                     pd->prpty_Value = pv;
1355                     pd->prpty_Data = (union prp_data*)ht;
1356                     pd->prpty_Succ = Pointer->oPrptyList;
1357                     Pointer->oPrptyList = pd;
1358                 }
1359                 ht = HYcopy(ht);
1360             }
1361         }
1362         if (PDesc && PDesc->prpty_Value == Value) {
1363             HYfree((struct hprlist*)PDesc->prpty_Data);
1364             PDesc->prpty_Data = (union prp_data*)ht;
1365         }
1366         else {
1367             for (pd = Pointer->oPrptyList; pd; pd = pd->prpty_Succ)
1368                 if (pd->prpty_Value == Value) break;
1369             if (pd && Value != P_OTHER) {
1370                 HYfree((struct hprlist*)pd->prpty_Data);
1371                 pd->prpty_Data = (union prp_data*)ht;
1372             }
1373             else {
1374                 pd = alloc(prpty);
1375                 pd->prpty_Value = Value;
1376                 pd->prpty_Data = (union prp_data*)ht;
1377                 pd->prpty_Succ = Pointer->oPrptyList;
1378                 Pointer->oPrptyList = pd;
1379             }
1380         }
1381         Parameters.kpModified = True;
1382     }
1383     else if (InChar == 'd' || InChar == 'D') {
1384         if (PDesc == NULL) {
1385             ShowPromptAndWait("No property to delete.");
1386             goto quit;
1387         }
1388         if (PDesc->prpty_Value >= 10) {
1389             ShowPromptAndWait("Can't delete internal properties.");
1390             goto quit;
1391         }
1392         pd = Pointer->oPrptyList;
1393         if (pd == PDesc)
1394             Pointer->oPrptyList = PDesc->prpty_Succ;
1395         else {
1396             /* must be in the list */
1397             for (; pd && pd->prpty_Succ != PDesc; pd = pd->prpty_Succ) ;
1398               pd->prpty_Succ = PDesc->prpty_Succ;
1399         }
1400         HYfree((struct hprlist*)PDesc->prpty_Data);
1401         tfree(PDesc);
1402         Parameters.kpModified = True;
1403         ShowPromptAndWait("Property deleted.");
1404     }
1405 quit:
1406     return (1);
1407 }
1408 
1409 
1410 static void
global_modify()1411 global_modify()
1412 
1413 {
1414     struct ks *SQDesc;
1415     struct prpty *pd;
1416     int val, InChar;
1417     char *name;
1418     struct hprlist *ht;
1419 
1420     ShowPrompt(
1421 "Enter property type to globally add/repl (Model m  Value v  Init Cnd i): ");
1422 top:
1423     if ((InChar = FBGetchar(DISPLAY)) == ESCAPE)
1424         return;
1425     val = pType(InChar);
1426     switch (val) {
1427         case P_MODEL:
1428             ShowPrompt("Model name? ");
1429             break;
1430         case P_VALUE:
1431             ShowPrompt("Value? ");
1432             break;
1433         case P_INITC:
1434             ShowPrompt("Initial Conditions? ");
1435             break;
1436         default:
1437             ShowPrompt("Bad entry, enter m,v,i or Esc to exit: ");
1438             goto top;
1439     }
1440     ht = FBHyEdit(NULL);
1441     if (ht == NULL)
1442         return;
1443 
1444     for (SQDesc = SelectQHead; SQDesc; SQDesc = SQDesc->ksSucc) {
1445         if (SQDesc->ksPointer->oType != CDSYMBOLCALL) continue;
1446         name = ((struct c *)SQDesc->ksPointer->oRep)->cMaster->mName;
1447         if (!IsCellInLib(name)) continue;
1448 
1449         for (pd = SQDesc->ksPointer->oPrptyList; pd; pd = pd->prpty_Succ)
1450             if (pd->prpty_Value == val) break;
1451         if (pd) {
1452             HYfree((struct hprlist*)pd->prpty_Data);
1453             pd->prpty_Data = (union prp_data*)HYcopy(ht);
1454         }
1455         else {
1456             pd = alloc(prpty);
1457             pd->prpty_Value = val;
1458             pd->prpty_Data = (union prp_data*)HYcopy(ht);
1459             pd->prpty_Succ = SQDesc->ksPointer->oPrptyList;
1460             SQDesc->ksPointer->oPrptyList = pd;
1461         }
1462     }
1463     HYfree(ht);
1464     Parameters.kpModified = True;
1465 }
1466 
1467 
1468 static int
pType(c)1469 pType(c)
1470 
1471 char c;
1472 {
1473     switch (c) {
1474         case '1':
1475         case 'm':
1476         case 'M':
1477             return (P_MODEL);
1478         case '2':
1479         case 'v':
1480         case 'V':
1481             return (P_VALUE);
1482         case '3':
1483         case 'i':
1484         case 'I':
1485             return (P_INITC);
1486         default:
1487             return (P_OTHER);
1488     }
1489 }
1490 
1491 
1492 /***********************************************************************
1493  *
1494  * Routines to create user specified subcircut connections.
1495  *
1496  ***********************************************************************/
1497 
1498 extern char *MenuSUBCT;
1499 extern char *MenuUNDO;
1500 extern char *MenuTERMS;
1501 
1502 #ifdef __STDC__
1503 static void insert_terminal(long,long);
1504 #else
1505 static void insert_terminal();
1506 #endif
1507 
1508 
1509 void
Subcircuit(LookedAhead)1510 Subcircuit(LookedAhead)
1511 
1512 /* Add node and name fields to cell descriptor */
1513 int *LookedAhead;
1514 {
1515     struct prpty *PDesc;
1516     int setone,count,int1,int2;
1517     long X,Y,OldX,OldY;
1518 
1519     MenuSelect(MenuSUBCT);
1520     ShowPrompt("Point to subcircuit connection points (ESC to exit).");
1521 
1522     DisplayTerminals(DISPLAY);
1523     loop {
1524         switch (PointLoop(LookedAhead)) {
1525             case PL_CMD:
1526                 if (!strcmp(Parameters.kpCommand,MenuSUBCT))
1527                     *LookedAhead = False;
1528             case PL_ESC:
1529                 goto quit;
1530             case PL_UND:
1531                 MenuSelect(MenuUNDO);
1532                 if (setone > 0) {
1533                     insert_terminal(OldX,OldY);
1534                     MenuDeselect(MenuUNDO);
1535                 }
1536                 else
1537                     goto quit;
1538                 break;
1539             case PL_PCW:
1540                 X = SCursor.kcX;
1541                 Y = SCursor.kcY;
1542                 if (!SelectNode(&X,&Y)) continue;
1543                 insert_terminal(X,Y);
1544                 Parameters.kpModified = True;
1545                 setone = True;
1546                 OldX = X;
1547                 OldY = Y;
1548         }
1549     }
1550 quit:
1551 
1552     /* The first (or earliest) terminal assigned is the
1553      * reference terminal.  This is last on the list.
1554      */
1555     count = 0;
1556     PDesc = Parameters.kpCellDesc->sPrptyList;
1557     for (; PDesc; PDesc = PDesc->prpty_Succ) {
1558         if (PDesc->prpty_Value != P_NODE) continue;
1559         count++;
1560     }
1561     if (count) {
1562         PDesc = Parameters.kpCellDesc->sPrptyList;
1563         for (; PDesc; PDesc = PDesc->prpty_Succ) {
1564             if (PDesc->prpty_Value != P_NODE) continue;
1565             count--;
1566             PDesc->prpty_Data->p_node.enode = -1;
1567             PDesc->prpty_Data->p_node.inode = count;
1568             ShowMarker(ERASE,0,PDesc->prpty_Data->p_node.x,
1569                 PDesc->prpty_Data->p_node.y,100,MARK_CROSS,0);
1570         }
1571         /* subckts have 3 entries in name field */
1572         PDesc = Parameters.kpCellDesc->sPrptyList;
1573         for (; PDesc; PDesc = PDesc->prpty_Succ)
1574             if (PDesc->prpty_Value == P_NAME) break;
1575         if (!PDesc) {
1576             sprintf(TypeOut,"X 0 %s",Parameters.kpCellName);
1577             if (Not CDAddProperty(Parameters.kpCellDesc,(struct o *)NULL,
1578                 P_NAME,TypeOut))
1579                 MallocFailed();
1580         }
1581     }
1582 
1583     MenuDeselect(MenuUNDO);
1584     MenuDeselect(MenuSUBCT);
1585     ErasePrompt();
1586 }
1587 
1588 
1589 static void
insert_terminal(X,Y)1590 insert_terminal(X,Y)
1591 
1592 /* If terminal already assigned, delete assignment.
1593  * Otherwise, add new terminal.
1594  */
1595 long X,Y;
1596 {
1597     struct prpty *PDesc;
1598     struct prpty *PPrev = NULL;
1599 
1600     PDesc = Parameters.kpCellDesc->sPrptyList;
1601     for (; PDesc; PPrev = PDesc,PDesc = PDesc->prpty_Succ) {
1602         if (PDesc->prpty_Value != P_NODE) continue;
1603         if (X == PDesc->prpty_Data->p_node.x &&
1604             Y == PDesc->prpty_Data->p_node.y) {
1605             if (PPrev)
1606                 PPrev->prpty_Succ = PDesc->prpty_Succ;
1607             else
1608                 Parameters.kpCellDesc->sPrptyList = PDesc->prpty_Succ;
1609             ShowMarker(ERASE,0,X,Y,100,MARK_CROSS,0);
1610             free(PDesc->prpty_Data);
1611             free(PDesc);
1612             return;
1613         }
1614     }
1615     sprintf(TypeOut,"-1 0 %ld %ld",X,Y);
1616     if (Not CDAddProperty(Parameters.kpCellDesc,(struct o *)NULL,
1617         P_NODE,TypeOut))
1618         MallocFailed();
1619     ShowMarker(DISPLAY,HighlightingColor,X,Y,100,MARK_CROSS,0);
1620 }
1621 
1622 
1623 int
SelectNode(Xo,Yo)1624 SelectNode(Xo,Yo)
1625 
1626 /* Do the coordinates match a circuit node?  It yes, return the exact node
1627  * coordinates.
1628  */
1629 long *Xo,*Yo;
1630 {
1631     struct ka AOI;
1632     struct g *GenDesc;
1633     struct o *Pointer;
1634     struct p *Path;
1635     struct prpty *PDesc;
1636     int Layer,Delta;
1637     long X,Y,Width,*xy;
1638 
1639 
1640     if (SCursor.kcInFine == True)
1641         Delta = 5.0/View->kvFineRatio;
1642     else
1643         Delta = 5.0/View->kvCoarseRatio;
1644 
1645     AOI.kaLeft = *Xo - Delta;
1646     AOI.kaRight = *Xo + Delta;
1647     AOI.kaBottom = *Yo - Delta;
1648     AOI.kaTop = *Yo + Delta;
1649 
1650     /* first check subcircuit terminals */
1651     PDesc = Parameters.kpCellDesc->sPrptyList;
1652     for (; PDesc; PDesc = PDesc->prpty_Succ) {
1653         if (PDesc->prpty_Value != P_NODE) continue;
1654         X = PDesc->prpty_Data->p_node.x;
1655         Y = PDesc->prpty_Data->p_node.y;
1656 
1657         if (InBox(X,Y,&AOI)) {
1658             *Xo = X;
1659             *Yo = Y;
1660             return (True);
1661         }
1662     }
1663 
1664     /* next check the devices */
1665     if (Not CDInitGen(Parameters.kpCellDesc,0,AOI.kaLeft,AOI.kaBottom,
1666         AOI.kaRight,AOI.kaTop,&GenDesc)) MallocFailed();
1667     loop {
1668         CDGen(Parameters.kpCellDesc,GenDesc,&Pointer);
1669         if (Pointer == NULL) break;
1670         if (Pointer->oInfo == SQ_GONE) continue;
1671 
1672         PDesc = Pointer->oPrptyList;
1673         for (; PDesc; PDesc = PDesc->prpty_Succ) {
1674             if (PDesc->prpty_Value != P_NODE) continue;
1675             X = PDesc->prpty_Data->p_node.x;
1676             Y = PDesc->prpty_Data->p_node.y;
1677 
1678             if (InBox(X,Y,&AOI)) {
1679                 tfree(GenDesc);
1680                 *Xo = X;
1681                 *Yo = Y;
1682                 return (True);
1683             }
1684         }
1685     }
1686 
1687     /* now check wires */
1688     if (Not CDInitGen(Parameters.kpCellDesc,1,AOI.kaLeft,AOI.kaBottom,
1689         AOI.kaRight,AOI.kaTop,&GenDesc)) MallocFailed();
1690     loop {
1691         CDGen(Parameters.kpCellDesc,GenDesc,&Pointer);
1692         if (Pointer == NULL) break;
1693         if (Pointer->oInfo == SQ_GONE) continue;
1694         if (Pointer->oType != CDWIRE) continue;
1695         CDWire(Pointer,&Layer,&Width,&Path);
1696 
1697         for (; Path; Path = Path->pSucc)
1698             if (InBox(Path->pX,Path->pY,&AOI)) {
1699                 tfree(GenDesc);
1700                 *Xo = Path->pX;
1701                 *Yo = Path->pY;
1702                 return (True);
1703             }
1704     }
1705     return (False);
1706 }
1707 
1708 
1709 void
ShowTerminals()1710 ShowTerminals()
1711 
1712 /* Display the terminal locations of the current cell */
1713 {
1714 
1715     if (Parameters.kpShowTerminals) {
1716         MenuDeselect(MenuTERMS);
1717         Parameters.kpShowTerminals = False;
1718         DisplayTerminals(ERASE);
1719     }
1720     else {
1721         MenuSelect(MenuTERMS);
1722         Parameters.kpShowTerminals = True;
1723         DisplayTerminals(DISPLAY);
1724     }
1725 }
1726 
1727 
1728 void
DisplayTerminals(DisplayOrErase)1729 DisplayTerminals(DisplayOrErase)
1730 
1731 int DisplayOrErase;
1732 {
1733     struct prpty *PDesc;
1734 
1735     PDesc = Parameters.kpCellDesc->sPrptyList;
1736     for (; PDesc; PDesc = PDesc->prpty_Succ) {
1737         if (PDesc->prpty_Value != P_NODE) continue;
1738         ShowMarker(DisplayOrErase,HighlightingColor,
1739             PDesc->prpty_Data->p_node.x,PDesc->prpty_Data->p_node.y,
1740             100,MARK_CROSS,0);
1741     }
1742 }
1743 
1744 
1745 
1746 /***********************************************************************
1747  *
1748  * Routines to update subcircuit connection coordinates if the
1749  * underlying element is moved.
1750  *
1751  ***********************************************************************/
1752 
1753 #ifdef __STDC__
1754 static int  device_node(long,long);
1755 #else
1756 static int  device_node();
1757 #endif
1758 
1759 void
TransformReferences(Pointer)1760 TransformReferences(Pointer)
1761 
1762 /* look through the cell reference points.  If any correspond to an
1763  * element that was just moved, transform the reference. Save the old
1764  * union in the Info field.
1765  */
1766 struct o *Pointer;
1767 {
1768     struct ka BB;
1769     struct prpty *PDesc;
1770     struct p *Path;
1771     int Layer;
1772     long X,Y,Width,X1,Y1,X2,Y2;
1773     long *InPath();
1774 
1775     CDBB(Parameters.kpCellDesc,Pointer,
1776         &BB.kaLeft,&BB.kaBottom,&BB.kaRight,&BB.kaTop);
1777 
1778     PDesc = Parameters.kpCellDesc->sPrptyList;
1779     for (; PDesc; PDesc = PDesc->prpty_Succ) {
1780         switch (PDesc->prpty_Value) {
1781             case P_NODE:
1782                 X = PDesc->prpty_Data->p_node.x;
1783                 Y = PDesc->prpty_Data->p_node.y;
1784                 if (!InBox(X,Y,&BB)) continue;
1785                 switch (Pointer->oType) {
1786                     case CDWIRE:
1787                         CDWire(Pointer,&Layer,&Width,&Path);
1788                         if (InPath(20,Path,X,Y) == NULL) continue;
1789                         if (device_node(X,Y)) continue;
1790                     case CDSYMBOLCALL:
1791                         TPoint(&X,&Y);
1792                         PDesc->prpty_Info = (char*)PDesc->prpty_Data;
1793                         PDesc->prpty_Data = umalloc(prp_data);
1794                         PDesc->prpty_Data->p_node.x = X;
1795                         PDesc->prpty_Data->p_node.y = Y;
1796                         PDesc->prpty_Data->p_node.enode =
1797                           ((union prp_data*)PDesc->prpty_Info)->p_node.enode;
1798                         PDesc->prpty_Data->p_node.inode =
1799                           ((union prp_data*)PDesc->prpty_Info)->p_node.inode;
1800                 }
1801                 continue;
1802             case P_MUT:
1803                 /* get the transformed lower left corner */
1804                 if (Pointer->oType != CDSYMBOLCALL) continue;
1805                 X = PDesc->prpty_Data->p_mut.x1;
1806                 Y = PDesc->prpty_Data->p_mut.y1;
1807                 X1 = PDesc->prpty_Data->p_mut.x2;
1808                 Y1 = PDesc->prpty_Data->p_mut.y2;
1809                 if (X == BB.kaLeft && Y == BB.kaBottom) {
1810                     X2 = BB.kaRight;
1811                     Y2 = BB.kaTop;
1812                     TPoint(&X,&Y);
1813                     TPoint(&X2,&Y2);
1814                     if (X > X2) X = X2;
1815                     if (Y > Y2) Y = Y2;
1816                 }
1817                 else if (X1 == BB.kaLeft && Y1 == BB.kaBottom) {
1818                     X2 = BB.kaRight;
1819                     Y2 = BB.kaTop;
1820                     TPoint(&X1,&Y1);
1821                     TPoint(&X2,&Y2);
1822                     if (X1 > X2) X1 = X2;
1823                     if (Y1 > Y2) Y1 = Y2;
1824                 }
1825                 else
1826                     continue;
1827                 PDesc->prpty_Info = (char*)PDesc->prpty_Data;
1828                 PDesc->prpty_Data = umalloc(prp_data);
1829                 PDesc->prpty_Data->p_mut.x1 = X;
1830                 PDesc->prpty_Data->p_mut.y1 = Y;
1831                 PDesc->prpty_Data->p_mut.x2 = X1;
1832                 PDesc->prpty_Data->p_mut.y2 = Y1;
1833                 PDesc->prpty_Data->p_mut.coeff =
1834                     ((union prp_data*)PDesc->prpty_Info)->p_mut.coeff;
1835                 continue;
1836         }
1837     }
1838 }
1839 
1840 
1841 void
TransformReferencePoint(Pointer,RefX,RefY)1842 TransformReferencePoint(Pointer,RefX,RefY)
1843 
1844 /* look through the cell reference points.  If any correspond to a
1845  * wire vertex that was just moved, transform the reference.
1846  */
1847 struct o *Pointer;
1848 long RefX,RefY;
1849 {
1850     struct prpty *PDesc;
1851     long X,Y;
1852 
1853     if (Pointer->oType != CDWIRE) return;
1854 
1855     PDesc = Parameters.kpCellDesc->sPrptyList;
1856     for (; PDesc; PDesc = PDesc->prpty_Succ) {
1857         if (PDesc->prpty_Value != P_NODE) continue;
1858         X = PDesc->prpty_Data->p_node.x;
1859         Y = PDesc->prpty_Data->p_node.y;
1860         if (RefX == X && RefY == Y) {
1861             TPoint(&X,&Y);
1862             PDesc->prpty_Info = (char*)PDesc->prpty_Data;
1863             PDesc->prpty_Data = umalloc(prp_data);
1864             PDesc->prpty_Data->p_node.x = X;
1865             PDesc->prpty_Data->p_node.y = Y;
1866             PDesc->prpty_Data->p_node.enode =
1867               ((union prp_data*)PDesc->prpty_Info)->p_node.enode;
1868             PDesc->prpty_Data->p_node.inode =
1869               ((union prp_data*)PDesc->prpty_Info)->p_node.inode;
1870         }
1871     }
1872 }
1873 
1874 
1875 void
UndoReferenceTransform()1876 UndoReferenceTransform()
1877 
1878 {
1879     struct prpty *PDesc;
1880 
1881     PDesc = Parameters.kpCellDesc->sPrptyList;
1882     for (; PDesc; PDesc = PDesc->prpty_Succ) {
1883         if (PDesc->prpty_Value != P_NODE) continue;
1884         if (PDesc->prpty_Info == NULL) continue;
1885         free(PDesc->prpty_Data);
1886         PDesc->prpty_Data = (union prp_data*)PDesc->prpty_Info;
1887         PDesc->prpty_Info = NULL;
1888     }
1889 }
1890 
1891 
1892 void
ClearReferenceUndoFlags()1893 ClearReferenceUndoFlags()
1894 
1895 {
1896     struct prpty *PDesc;
1897 
1898     PDesc = Parameters.kpCellDesc->sPrptyList;
1899     for (; PDesc; PDesc = PDesc->prpty_Succ) {
1900         if (PDesc->prpty_Value != P_NODE) continue;
1901         if (PDesc->prpty_Info == NULL) continue;
1902         free(PDesc->prpty_Info);
1903         PDesc->prpty_Info = NULL;
1904     }
1905 }
1906 
1907 
1908 static int
device_node(X,Y)1909 device_node(X,Y)
1910 
1911 /* return True if X,Y are coordinates of a device or subcircuit terminal */
1912 long X,Y;
1913 {
1914     struct g *GenDesc;
1915     struct prpty *PDesc;
1916     struct o *Pointer;
1917     int Info;
1918 
1919     if (Not CDInitGen(Parameters.kpCellDesc,0,X,Y,X,Y,&GenDesc))
1920         MallocFailed();
1921 
1922     loop {
1923 
1924         CDGen(Parameters.kpCellDesc,GenDesc,&Pointer);
1925         if (Pointer == NULL) break;
1926         if (Pointer->oInfo == SQ_GONE) continue;
1927 
1928         PDesc = Pointer->oPrptyList;
1929         for (; PDesc; PDesc = PDesc->prpty_Succ) {
1930             if (PDesc->prpty_Value != P_NODE) continue;
1931             if (X == PDesc->prpty_Data->p_node.x &&
1932                 Y == PDesc->prpty_Data->p_node.y) {
1933                 tfree(GenDesc);
1934                 return (True);
1935             }
1936         }
1937     }
1938     return (False);
1939 }
1940 
1941