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