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