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 17:45:19 2009
19 ****************************************************************************/
20 
21 #include "tkgate.h"
22 #include "print.h"
23 
24 #define AOX_WIRESPACE	5	/* Space between ports when using extender bars */
25 #define AOX_HOOK	5
26 
27 #define AND_IN 0
28 #define AND_OUT 1
29 
30 /*
31  * AOX=AND/OR/XOR specific operations
32  */
33 GCElement *AOX_Make(EditState **,GModuleDef *,int,int,int,int,const char *,int,const char**,int);
34 void AOX_Draw(GCElement *g,int md);
35 void AOX_AddInput(EditState *es,GCElement*);
36 void AOX_VerSave(FILE*,GCElement*);
37 void AOX_SetProp(GCElement*,const char*,const void*);
38 int AOX_EditProps(GCElement *g,int isLoadDialog);
39 void AOX_PSWrite(GPrint *P,GModLayout*,GCElement *g);
40 void AOX_RemovePort(EditState *es,GCElement *g,GWire *);
41 GCElement *AOX_Copy(GModuleDef *M,GCElement *g,int x,int y,unsigned flags);
42 void AOX_Rotate(GCElement *g,int centX, int centY,int rdir);
43 void AOX_WriteCellDef(FILE *f,GCellSpec *gcs);
44 
45 static iconDimensions and_iconDims[] = {
46   {0, 0, 20, 15, 10, 7},
47   {21, 0, 15, 20, 7, 9},
48   {16, 21, 20, 15, 9, 7},
49   {0, 16, 15, 20, 7, 10},
50 };
51 static int and_iconBoldOffset = 37;
52 
53 GPadLoc and_out_loc[] ={		/* Gate output */
54  {10,0,10,0,D_RIGHT},
55  {0,-10,0,-10,D_UP},
56  {-10,0,-10,0,D_LEFT},
57  {0,10,0,10,D_DOWN}};
58 
59 GPadLoc and_in_loc[] = {		/* Gate input */
60  {-11,-7,-11,7,D_LEFT},
61  {-7,11,7,11,D_DOWN},
62  {11,-7,11,7,D_RIGHT},
63  {-7,-11,7,-11,D_UP}};
64 
65 static char *psAnd[] = {
66   "%",
67   "% An AND gate",
68   "%",
69   "/psand {",
70   "  startgate",
71   "  2.5 7 moveto",
72   "  -10.5 7 lineto",
73   "  -10.5 -7 lineto",
74   "  2.5 -7 lineto",
75   "  2.5 0 7 -90 90 arc",
76   "  closepath",
77   "  stroke",
78   "  grestore",
79   "} bind def",
80   0
81 };
82 
83 GGateInfo gate_and_info = {
84   0,
85   "AND",
86   "and:nand",0x2,
87   "psand",psAnd,
88   0,0,
89 
90   {{"a",	{"gm.gate",0},		{"gm.gate.and",0,0,100},	"gat_make AND"},
91    {"A",	{"gm.gate",0},		{"gm.gate.nand",3,0,101},	"gat_make AND -invert Z"},
92    {"Ctl-r a",	{"gm.rgate",0},		{"gm.rgate.and",0,0,100},	"gat_make AND -pins I=1"},
93    {"Ctl-r A",	{"gm.rgate",0},		{"gm.rgate.nand",3,0,101},	"gat_make AND -pins I=1 -invert Z"},
94    {0}},
95 
96   and_iconDims,
97 
98   2,{{"I",IN,1,2,and_in_loc,1},{"Z",OUT,1,1,and_out_loc,0}},
99   {{0,-12,CT},{12,0,LJ},{0,-12,CT},{12,0,LJ}},
100   {1},
101 
102   {"Diz",0},
103 
104   AOX_Make,
105   AOX_WriteCellDef,
106   Generic_Init,
107   Generic_Delete,
108   Generic_GetExtents,
109   Generic_HitDistance,
110   AOX_Draw,
111   Generic_Move,
112   AOX_Copy,
113   AOX_AddInput,
114   Err_AddOutput,
115   Err_AddInOut,
116   AOX_Rotate,
117   AOX_RemovePort,
118   Err_ChangePin,
119   Nop_SimInitFunc,
120   Nop_SimHitFunc,
121   AOX_PSWrite,
122   AOX_EditProps,
123   AOX_VerSave,
124   AOX_SetProp,
125   0,
126   0
127 };
128 
AOX_Make(EditState ** es,GModuleDef * env,int GType,int x,int y,int r,const char * Name,int noWires,const char ** options,int nOptions)129 GCElement *AOX_Make(EditState **es,GModuleDef *env,int GType,
130 			int x,int y,int r,const char *Name,int noWires,const char **options,int nOptions)
131 {
132   GCElement *g = Generic_Make(es,env,GType,x,y,r,Name,noWires,options,nOptions);
133 
134   ob_touch(g);
135   g->u.basic.extbar = TkGate.circuit->useExtBars;
136 
137   return g;
138 }
139 
140 /*
141  * Get coordinates for extender bars.  The is_draw flag should be '1' if coordinates
142  * are for screen use, and 0 if coordinates are for postscript use.
143  */
AOX_extBarCoords(GCElement * g,int is_draw,int _x1[2],int _y1[2],int _x2[2],int _y2[2],int * b_dx,int * b_dy)144 void AOX_extBarCoords(GCElement *g,int is_draw,int _x1[2],int _y1[2],int _x2[2],int _y2[2],int *b_dx,int *b_dy)
145 {
146   int N = wire_numOnPad(g->wires[AND_IN]);
147   int D = (N+1)*AOX_WIRESPACE;						/* Total length required */
148   int x1 = g->xpos + g->typeinfo->Pad[AND_IN].Loc[g->orient].x1;
149   int y1 = g->ypos + g->typeinfo->Pad[AND_IN].Loc[g->orient].y1;
150   int x2 = g->xpos + g->typeinfo->Pad[AND_IN].Loc[g->orient].x2;
151   int y2 = g->ypos + g->typeinfo->Pad[AND_IN].Loc[g->orient].y2;
152 
153   if (is_draw) {
154     x1 = ctow_x(x1);
155     y1 = ctow_y(y1);
156     x2 = ctow_x(x2);
157     y2 = ctow_y(y2);
158   }
159 
160   switch (g->orient) {
161   case D_RIGHT :
162     D = (D-(y2-y1-1));		/* distance to add */
163     _x1[0] = x1+1;		_y1[0] = y1-1;
164     _x2[0] = x1+1;		_y2[0] = y1-D/2;
165     _x1[1] = x1+1;		_y1[1] = y2+1;
166     _x2[1] = x1+1;		_y2[1] = y2+D-(D/2);
167     *b_dx = 1;			*b_dy = 0;
168     break;
169   case D_LEFT :
170     D = (D-(y2-y1-1));		/* distance to add */
171     _x1[0] = x1-1;		_y1[0] = y1-1;
172     _x2[0] = x1-1;		_y2[0] = y1-D/2;
173     _x1[1] = x1-1;		_y1[1] = y2+1;
174     _x2[1] = x1-1;		_y2[1] = y2+D-(D/2);
175     *b_dx = -1;			*b_dy = 0;
176     break;
177   case D_UP :
178     D = (D-(x2-x1-1));		/* distance to add */
179     _x1[0] = x1-1;		_y1[0] = y1-1;
180     _x2[0] = x1-D/2;		_y2[0] = y1-1;
181     _x1[1] = x2+1;		_y1[1] = y1-1;
182     _x2[1] = x2+D-(D/2);	_y2[1] = y1-1;
183     *b_dx = 0;			*b_dy = -1;
184     break;
185   case D_DOWN :
186     D = (D-(x2-x1-1));		/* distance to add */
187     _x1[0] = x1-1;		_y1[0] = y1+1;
188     _x2[0] = x1-D/2;		_y2[0] = y1+1;
189     _x1[1] = x2+1;		_y1[1] = y1+1;
190     _x2[1] = x2+D-(D/2);	_y2[1] = y1+1;
191     *b_dx = 0;			*b_dy = 1;
192     break;
193   }
194 }
195 
AOX_Draw(GCElement * g,int md)196 void AOX_Draw(GCElement *g,int md)
197 {
198   int N = wire_numOnPad(g->wires[AND_IN]);
199 
200   Generic_Draw(g,md);
201 
202   if (N > 2 && g->u.basic.extbar) {
203     int x1[2],y1[2],x2[2],y2[2],b_dx,b_dy,i;
204 
205     AOX_extBarCoords(g,1,x1,y1,x2,y2,&b_dx,&b_dy);
206 
207     for (i = 0;i < 2;i++) {
208       ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x1[i],y1[i],x2[i],y2[i]);
209       if (g->selected)
210 	ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x1[i]+b_dx,y1[i]+b_dy,x2[i]+b_dx,y2[i]+b_dy);
211     }
212   }
213 }
214 
AOX_adjustWires(GCElement * g)215 static void AOX_adjustWires(GCElement *g)
216 {
217   int N,L,i,wx,wy,dx,dy;
218   GWire *w;
219   int d = 1;
220 
221   wx = wy = dx = dy = 0;
222 
223   N = wire_numOnPad(g->wires[AND_IN]);
224   L = AOX_WIRESPACE*(N+1);
225 
226   switch (g->orient) {
227   case 0 :
228     wx = g->xpos + g->typeinfo->Pad[AND_IN].Loc[g->orient].x1;
229     wy = g->ypos - d*L/2;
230     dx = 0;
231     dy = d*AOX_WIRESPACE;
232     break;
233   case 1 :
234     wx = g->xpos - d*L/2;
235     wy = g->ypos + g->typeinfo->Pad[AND_IN].Loc[g->orient].y1;
236     dx = d*AOX_WIRESPACE;
237     dy = 0;
238     break;
239   case 2 :
240     wx = g->xpos + g->typeinfo->Pad[AND_IN].Loc[g->orient].x1;
241     wy = g->ypos + d*L/2;
242     dx = 0;
243     dy = -d*AOX_WIRESPACE;
244     break;
245   case 3 :
246     wx = g->xpos + d*L/2;
247     wy = g->ypos + g->typeinfo->Pad[AND_IN].Loc[g->orient].y1;
248     dx = -d*AOX_WIRESPACE;
249     dy = 0;
250     break;
251   }
252 
253   for (i = 0,w = g->wires[AND_IN];w;i++, w = w->next) {
254     wx += dx;
255     wy += dy;
256     wire_move(w->nodes,wx-w->nodes->x,wy-w->nodes->y,VERTICAL|HORIZONTAL);
257   }
258 }
259 
AOX_AddInput(EditState * es,GCElement * g)260 void AOX_AddInput(EditState *es,GCElement *g)
261 {
262   if (!g->u.basic.extbar)
263     Generic_AddInput(es,g);		/* Legacy gate, use generic add function */
264   else {
265     GWire *e1,*e2;
266 
267     gate_draw(g,0);
268 
269     wire_new(es->env,&e1,&e2);
270 
271     ob_touch(g);
272     ob_touch(e1->nodes);
273     ob_touch(e2->nodes);
274     ob_touch(e1);
275     ob_touch(e2);
276 
277     e1->nodes->x = e2->nodes->x = 0;
278     e1->nodes->y = e2->nodes->y = 0;
279 
280     g->wires[AND_IN] = wire_append(g->wires[AND_IN],e1);
281     e1->gate = g;
282     e1->orient = g->typeinfo->Pad[AND_IN].Loc[g->orient].dir;
283 
284     switch (e1->orient) {
285     case D_RIGHT :
286       e2->nodes->x += TKGATE_STUBLEN;
287       break;
288     case D_UP :
289       e2->nodes->y -= TKGATE_STUBLEN;
290       break;
291     case D_LEFT :
292       e2->nodes->x -= TKGATE_STUBLEN;
293       break;
294     case D_DOWN :
295       e2->nodes->y += TKGATE_STUBLEN;
296       break;
297     }
298 
299     wire_finalizeNet(e1);
300     AOX_adjustWires(g);
301 
302     gate_draw(g,0);
303   }
304 }
305 
AOX_RemovePort(EditState * es,GCElement * g,GWire * w)306 void AOX_RemovePort(EditState *es,GCElement *g,GWire *w)
307 {
308   Generic_RemovePort(es,g,w);
309   AOX_adjustWires(g);
310 }
311 
AOX_GateParmList(FILE * f,GCElement * g)312 int AOX_GateParmList(FILE *f,GCElement *g)
313 {
314   GGateInfo *gi = g->typeinfo;
315   GWire *w;
316   int i,j;
317   int first_pin;
318   int nbits = g->wires[AND_OUT]->net->n_nbits;
319 
320   first_pin = 1;
321   fprintf(f," (");
322   for (i = 0;i < gi->NumPads;i++) {
323     for (w = g->wires[i], j=0;w;w = w->next, j++) {
324       char *inv = "";
325 
326       if (!first_pin)
327 	fprintf(f,", ");
328       first_pin = 0;
329 
330       if (gi->Pad[i].iotype == IN && w->invert)
331 	inv = "!";
332 
333       if (gi->Pad[i].CanAdd)
334 	fprintf(f,".%s%d",gi->Pad[i].name,j);
335       else
336 	fprintf(f,".%s",gi->Pad[i].name);
337       if (w->net->n_signame) {
338 	fprintf(f,"(%s",inv);
339 	if (w->net->n_nbits == 1 && nbits > 1)
340 	  fprintf(f,"{%d{%s}}",nbits,w->net->n_signame);
341 	else
342 	  fprintf(f,"%s",w->net->n_signame);
343 	fprintf(f,")");
344       } else
345 	fprintf(f,"(%sw%lx)",inv,(uintptr_t)w->net);
346     }
347   }
348   fprintf(f,");");
349   return 0;
350 }
351 
AOX_VerSave(FILE * f,GCElement * g)352 void AOX_VerSave(FILE *f,GCElement *g)
353 {
354   VerilogBasicGateCall(f,g);
355   AOX_GateParmList(f,g);
356   VerilogBasicGateComment(f,g,1);
357 
358   if (g->u.basic.extbar != TkGate.circuit->useExtBars)
359     fprintf(f," /eb:%d",g->u.basic.extbar);
360 
361   fprintf(f,"\n");
362 }
363 
AOX_SetProp(GCElement * g,const char * prop,const void * value)364 void AOX_SetProp(GCElement *g,const char *prop,const void *value)
365 {
366   if (strcmp(prop,"/eb") == 0) {
367     int n = *((int*)value);
368     g->u.basic.extbar = n;
369   }
370 }
371 
AOX_PSWrite(GPrint * P,GModLayout * l,GCElement * g)372 void AOX_PSWrite(GPrint *P,GModLayout *l,GCElement *g)
373 {
374   int N = wire_numOnPad(g->wires[AND_IN]);
375 
376   Generic_PSWrite(P,l,g);
377 
378   if (N > 2 && g->u.basic.extbar) {
379     int x1[2],y1[2],x2[2],y2[2],b_dx,b_dy,i;
380 
381     AOX_extBarCoords(g,0,x1,y1,x2,y2,&b_dx,&b_dy);
382 
383     for (i = 0;i < 2;i++)
384       fprintf(P->p_f,"gsave %d %d %d %d moveto lineto stroke grestore\n",x1[i],y1[i],x2[i],y2[i]);
385   }
386 }
387 
AOX_Copy(GModuleDef * M,GCElement * g,int x,int y,unsigned flags)388 GCElement *AOX_Copy(GModuleDef *M,GCElement *g,int x,int y,unsigned flags)
389 {
390   GCElement *ng = Generic_Copy(M,g,x,y,flags);
391 
392   ob_touch(ng);
393   ng->u.basic.extbar = g->u.basic.extbar;
394 
395   return ng;
396 }
397 
AOX_EditProps(GCElement * g,int isLoadDialog)398 int AOX_EditProps(GCElement *g,int isLoadDialog)
399 {
400   Tcl_Interp *tcl = TkGate.tcl;
401 
402   Generic_EditProps(g,isLoadDialog);
403   if (isLoadDialog) {
404     DoTcl("set ::edgat_extbar %d",g->u.basic.extbar);
405   } else {
406     const char *p;
407     if ((p = Tcl_GetVar(tcl,"edgat_extbar",TCL_GLOBAL_ONLY))) {
408       int eb;
409 
410       sscanf(p,"%d",&eb);
411 
412       if (eb != g->u.basic.extbar) {
413 	ob_touch(g);
414 	g->u.basic.extbar = eb;
415 	gate_draw(g,0);
416 	if (eb)
417 	  AOX_adjustWires(g);
418 	else
419 	  wire_setPadSpacing(g,AND_IN);
420 	gate_draw(g,0);
421       }
422     }
423   }
424 
425   return 0;
426 }
427 
AOX_Rotate(GCElement * g,int centX,int centY,int rdir)428 void AOX_Rotate(GCElement *g,int centX, int centY,int rdir)
429 {
430   Generic_Rotate(g,centX,centY,rdir);
431 #if 0
432   if (g->u.basic.extbar)
433     AOX_adjustWires(g);
434   else
435     wire_setPadSpacing(g,AND_IN);
436 #endif
437 }
438 
439 /*****************************************************************************
440  *
441  * Generate primitive cell definition for AND, OR and XOR gates.
442  *
443  * Parameters:
444  *    f			File to write cell to.
445  *    name		Name of cell to write.
446  *
447  *****************************************************************************/
AOX_WriteCellDef(FILE * f,GCellSpec * gcs)448 void AOX_WriteCellDef(FILE *f,GCellSpec *gcs)
449 {
450   GGateInfo *gi = gcs->gc_info;
451   int multiPad = gcs->gc_multiPad;
452   int numBit = gcs->gc_numBits;
453   const char *invSpec = gcs->gc_invSpec;
454   PrimParm primParm;
455   const char *type = "and";
456 
457   if (multiPad == 1) {
458     if (strcmp(gi->name,"OR") == 0)
459       type = "ror";
460     else if (strcmp(gi->name,"XOR") == 0)
461       type = "rxor";
462     else
463       type = "rand";
464   } else {
465     if (strcmp(gi->name,"OR") == 0)
466       type = "or";
467     else if (strcmp(gi->name,"XOR") == 0)
468       type = "xor";
469     else
470       type = "and";
471   }
472 
473   PrimParm_init(&primParm);
474   PrimParm_rangeSet(&primParm,"Z_RANGE", (multiPad ==1) ? 1 : numBit);
475   PrimParm_rangeSet(&primParm,"I_RANGE", numBit);
476   PrimParm_invSet(&primParm,"invZ", (*invSpec == 'N'));
477   PrimParm_intSet(&primParm,"NUMIN", multiPad);
478   Primitive_write(f,type,gcs,&primParm);
479 }
480 
init_and()481 void init_and()
482 {
483   Pixmap P;
484 
485   P = Pixmap_registerFromFile("and","and.b");
486   gateinfo_iconInit(&gate_and_info,P,and_iconDims,and_iconBoldOffset);
487   RegisterGate(&gate_and_info);
488 }
489