1 /****************************************************************************
2     Copyright (C) 1987-2015 by Jeffery P. Hansen
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License along
15     with this program; if not, write to the Free Software Foundation, Inc.,
16     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 
18     Last edit by hansen on Sat Feb 21 16:44:18 2009
19 ****************************************************************************/
20 
21 #ifdef __cplusplus
22 #include <cstdlib>
23 #include <cstdio>
24 #include <cstring>
25 #include <cassert>
26 #else
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <assert.h>
31 #endif
32 
33 #include <ctype.h>
34 
35 #include "tkgate.h"
36 #include "print.h"
37 
38 void init_and();
39 void init_or();
40 void init_xor();
41 void init_buffer();
42 void init_bufif();
43 void init_adder();
44 void init_mult();
45 void init_divide();
46 void init_register();
47 void init_ff();
48 void init_clock();
49 void init_switch();
50 void init_ground();
51 void init_vdd();
52 void init_in();
53 void init_out();
54 void init_inout();
55 void init_dip();
56 void init_mux();
57 void init_demux();
58 void init_decoder();
59 void init_tap();
60 void init_concat();
61 void init_lshift();
62 void init_rshift();
63 void init_arshift();
64 void init_roll();
65 void init_joint();
66 void init_block();
67 void init_symblock();
68 void init_ram();
69 void init_rom();
70 void init_nmos();
71 void init_pmos();
72 void init_pullup();
73 void init_pulldown();
74 void init_comment();
75 void init_frame();
76 void init_led();
77 void init_jkff();
78 void init_script();
79 
80 MakeMenuData *makeMenuData = 0;
81 
82 extern NHash *GateIdxHash;
83 
84 extern int Marked;
85 
86 GWire *wire_root(GWireNode *n,int size);
87 
seekOption(const char * opt,const char ** optList,int nOpts)88 const char *seekOption(const char *opt,const char **optList,int nOpts)
89 {
90   int i;
91 
92   for (i = 0;i < nOpts;i++)
93     if (strcmp(opt,optList[i]) == 0 && i+1 < nOpts)
94       return optList[i+1];
95   return 0;
96 }
97 
98 
99 /*
100    Build the standard pin connection portion of a gate description
101 */
102 #if 0
103 void buildStdPins(char *p,GSimState *ss, GCElement *g)
104 {
105   struct wire *w;
106   int i;
107   int N = GCElement_numPads(g);
108 
109   for (i = 0;i < N;i++) {
110     strcpy(p," ( "); p += 3;
111     for (w = g->wires[i];w;w = w->next) {
112       sprintf(p,"%s%d ",w->invert ? "~" : "",simnet_id(ss,w->driver));
113       p += strlen(p);
114     }
115     strcpy(p," ) "); p += 3;
116   }
117 }
118 #endif
119 
Generic_Make(EditState ** es,GModuleDef * PM,int GType,int x,int y,int r,const char * Name,int noWires,const char ** options,int nOptions)120 GCElement *Generic_Make(EditState **es,GModuleDef *PM,int GType,
121 			int x,int y,int r,const char *Name,int noWires,const char **options,int nOptions)
122 {
123   int i,j;
124   GCElement *g;
125   const char *Invert,*Pins;
126   Invert = seekOption("-invert",options,nOptions);
127   Pins = seekOption("-pins",options,nOptions);
128 
129   if (es && *es) {
130     if (!(*es)->env->m_isSpecial)
131       SetModified(MF_NET|MF_GATE);
132   }
133 
134   g = gate_new(x,y,r,GType);
135   ob_touch(g);
136   gate_setName(g,Name,PM);
137   gate_add(PM,g);
138 
139   if (!noWires) {
140     int N = GCElement_numPads(g);
141     for (i = 0;i < N;i++) {
142       int Num = 0;
143 
144       if (Pins) {
145 	char buf[STRMAX];
146 	int N;
147 	if (sscanf(Pins,"%[^=]=%d",buf,&N) == 2 && strcmp(buf,g->typeinfo->Pad[i].name) == 0)
148 	  Num = N;
149       }
150       if (!Num)
151 	Num = g->typeinfo->Pad[i].num;
152 
153       for (j = 0;j < Num;j++) {
154 	if (Invert && strcmp(Invert,g->typeinfo->Pad[i].name) == 0)
155 	  wire_addToGate(g,i,PM,1);
156 	else
157 	  wire_addToGate(g,i,PM,0);
158       }
159     }
160   }
161   return g;
162 }
163 
Generic_Init(GCElement * g)164 void Generic_Init(GCElement*g)
165 {
166 }
167 
Generic_Delete(GCElement * g,GModuleDef * M,int drawp)168 void Generic_Delete(GCElement *g,GModuleDef *M,int drawp)
169 {
170   if (drawp) gate_draw(g,GD_NOWIRE);
171   gate_cutOffWires(g,M,drawp);
172   if (M)     gate_remove(M,g);
173 }
174 
Generic_GetExtents(GCElement * g,TargetDev_e target,int * minx,int * miny,int * maxx,int * maxy,int * bd)175 void Generic_GetExtents(GCElement *g,TargetDev_e target,int *minx,int *miny,int *maxx,int *maxy,int *bd)
176 {
177   GGateInfo *gi = g->typeinfo;
178   iconDimensions *id = 0;
179 
180   if (bd) *bd = 10;
181 
182   if (!gi->dim) {
183     *minx = g->xpos - 5;
184     *miny = g->ypos - 5;
185     *maxx = g->xpos + 5;
186     *maxy = g->ypos + 5;
187     logError(ERL_ERROR,"Generic_GetExtents called on gate with no dimensions.");
188     return;
189   }
190 
191   if (gi->Flags.CanRot && !gi->Flags.single_icon)
192     id = &gi->dim[g->orient];
193   else
194     id = &gi->dim[0];
195 
196   *minx = g->xpos - id->ox;
197   *miny = g->ypos - id->oy;
198   *maxx = g->xpos - id->ox + id->w;
199   *maxy = g->ypos - id->oy + id->h;
200 }
201 
Generic_Draw(GCElement * g,int md)202 void Generic_Draw(GCElement *g,int md)
203 {
204   mk_gate(g->xpos,g->ypos,g->typeinfo,g->orient,g->selected);
205   gate_drawWires(g,md);
206 
207   if (g->ename && g->show_name)
208     gate_drawgatename(g,g->ename);
209 }
210 
Generic_HitDistance(GCElement * g,int x,int y)211 int Generic_HitDistance(GCElement *g,int x,int y)
212 {
213   int minx,miny,maxx,maxy;
214   int d;
215 
216   if (g->typeinfo->GetExtents)
217     (*g->typeinfo->GetExtents)(g,TD_X11,&minx,&miny,&maxx,&maxy,0);
218   else
219     Generic_GetExtents(g,TD_X11,&minx,&miny,&maxx,&maxy,0);
220 
221   d = distance(x,y,g->xpos,g->ypos);
222   if (x >= minx  && x <= maxx && y >= miny && y <= maxy && d > GATERANGE)
223     d = GATERANGE-1;
224   return d;
225 }
226 
Generic_Move(GCElement * g,int x,int y)227 void Generic_Move(GCElement *g,int x,int y)
228 {
229   int i;
230   struct wire *w;
231   int N = GCElement_numPads(g);
232 
233   ob_touch(g);
234   g->xpos += x;
235   g->ypos += y;
236   for (i = 0;i < N;i++)
237     for (w = g->wires[i];w;w = w->next)
238       wire_move(w->nodes,x,y,FULL);
239 }
240 
replicateGateWires(GCElement * ng,GCElement * g,GModuleDef * M)241 static void replicateGateWires(GCElement *ng,GCElement *g,GModuleDef *M)
242 {
243   int i;
244   GWire *w;
245   int N = GCElement_numPads(g);
246 
247   ob_touch(ng);
248 
249   /*
250    * Clear an existing wires on ng
251    */
252   for (i = 0;i < N;i++)
253     ng->wires[i] = 0;
254 
255   for (i = 0;i < N;i++) {
256     for (w = g->wires[i];w;w = w->next) {
257       GWire *nw,*nw2;
258 
259       wire_new(M,&nw,&nw2);
260       ob_touch(nw);
261 
262       ng->wires[i] = wire_append(ng->wires[i],nw);
263       nw->gate = ng;
264 
265       ob_touch(nw->net);
266       nw->net->n_nbits = w->net->n_nbits;
267       nw->orient = w->orient;
268       nw->offset.num = w->offset.num;
269       nw->offset.den = w->offset.den;
270       nw->invert = w->invert;
271 
272       ob_touch(nw->nodes);
273       nw->nodes->x = w->nodes->x + (ng->xpos-g->xpos);
274       nw->nodes->y = w->nodes->y + (ng->ypos-g->ypos);
275 
276       ob_touch(nw->nodes->out);
277       nw->nodes->out->x = nw->nodes->x;
278       nw->nodes->out->y = nw->nodes->y;
279 
280       if (w->name) nw->name = ob_strdup(w->name);
281 
282       switch (nw->orient) {
283       case D_UP :
284 	nw->nodes->out->y -= TKGATE_STUBLEN;
285 	break;
286       case D_DOWN :
287 	nw->nodes->out->y += TKGATE_STUBLEN;
288 	break;
289       case D_LEFT :
290 	nw->nodes->out->x -= TKGATE_STUBLEN;
291 	break;
292       case D_RIGHT :
293 	nw->nodes->out->x += TKGATE_STUBLEN;
294 	break;
295       }
296     }
297   }
298 
299   for (i = 0;i < N;i++) {
300     for (w = ng->wires[i];w;w = w->next) {
301       wire_finalizeNet(w);
302     }
303   }
304 }
305 
Generic_Copy(GModuleDef * M,GCElement * g,int x,int y,unsigned flags)306 GCElement *Generic_Copy(GModuleDef *M,GCElement *g,int x,int y,unsigned flags)
307 {
308   GCElement *ng;
309   char *name = 0;
310   int i;
311 
312   ng = gate_new(x,y,g->orient,g->typeinfo->code);
313   ob_touch(ng);
314 
315   if (GModuleDef_findGate(M,g->ename))
316     name = 0;
317   else
318     name = g->ename;
319   gate_setName(ng,name,M);
320   ng->show_name = g->show_name;
321 
322   ng->tech = ob_strdup(g->tech);
323   ng->cust_delay = g->cust_delay;
324   ob_touch(ng->delays);
325   for (i = 0;g->typeinfo->delayNames[i];i++)
326     ng->delays[i] = g->delays[i];
327 
328   if (!(flags & REP_NOWIRES))
329     replicateGateWires(ng,g,M);
330 
331   return ng;
332 }
333 
Generic_AddInput(EditState * es,GCElement * g)334 void Generic_AddInput(EditState *es,GCElement *g)
335 {
336   int i;
337   int N = GCElement_numPads(g);
338 
339   for (i = 0;i < N;i++)
340     if (GCElement_getPadDir(g,i) == IN && GCElement_getPadCanAdd(g,i))
341       break;
342 
343   if (i == N)
344     return;
345 
346   if (es) SetModified(MF_GATE|MF_NET);
347 
348   gate_draw(g,GD_NORMAL);
349 
350   wire_addToGate(g,i,es->env,0);
351   gate_draw(g,GD_NORMAL);
352 }
353 
Generic_AddOutput(EditState * es,GCElement * g)354 void Generic_AddOutput(EditState *es,GCElement *g)
355 {
356   int i;
357   int N = GCElement_numPads(g);
358 
359   for (i = 0;i < N;i++)
360     if (GCElement_getPadDir(g,i) == OUT && GCElement_getPadCanAdd(g,i))
361       break;
362 
363   if (i == N)
364     return;
365 
366   if (es) SetModified(MF_GATE|MF_NET);
367 
368   gate_draw(g,GD_NORMAL);
369 
370   wire_addToGate(g,i,es->env,0);
371   gate_draw(g,GD_NORMAL);
372 }
373 
Generic_RemovePort(EditState * es,GCElement * g,GWire * dw)374 void Generic_RemovePort(EditState *es,GCElement *g,GWire *dw)
375 {
376   int i,j;
377   GWire *w;
378   int isfound = 0;
379   int N = GCElement_numPads(g);
380 
381   ob_touch(g);
382 
383   for (i = 0;i < N && !isfound;i++) {
384     if (g->wires[i] == dw) {
385       g->wires[i] = dw->next;
386       isfound = 1;
387     } else {
388       for (w = g->wires[i], j = 0;w && w->next;w = w->next, j++) {
389 	if (w->next == dw) {
390 	  ob_touch(w);
391 	  w->next = dw->next;
392 	  isfound = 1;
393 	  break;
394 	}
395       }
396     }
397   }
398 
399   if (!isfound) return;
400 
401   /*
402    * Finish up wire destruction.
403    */
404   ob_touch(dw);
405   dw->gate = 0;
406   wire_setPadSpacing(g,i);
407   wire_nuke(dw,0,TkGate.circuit->es->env);
408 }
409 
Err_RemovePort(EditState * es,GCElement * g,GWire * w)410 void Err_RemovePort(EditState *es,GCElement *g,GWire *w)
411 {
412 }
413 
Err_AddInput(EditState * es,GCElement * g)414 void Err_AddInput(EditState *es,GCElement *g)
415 {
416   message(1,msgLookup("err.badinadd"));			/* Can't add any more inputs to selected gate. */
417 }
418 
Err_AddOutput(EditState * es,GCElement * g)419 void Err_AddOutput(EditState *es,GCElement *g)
420 {
421   message(1,msgLookup("err.badoutadd"));		/* Can't add any more outputs to selected gate. */
422 }
423 
Err_AddInOut(EditState * es,GCElement * g)424 void Err_AddInOut(EditState *es,GCElement *g)
425 {
426   message(1,msgLookup("err.badinoutadd"));		/* Can't add any more inout pins to selected gate. */
427 }
428 
Err_ChangePin(EditState * es,GCElement * g)429 void Err_ChangePin(EditState *es,GCElement *g)
430 {
431   message(1,msgLookup("err.badpinchg"));		/* Can't change pin types on selected gate. */
432 }
433 
Generic_DrawGateLabel(GPrint * P,GCElement * g,const char * text)434 void Generic_DrawGateLabel(GPrint *P,GCElement *g,const char *text)
435 {
436   HtmlFont font[1];
437   GateFont gateFont = {FF_HELVETICA,FP_ROMAN};
438 
439   PSDrawText(P,HtmlFont_init(font,gateFont,8),
440 	     g->xpos+g->typeinfo->lpos[g->orient].x,
441 	     g->ypos+g->typeinfo->lpos[g->orient].y,
442 	     text,g->typeinfo->lpos[g->orient].just);
443 }
444 
Generic_PSLabels(GPrint * P,GCElement * g)445 void Generic_PSLabels(GPrint *P,GCElement *g)
446 {
447   if (g->show_name && g->ename)
448     Generic_DrawGateLabel(P,g,g->ename);
449 }
450 
Generic_PSWrite(GPrint * P,GModLayout * L,GCElement * g)451 void Generic_PSWrite(GPrint *P,GModLayout *L,GCElement *g)
452 {
453   Generic_PSLabels(P,g);
454 
455   fprintf(P->p_f,"%d %d %d %s\n",g->xpos,g->ypos,-g->orient*90,
456 	  g->typeinfo->psprint);
457 }
458 
Generic_editPropsDLWires(GCElement * g)459 void Generic_editPropsDLWires(GCElement *g)
460 {
461   Tcl_Interp *tcl = TkGate.tcl;
462   int N = GCElement_numPads(g);
463   char buf[8*STRMAX],*p;
464   GWire *w;
465   int i,j;
466 
467   p = buf;
468   *p = 0;
469   for (i = 0;i < N;i++) {
470     char *dir = 0;
471     switch (GCElement_getPadDir(g,i)) {
472     case IN  : dir = "in"; break;
473     case OUT : dir = "out"; break;
474     case TRI : dir = "bidir"; break;
475     }
476     for (w = g->wires[i], j = 0;w;w = w->next, j++) {
477       char port[STRMAX];
478 
479       /*
480        * Special hack to hide the "I" port on a wire-tap element.
481        */
482       if (GCElement_getType(g) == GC_TAP && i == 1) continue;
483 
484       if (GCElement_getPadCanAdd(g,i))
485 	sprintf(port,"%s%d",GCElement_getPadName(g,i),j);
486       else
487 	strcpy(port,GCElement_getPadName(g,i));
488       p += sprintf(p," { \"%s\"",w->net->n_signame ? w->net->n_signame : "*unnamed*");
489       if (w->name)
490 	p += sprintf(p," \"%s\"",w->name);
491       else
492 	p += sprintf(p," \"%s\"",port);
493       p += sprintf(p," \"%s\" %d ",dir,w->net->n_nbits);
494 
495       if (w->name) {
496 	switch (*port) {
497 	case 'T' : p += sprintf(p,"top"); break;
498 	case 'B' : p += sprintf(p,"bottom"); break;
499 	case 'L' : p += sprintf(p,"left"); break;
500 	case 'R' : p += sprintf(p,"right"); break;
501 	}
502       }
503 
504       p += sprintf(p,"}");
505     }
506   }
507   *p = 0;
508 
509   Tcl_SetVar(tcl,"edgat_wires",buf,TCL_GLOBAL_ONLY);
510 }
511 
512 /*
513    Process any wire operations on 'g'.  The wop list is a list of
514    elements having one of the forms:
515 
516       {add I}			Add a wire to port group I
517       {delete I2}		Delete 2nd wire of port group I
518       {edit Pold w Pnew io n}	Edit port.  Pold is old port name, w is signal name,
519       				Pnew is new port name, io is the I/O type,
520 				and n is the number of bits.
521 */
Generic_editPropsULWires(GCElement * g)522 void Generic_editPropsULWires(GCElement *g)
523 {
524   Tcl_Interp *tcl = TkGate.tcl;
525   char port[128],name[STRMAX],_newport[128],dir[128];
526   const char *p;
527   int bits;
528   int n,i,j;
529   const char *wops = Tcl_GetVar(tcl,"edgat_wops",TCL_GLOBAL_ONLY);
530 
531   if (g->typeinfo->code == GC_TAP) return;	/* Can't edit tap ports */
532 
533   ob_touch(g);
534 
535   SetModified(MF_NET|MF_GATE);
536   for (p = wops+strcspn(wops,"{");*p;p += strcspn(p,"{")) {
537     if (sscanf(p,"{add %[A-Za-z]",port) == 1) {
538       GGateInfo *gi = g->typeinfo;
539       int N = GCElement_numPads(g);
540       int pdir = ANY;
541 
542       for (i = 0;i < N;i++)
543 	if (strcmp(gi->Pad[i].name,port) == 0) {
544 	  pdir = gi->Pad[i].iotype;
545 	  break;
546 	}
547 
548       switch (pdir) {
549       case TRI :
550 	(*g->typeinfo->AddTri)(TkGate.circuit->es,g);
551 	break;
552       case OUT :
553 	(*g->typeinfo->AddOutput)(TkGate.circuit->es,g);
554 	break;
555       case IN :
556       default :
557 	(*g->typeinfo->AddInput)(TkGate.circuit->es,g);
558 	break;
559       }
560     } else if (sscanf(p,"{delete %[A-Za-z]%d",port,&n) == 2) {
561       int N = GCElement_numPads(g);
562       GWire *w;
563 
564       for (i = 0;i < N;i++) {
565 	const char *padName = GCElement_getPadName(g,i);
566 	if (strcmp(padName,port) == 0)
567 	  break;
568       }
569 
570       if (i < N) {
571 	GWire *dw = 0;
572 
573 	/*
574 	 * Find wire to be deleted.
575 	 */
576 	for (w = g->wires[i], j = 0;w;w = w->next, j++) {
577 	  if (j == n) {
578 	    dw = w;
579 	    break;
580 	  }
581 	}
582 
583 	(*g->typeinfo->RemovePort)(TkGate.circuit->es,g,dw);
584       }
585     } else if (sscanf(p,"{edit %s %s %s %s %d",port,name,_newport,dir,&bits) == 5) {
586       int N = GCElement_numPads(g);
587       GWire *w = 0;
588       GWire *r;
589 
590 #if 0
591       printf("{edit %s %s %s %s %d}\n",port,name,_newport,dir,bits);
592 #endif
593 
594       if (*name == '*') *name = 0;	/* Use default signal name */
595 
596       if (g->typeinfo->code == GC_BLOCK) {
597 	char *q;
598 	char *oldport = port;
599 	char *newport = _newport;
600 
601 	/*
602 	 * Trim off the leading "??:"
603 	 */
604 	q = strchr(oldport,':');
605 	if (q) oldport = q+1;
606 	q = strchr(newport,':');
607 	if (q) newport = q+1;
608 
609 	/*
610 	 * Search for the named port.
611 	 */
612 	for (i = 0;i < N;i++) {
613 	  for (w = g->wires[i];w;w = w->next)
614 	    if (strcmp(w->name,oldport) == 0)
615 	      goto gotw;
616 	}
617       gotw:
618 
619 	if (strcmp(oldport,newport) != 0 && w) {
620 	  if (w->name) ob_free(w->name);
621 	  ob_touch(w);
622 	  w->name = ob_strdup(newport);
623 	}
624       } else {
625 	int N = GCElement_numPads(g);
626 	char *q;
627 
628 	/*
629 	 * Separate the port name into the base name 'port' and the
630 	 * quantifier index.
631 	 */
632 	q = port + strcspn(port,"0123456789");
633 	if (sscanf(q,"%d",&n) == 1)
634 	  *q = 0;
635 	else
636 	  n = 0;
637 
638 	/*
639 	 * Search for the wire associated with the port, the
640 	 * selected wire will be in 'w'.
641 	 */
642 	for (i = 0;i < N;i++) {
643 	  const char *padName = GCElement_getPadName(g,i);
644 	  if (strcmp(padName,port) == 0)
645 	    break;
646 	}
647 	for (w = g->wires[i], j = 0;j < n;w = w->next, j++);
648       }
649 
650       /*
651        * Apply edits to wire w if found.
652        */
653       if (w) {
654 	r = wire_root(w->nodes,0);
655 	net_setSize(r->net,bits);
656 	if (strcmp(w->net->n_signame,name) != 0)
657 	  net_rename(w->net,name,GNet_getShowName(w->net));
658       }
659     } else {
660       printf("FAILED: %s\n",p);
661     }
662     p++;
663   }
664 }
665 
Generic_editPropsDLDelay(GCElement * g)666 void Generic_editPropsDLDelay(GCElement *g)
667 {
668   char buf[STRMAX],*p;
669   GGateInfo *gi = g->typeinfo;
670   GDelayDef *dd;
671   int i;
672 
673   if (!gi->delayNames[0]) {
674     DoTcl("set ::edgat_dtype none");
675     return;
676   }
677 
678   p = buf;
679   *p = 0;
680   for (i = 0;gi->delayNames[i];i++) {
681     p += sprintf(p," \"%s\"",gi->delayNames[i]);
682     DoTcl("set ::edgat_techdelay(%s) 5",gi->delayNames[i]);
683     DoTcl("set ::edgat_delayvalue(%s) %d",gi->delayNames[i],g->delays[i]);
684   }
685 
686   DoTcl("set ::edgat_tech %s",g->tech);
687   DoTcl("set ::edgat_delays { %s }",buf);
688   if (g->cust_delay) {
689     DoTcl("set ::edgat_dtype cust");
690   } else {
691     DoTcl("set ::edgat_dtype tech");
692   }
693 
694   if (gi->delay_defs) {
695     p = buf;
696     *p = 0;
697     for (dd = gi->delay_defs;dd;dd = dd->dd_next) {
698       p += sprintf(p," %s",dd->dd_tech ? dd->dd_tech : TKGATE_DEFAULT_TECH);
699     }
700 
701     DoTcl("set ::edgat_techList { %s }",buf);
702   } else {
703     /* NOTE: This branch is only called when tkgate is improperly configured */
704     DoTcl("set ::edgat_techList { default }");
705   }
706 }
707 
Generic_editPropsULDelay(GCElement * g)708 void Generic_editPropsULDelay(GCElement *g)
709 {
710   GGateInfo *gi = g->typeinfo;
711   int i;
712   const char *dtype,*tech;
713 
714   ob_touch(g);
715 
716   for (i = 0;gi->delayNames[i];i++) {
717     char buf[STRMAX];
718     const char *r;
719     int value;
720 
721     sprintf(buf,"edgat_delayvalue(%s)",gi->delayNames[i]);
722     r = Tcl_GetVar(TkGate.tcl,buf,TCL_GLOBAL_ONLY);
723     if (r && sscanf(r,"%d",&value) == 1) {
724       if (value < 1) value = 1;
725       ob_touch(g->delays);
726       g->delays[i] = value;
727     }
728   }
729 
730   dtype = Tcl_GetVar(TkGate.tcl,"edgat_dtype",TCL_GLOBAL_ONLY);
731   tech = Tcl_GetVar(TkGate.tcl,"edgat_tech",TCL_GLOBAL_ONLY);
732 
733   if (!dtype) return;
734   if (strcmp(dtype,"tech") == 0) {
735     if (g->tech) ob_free(g->tech);
736     g->tech = ob_strdup(tech);
737     g->cust_delay = 0;
738   } else if (strcmp(dtype,"cust") == 0) {
739     g->cust_delay = 1;
740   }
741 }
742 
Generic_editPropsDLBasics(GCElement * g)743 void Generic_editPropsDLBasics(GCElement *g)
744 {
745   int x,y,rw,rh;
746   int dbw = 440;		/* Estimated width of dialog box */
747   int dbh = 410;		/* Estimated height of dialog box */
748 
749 #if 0
750   printf("Generic_editPropsDLBasics(%s)\n",g->typeinfo->name);
751 #endif
752   Tcl_SetVar(TkGate.tcl,"edgat_type",g->typeinfo->name,TCL_GLOBAL_ONLY);
753   Tcl_SetVar(TkGate.tcl,"edgat_name",(g->ename?g->ename:""),TCL_GLOBAL_ONLY);
754   DoTcl("set ::edgat_hideName %d",!g->show_name);
755   DoTcl("set ::edgat_anchor %d",g->anchored);
756   DoTcl("set ::edgat_cpbreak %d",g->cpath_cut);
757   DoTcl("set ::edgat_xpos %d",g->xpos);
758   DoTcl("set ::edgat_ypos %d",g->ypos);
759 
760   rh = HeightOfScreen(TkGate.S);
761   rw = WidthOfScreen(TkGate.S);
762   x = ctow_x(g->xpos-50);
763   y = ctow_y(g->ypos-50);
764 
765   DoTcl("offsetgeometry . %d %d",x,y);
766   sscanf(Tcl_GetStringResult(TkGate.tcl),"+%d+%d",&x,&y);
767 
768   if (x < 25) x = 25;
769   if (y < 25) y = 25;
770   if (x + dbw > rw-25) x = rw-25-dbw;
771   if (y + dbh > rh-50) y = rh-50-dbh;
772 
773   DoTcl("set ::edgat_geom +%d+%d",x,y);
774 }
775 
Generic_editPropsULBasics(GCElement * g)776 void Generic_editPropsULBasics(GCElement *g)
777 {
778   Tcl_Interp *tcl = TkGate.tcl;
779   const char *name = Tcl_GetVar(tcl,"edgat_name",TCL_GLOBAL_ONLY);
780   const char *hide = Tcl_GetVar(tcl,"edgat_hideName",TCL_GLOBAL_ONLY);
781   const char *anchor = Tcl_GetVar(tcl,"edgat_anchor",TCL_GLOBAL_ONLY);
782   const char *cpcut = Tcl_GetVar(tcl,"edgat_cpbreak",TCL_GLOBAL_ONLY);
783   const char *xpos = Tcl_GetVar(tcl,"edgat_xpos",TCL_GLOBAL_ONLY);
784   const char *ypos = Tcl_GetVar(tcl,"edgat_ypos",TCL_GLOBAL_ONLY);
785   int n,x,y;
786 
787   SetModified(MF_NET|MF_GATE);
788 
789   ob_touch(g);
790 
791   if (*name)
792     gate_setName(g,name,TkGate.circuit->es->env);
793 
794   if (sscanf(hide,"%d",&n) == 1)
795     g->show_name = !n;
796 
797   if (sscanf(anchor,"%d",&n) == 1)
798     g->anchored = n;
799 
800   if (sscanf(cpcut,"%d",&n) == 1)
801     g->cpath_cut = n;
802 
803   if (xpos && ypos && sscanf(xpos,"%d",&x) == 1 && sscanf(ypos,"%d",&y) == 1) {
804     if (x != g->xpos || y != g->ypos) {
805       int a = g->anchored;
806       g->anchored = 0;
807       gate_moveTo(g,x,y);
808       g->anchored = a;
809     }
810   }
811 }
812 
Generic_EditProps(GCElement * g,int isLoadDialog)813 int Generic_EditProps(GCElement *g,int isLoadDialog)
814 {
815   if (isLoadDialog) {
816     Generic_editPropsDLBasics(g);
817     Generic_editPropsDLWires(g);
818     Generic_editPropsDLDelay(g);
819   } else {
820     ob_touch(g);
821     Generic_editPropsULWires(g);
822     Generic_editPropsULBasics(g);
823     Generic_editPropsULDelay(g);
824 
825     FlagRedraw();
826   }
827   return 0;
828 }
829 
Generic_VerSave(FILE * f,GCElement * g)830 void Generic_VerSave(FILE *f,GCElement *g)
831 {
832   VerilogBasicGateCall(f,g);
833   VerilogBasicGateParmList(f,g);
834   VerilogBasicGateComment(f,g,1);
835   fprintf(f,"\n");
836 }
837 
838 /*
839  * Rotate a gate 90 degree counter-clockwise around (x,y) and adjust fixed
840  * wire positions if necessary.
841  */
Generic_Rotate(GCElement * g,int centX,int centY,int rdir)842 void Generic_Rotate(GCElement *g, int centX, int centY,int rdir)
843 {
844   int N = GCElement_numPads(g);
845   int x = g->xpos;
846   int y = g->ypos;
847   int i,j;
848 
849   ob_touch(g);
850   g->xpos = rotateX(x - centX,y - centY,rdir) + centX;
851   g->ypos = rotateY(x - centX,y - centY,rdir) + centY;
852   g->orient = (g->orient + 4 + rdir) % 4;
853 
854   for (i = 0;i < N;i++) {
855     GWire *w = g->wires[i];
856     GPadLoc *L = GCElement_getPadLoc(g,i,g->orient);
857     int x1 = L->x1 + g->xpos;
858     int y1 = L->y1 + g->ypos;
859     int x2 = L->x2 + g->xpos;
860     int y2 = L->y2 + g->ypos;
861 
862     for (j = 0;w;w = w->next, j++) {
863       if (x1 == x2 && y1 == y2) {
864 	wire_move(w->nodes,x1-w->nodes->x,y1-w->nodes->y,VERTICAL|HORIZONTAL);
865       }
866     }
867   }
868 }
869 
Generic_wireSnap(GCElement * g,GWire * w,int * mod,int retry)870 GWireNode *Generic_wireSnap(GCElement *g,GWire *w,int *mod,int retry)
871 {
872   int p,n;
873 
874   if (posongate(w,w->gate,&p,&n) == 0) {
875     GPadLoc *loc = GCElement_getPadLoc(g,p,w->gate->orient);
876     *mod = wire_force(w,loc->dir,retry);
877   }
878   return w->nodes;
879 }
880 
Nop_SimInitFunc(EditState * ss,GCElement * g,const char * path)881 void Nop_SimInitFunc(EditState *ss,GCElement *g,const char *path)
882 {
883 }
884 
Nop_SimHitFunc(EditState * ss,GCElement * g)885 int Nop_SimHitFunc(EditState *ss,GCElement *g)
886 {
887   return 0;
888 }
889 
890 
Nop_VerSave(FILE * f,GCElement * g)891 int Nop_VerSave(FILE *f,GCElement *g)
892 {
893   return 0;
894 }
895 
Nop_Copy(EditState * es,GCElement * g,int x,int y,unsigned flags)896 GCElement *Nop_Copy(EditState *es,GCElement *g,int x,int y,unsigned flags)
897 {
898   return 0;
899 }
900 
gateinfo_iconInit(GGateInfo * gi,Pixmap P,iconDimensions * id,int boldOffset)901 void gateinfo_iconInit(GGateInfo *gi,Pixmap P,iconDimensions *id,int boldOffset)
902 {
903   int i;
904 
905   for (i = 0;i < 4;i++) {
906     gi->icon[i] = new_Icon(P,id[i].x,id[i].y,id[i].w,id[i].h,id[i].ox,id[i].oy);
907     gi->icon[i+4] = new_Icon(P,id[i].x,id[i].y+boldOffset,id[i].w,id[i].h,id[i].ox,id[i].oy);
908   }
909 }
910 
gateinfo_altIconInit(GGateInfo * gi,Pixmap P,iconDimensions * id,int boldOffset)911 void gateinfo_altIconInit(GGateInfo *gi,Pixmap P,iconDimensions *id,int boldOffset)
912 {
913   int i;
914 
915   for (i = 0;i < 4;i++) {
916     gi->altIcon[i] = new_Icon(P,id[i].x,id[i].y,id[i].w,id[i].h,id[i].ox,id[i].oy);
917     gi->altIcon[i+4] = new_Icon(P,id[i].x,id[i].y+boldOffset,id[i].w,id[i].h,id[i].ox,id[i].oy);
918   }
919 }
920 
gateinfo_1iconInit(GGateInfo * gi,Pixmap P,iconDimensions * id,int boldOffset)921 void gateinfo_1iconInit(GGateInfo *gi,Pixmap P,iconDimensions *id,int boldOffset)
922 {
923   int i;
924   Icon *pid,*bid;
925 
926   pid = new_Icon(P,id->x,id->y,id->w,id->h,id->ox,id->oy);
927   bid = new_Icon(P,id->x,id->y+boldOffset,id->w,id->h,id->ox,id->oy);
928 
929   for (i = 0;i < 4;i++) {
930     gi->icon[i] = pid;
931     gi->icon[i+4] = bid;
932   }
933 }
934 
keymenuent_compare(const void * pA,const void * pB)935 static int keymenuent_compare(const void *pA,const void *pB)
936 {
937   GKeyMenuEnt **A = (GKeyMenuEnt **) pA;
938   GKeyMenuEnt **B = (GKeyMenuEnt **) pB;
939   int x;
940 
941   x = strcmp((*A)->entry.gtag,(*B)->entry.gtag);
942   if (x == 0) return (*A)->entry.order-(*B)->entry.order;
943   return x;
944 }
945 
946 /*****************************************************************************
947  *
948  * Find or create a top-level entry in the "Make" menu.
949  *
950  * Parameters:
951  *    name		Name of message tag for menu entry (or NULL)
952  *
953  *****************************************************************************/
findAddRootMakeMenu(char * name)954 BuildMenuRoot *findAddRootMakeMenu(char *name)
955 {
956   BuildMenuRoot *bmr;
957 
958   if (name) {
959     bmr = (BuildMenuRoot *) SHash_find(makeMenuData->rmap,name);
960     if (!bmr) {
961       char buf[STRMAX];
962 
963       bmr = (BuildMenuRoot*) ob_malloc(sizeof(BuildMenuRoot),"BuildRootMenu");
964       sprintf(buf,"root%d",makeMenuData->numRoot);
965       bmr->mname = ob_strdup(buf);
966       SHash_insert(makeMenuData->rmap,name,bmr);
967       bmr->count = 0;
968       bmr->kme = (GKeyMenuEnt**) ob_malloc(sizeof(GKeyMenuEnt*)*MAKEENTRYMAX,"GKeyMenuEnt*[]");
969       makeMenuData->roots[makeMenuData->numRoot++] = bmr;
970     }
971   } else {
972     bmr = (BuildMenuRoot*) ob_malloc(sizeof(BuildMenuRoot),"BuildRootMenu");
973     bmr->count = 0;
974     bmr->mname = 0;
975     bmr->kme = (GKeyMenuEnt**) ob_malloc(sizeof(GKeyMenuEnt*)*MAKEENTRYMAX,"GKeyMenuEnt*[]");
976     makeMenuData->roots[makeMenuData->numRoot++] = bmr;
977   }
978 
979   return bmr;
980 }
981 
tcl_sanitize(char * buf,char * s)982 char *tcl_sanitize(char *buf,char *s)
983 {
984   char *p = buf;
985 
986   while (*s) {
987     if (strchr("\\{}\"[]",*s))
988       *p++ = '\\';
989     *p++ = *s++;
990   }
991   *p = 0;
992 
993   return buf;
994 }
995 
buildMakeMenuData()996 void buildMakeMenuData()
997 {
998   HashElem *E;
999   int i,j;
1000 
1001   if (makeMenuData) return;
1002 
1003   makeMenuData = (MakeMenuData*) ob_malloc(sizeof(MakeMenuData),"MakeMenuData");
1004   makeMenuData->rmap = new_SHash();
1005   makeMenuData->numRoot = 0;
1006 
1007   /*
1008    * Create the standard root menus.
1009    */
1010   findAddRootMakeMenu("gm.io");
1011   findAddRootMakeMenu("gm.gate");
1012   findAddRootMakeMenu("gm.rgate");
1013   findAddRootMakeMenu("gm.msi");
1014   findAddRootMakeMenu("gm.alu");
1015   findAddRootMakeMenu("gm.mem");
1016   findAddRootMakeMenu("gm.mod");
1017 
1018   /*
1019    * First Pass - standard entries
1020    * Register all root names
1021    * Create shortcuts
1022    *
1023    */
1024   for (E = Hash_first(GateIdxHash);E;E = Hash_next(GateIdxHash,E)) {
1025     GGateInfo *gi = (GGateInfo*) HashElem_obj(E);
1026 
1027     for (i = 0;gi->cmds[i].command;i++) {
1028       GKeyMenuEnt *kme = &gi->cmds[i];
1029 
1030       if (!kme->entry.gtag) kme->entry.gtag = "--";
1031 
1032       if (kme->root.name) {
1033 	BuildMenuRoot *bmr = findAddRootMakeMenu(kme->root.name);
1034 	assert(bmr->count < MAKEENTRYMAX);
1035 	bmr->kme[bmr->count++] = kme;
1036       }
1037     }
1038   }
1039 
1040   /*
1041    * Second Pass - direct top-level entries (e.g., Comment, Frame)
1042    * Create shortcuts
1043    *
1044    */
1045   for (E = Hash_first(GateIdxHash);E;E = Hash_next(GateIdxHash,E)) {
1046     GGateInfo *gi = (GGateInfo*) HashElem_obj(E);
1047 
1048     for (i = 0;gi->cmds[i].command;i++) {
1049       GKeyMenuEnt *kme = &gi->cmds[i];
1050       if (!kme->root.name && kme->entry.name) {
1051 	BuildMenuRoot *bmr = findAddRootMakeMenu(0);
1052 	bmr->count = 1;
1053 	bmr->kme[0] = kme;
1054       }
1055     }
1056   }
1057 
1058 
1059   for (j = 0;j < makeMenuData->numRoot;j++) {
1060     BuildMenuRoot *bmr = makeMenuData->roots[j];
1061     if (bmr->count == 0) continue;
1062     qsort(bmr->kme,bmr->count,sizeof(GKeyMenuEnt*),keymenuent_compare);
1063   }
1064 
1065 #if 0
1066   /* Debug dump of menu */
1067   printf("MENU\n");
1068   for (j = 0;j < makeMenuData->numRoot;j++) {
1069     BuildMenuRoot *bmr = makeMenuData->roots[j];
1070 
1071     if (bmr->count == 0) continue;
1072 
1073     if (bmr->mname) {
1074       printf("  %s : %s\n",bmr->mname,bmr->kme[0]->root.name);
1075       for (i = 0;i < bmr->count;i++) {
1076 	printf("     %s %s\n",bmr->kme[i]->entry.name,bmr->kme[i]->entry.gtag);
1077       }
1078     } else {
1079       printf("  -- : %s\n",bmr->kme[0]->entry.name);
1080     }
1081   }
1082 #endif
1083 }
1084 
1085 /*****************************************************************************
1086  *
1087  * Parse a keyboard sequence for creating a gate.
1088  *
1089  * Parameters:
1090  *    keys[]		Array of generated key event names
1091  *    key_seq		Abbreviated key sequence
1092  *
1093  * Returns:		Length of key sequence.
1094  *
1095  *****************************************************************************/
parseKeys(char keys[5][128],const char * key_seq)1096 int parseKeys(char keys[5][128],const char *key_seq)
1097 {
1098   char buf[STRMAX],*T;
1099   int n = 0;
1100 
1101   strcpy(buf,key_seq);
1102   for (T = strtok(buf," ");T;T = strtok(0," ")) {
1103     if (strncmp(T,"Ctl-",4) == 0) {
1104       sprintf(keys[n++],"Control-%s",T+4);
1105     } else if (!T[1] && isalnum(T[0])) {
1106       sprintf(keys[n++],"KeyPress-%s",T);
1107     } else if (T[1]) {
1108       sprintf(keys[n++],"%s",T);
1109     } else {
1110       char *ks = 0;
1111 
1112       switch (T[0]) {
1113       case '+' : ks = "plus"; break;
1114       case '-' : ks = "minus"; break;
1115       case '*' : ks = "asterisk"; break;
1116       case '=' : ks = "equal"; break;
1117       case '/' : ks = "slash"; break;
1118       case '{' : ks = "braceleft"; break;
1119       case '}' : ks = "braceright"; break;
1120       case '[' : ks = "bracketleft"; break;
1121       case ']' : ks = "bracketright"; break;
1122       case '@' : ks = "at"; break;
1123       }
1124       assert(ks);
1125       if (ks) strcpy(keys[n++],ks);
1126     }
1127     if (n == 5) break;
1128   }
1129 
1130   return n;
1131 }
1132 
1133 /*****************************************************************************
1134  *
1135  *****************************************************************************/
makeMakeShortcuts()1136 void makeMakeShortcuts()
1137 {
1138   int i;
1139   HashElem *E;
1140 
1141   for (E = Hash_first(GateIdxHash);E;E = Hash_next(GateIdxHash,E)) {
1142     GGateInfo *gi = (GGateInfo*) HashElem_obj(E);
1143 
1144     for (i = 0;gi->cmds[i].command;i++) {
1145       GKeyMenuEnt *kme = &gi->cmds[i];
1146       char keys[5][128];
1147       int n;
1148 
1149       if (kme->accel_label_only || !kme->key_seq) continue;
1150 
1151       n = parseKeys(keys,kme->key_seq);
1152       if (n == 1) {
1153 	DoTcl("KeyBinding::new <%s> { action Make { %s } } -perm 1",keys[0],kme->command);
1154       } else {
1155 	DoTcl("KeyBinding::new <%s><%s> { action Make { %s } } -perm 1",keys[0],keys[1],kme->command);
1156       }
1157     }
1158   }
1159 }
1160 
1161 
makeMakeMenu(const char * m)1162 void makeMakeMenu(const char *m)
1163 {
1164   int did_root_sep = 0;
1165   char buf[STRMAX];
1166   int i,j;
1167 
1168   DoTcl("menu %s",m);	/* Create the menu */
1169 
1170   for (j = 0;j < makeMenuData->numRoot;j++) {
1171     BuildMenuRoot *bmr = makeMenuData->roots[j];
1172 
1173     if (bmr->count == 0) continue;
1174 
1175     if (bmr->mname) {
1176       char *cur_gtag = 0;
1177 
1178 
1179       DoTcl("%s add cascade -label [m %s] -menu %s.%s -underline [ul %d]",
1180 	    m,bmr->kme[0]->root.name,m,bmr->mname,bmr->kme[0]->root.ul);
1181       DoTcl("menu %s.%s -tearoff 0",m,bmr->mname);
1182       for (i = 0;i < bmr->count;i++) {
1183 	if (cur_gtag && strcmp(cur_gtag,bmr->kme[i]->entry.gtag) != 0)
1184 	  DoTcl("%s.%s add separator",m,bmr->mname);
1185 	cur_gtag = bmr->kme[i]->entry.gtag;
1186 	DoTcl("%s.%s add command -label [m %s] -underline [ul %d] -command { action Make { %s } } -accelerator \"%s\"",
1187 	      m,bmr->mname,bmr->kme[i]->entry.name,bmr->kme[i]->entry.ul,bmr->kme[i]->command,tcl_sanitize(buf,bmr->kme[i]->key_seq));
1188       }
1189     } else {
1190       if (!did_root_sep)
1191 	DoTcl("%s add separator",m);
1192       did_root_sep = 1;
1193       DoTcl("%s add command -label [m %s] -underline [ul %d] -command { action Make { %s } } -accelerator \"%s\"",
1194 	    m,bmr->kme[0]->entry.name,bmr->kme[0]->entry.ul,bmr->kme[0]->command,tcl_sanitize(buf,bmr->kme[0]->key_seq));
1195     }
1196   }
1197 
1198 #if 0
1199   /*
1200    * Free temporary memory
1201    */
1202   for (E = Hash_first(H);E;E = Hash_next(H,E)) {
1203     BuildMenuRoot *bmr = (BuildMenuRoot*) HashElem_obj(E);
1204     ob_free(bmr->mname);
1205     ob_free(bmr->kme);
1206     ob_free(bmr);
1207   }
1208   delete_SHash(H);
1209 #endif
1210 }
1211 
1212 
1213 /*****************************************************************************
1214  *
1215  * Generate primitive cell definition
1216  *
1217  * Parameters:
1218  *    f			File to write cell to.
1219  *    name		Name of cell to write.
1220  *
1221  *****************************************************************************/
Generic_WriteCellDef(FILE * f,GCellSpec * gcs)1222 void Generic_WriteCellDef(FILE *f,GCellSpec *gcs)
1223 {
1224   GCellSpec_writeBeginModule(f,gcs);
1225   fprintf(f,"  // Definition pending\n");
1226   GCellSpec_writeEndModule(f,gcs);
1227 }
1228 
1229 /*****************************************************************************
1230  *
1231  * Place holder for null primitive cell definition generator
1232  *
1233  * Parameters:
1234  *    f			File to write cell to.
1235  *    name		Name of cell to write.
1236  *
1237  *****************************************************************************/
Nop_WriteCellDef(FILE * f,GCellSpec * gcs)1238 void Nop_WriteCellDef(FILE *f,GCellSpec *gcs)
1239 {
1240 }
1241 
init_gates()1242 void init_gates()
1243 {
1244   init_and();			/*  */
1245   init_or();			/*  */
1246   init_xor();			/*  */
1247   init_buffer();		/*  */
1248   init_bufif();			/* depends on 'buffer' */
1249   init_adder();			/*  */
1250   init_mult();			/*  */
1251   init_divide();		/*  */
1252   init_register();		/*  */
1253   init_ff();			/*  */
1254   init_clock();			/*  */
1255   init_switch();		/*  */
1256   init_ground();		/*  */
1257   init_vdd();			/*  */
1258   init_in();			/*  */
1259   init_out();			/* depends on 'in' */
1260   init_inout();			/* depends on 'in' */
1261   init_dip();			/*  */
1262   init_mux();			/*  */
1263   init_demux();			/*  */
1264   init_decoder();		/*  */
1265   init_tap();			/*  */
1266   init_concat();		/*  */
1267   init_lshift();		/*  */
1268   init_rshift();		/*  */
1269   init_arshift();		/*  */
1270   init_roll();			/*  */
1271   init_joint();			/*  */
1272   init_block();			/*  */
1273   init_symblock();		/*  */
1274   init_ram();			/*  */
1275   init_rom();			/*  */
1276   init_nmos();			/*  */
1277   init_pmos();			/*  */
1278   init_pullup();		/*  */
1279   init_pulldown();		/*  */
1280   init_comment();		/*  */
1281   init_frame();			/*  */
1282   init_led();			/*  */
1283   init_jkff();			/*  */
1284   init_script();		/*  */
1285 
1286   buildMakeMenuData();
1287 }
1288