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