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 Fri May 1 20:41:14 2009
19 ****************************************************************************/
20
21 #include "tkgate.h"
22 #include "print.h"
23
24 #define DECODER_IN 0
25 #define DECODER_EN 1
26 #define DECODER_OUT 2
27
28 static void Decoder_Delete(GCElement *g,GModuleDef *env,int drawp);
29 static void Decoder_Draw(GCElement *g,int md);
30 static GCElement *Decoder_Make(EditState **es,GModuleDef *env,int GType,
31 int x,int y,int r,const char *Name,int noWires,const char**,int);
32 GCElement *MuxDemux_Copy(GModuleDef *M,GCElement *g,int x,int y,unsigned flags);
33 static void Decoder_PSWrite(GPrint *P,GModLayout*,GCElement *g);
34 static void Decoder_Rotate(GCElement *g, int centX, int centY,int rdir);
35 static void Decoder_SetProp(GCElement*,const char*,const void*);
36 int MuxDemux_EditProps(GCElement *g,int isLoadDialog);
37 static void Decoder_VersionDelta(GCElement*,Version*);
38 static GWireNode *Decoder_wireSnap(GCElement *g,GWire *w,int *mod,int retry);
39 static void Decoder_AddOutput(EditState *es,GCElement *g);
40 void MuxDemux_VerSave(FILE*,GCElement*);
41 static void Decoder_WriteCellDef(FILE *f,GCellSpec *gcs);
42
43 static iconDimensions decoder_iconDims[] = {
44 {29, 60, 59, 29, 30, 12},
45 {0, 29, 29, 59, 12, 30},
46 {0, 0, 59, 29, 30, 15},
47 {60, 0, 29, 59, 15, 30},
48 };
49 static int decoder_iconBoldOffset = 89;
50
51 GPadLoc decoder_out_loc[] = {
52 {-30,16,30,16,D_DOWN},
53 {16,-30,16,30,D_RIGHT},
54 {-30,-16,30,-16,D_UP},
55 {-16,-30,-16,30,D_LEFT},
56 };
57
58 GPadLoc decoder_in_loc[] = {
59 {0,-13,0,-13,D_UP},
60 {-13,0,-13,0,D_LEFT},
61 {0,13,0,13,D_DOWN},
62 {13,0,13,0,D_RIGHT},
63 };
64
65 GPadLoc decoder_en_loc[] = {
66 {-24,0,-24,0,D_LEFT},
67 {0,22,0,22,D_DOWN},
68 {22,0,22,0,D_RIGHT},
69 {0,-24,0,-24,D_UP},
70 };
71
72 GPadLoc decoder_en_altloc[] = {
73 {22,0,22,0,D_RIGHT},
74 {0,-24,0,-24,D_UP},
75 {-24,0,-24,0,D_LEFT},
76 {0,22,0,22,D_DOWN},
77 };
78
79 static char *psDecoder[] = {
80 "%",
81 "% x y r decoder",
82 "%",
83 "/decoder {",
84 " startgate",
85 " 8 rfont",
86 " (dec) 0 5 rCT",
87 " -16.5 12.5 moveto",
88 " 16.5 12.5 lineto",
89 " 29.5 -15.5 lineto",
90 " -29.5 -15.5 lineto",
91 " closepath stroke",
92 " dup % n n",
93 " 1 add 58 exch div % n d1",
94 " 2 copy mul % n d1 dn",
95 " 3 -1 roll 1 sub 50 string cvs exch % d1 (n) dn",
96 " -29 add -12 rCT % d1",
97 " (0) exch -29 add -12 rCT",
98 " grestore",
99 "} def",
100 0
101 };
102
103 GGateInfo gate_decoder_info = {
104 0,
105 "DECODER",
106 "decoder",0x0,
107 "decoder",psDecoder,
108 2,2,
109
110 { {"D 2", {"gm.msi",0}, {"gm.msi.12dec",0,"xdecode",100}, "gat_make DECODER "},
111 {"D 3", {0,0}, {0,0,0,0}, "gat_make DECODER -pins Z=3"},
112 {"D 4", {"gm.msi",0}, {"gm.msi.14dec",0,"xdecode",200}, "gat_make DECODER -pins Z=4"},
113 {"D 5", {0,0}, {0,0,0,0}, "gat_make DECODER -pins Z=5"},
114 {"D 6", {0,0}, {0,0,0,0}, "gat_make DECODER -pins Z=6"},
115 {"D 7", {0,0}, {0,0,0,0}, "gat_make DECODER -pins Z=7"},
116 {"D 8", {"gm.msi",0}, {"gm.msi.18dec",0,"xdecode",300}, "gat_make DECODER -pins Z=8"},
117 {"D 9", {0,0}, {0,0,0,0}, "gat_make DECODER -pins Z=9"},
118 {0}},
119
120 decoder_iconDims,
121
122 3,{{"I",IN,1,1,decoder_in_loc,0},
123 {"E",IN,1,1,decoder_en_loc,0},
124 {"Z",OUT,1,2,decoder_out_loc,1}},
125 {{23,0,LJ},{0,40,CT},{-23,8,RJ},{0,-33,CT}},
126 {1},
127
128 {"Dez","Diz",0},
129
130 Decoder_Make,
131 Decoder_WriteCellDef,
132 Generic_Init,
133 Decoder_Delete,
134 Generic_GetExtents,
135 Generic_HitDistance,
136 Decoder_Draw,
137 Generic_Move,
138 MuxDemux_Copy,
139 Err_AddInput,
140 Decoder_AddOutput,
141 Err_AddInOut,
142 Decoder_Rotate,
143 Err_RemovePort,
144 Err_ChangePin,
145 Nop_SimInitFunc,
146 Nop_SimHitFunc,
147 Decoder_PSWrite,
148 MuxDemux_EditProps,
149 MuxDemux_VerSave,
150 Decoder_SetProp,
151
152 Decoder_VersionDelta,
153 Decoder_wireSnap
154 };
155
156 /*
157 * Adjust the wires on a mux to conform to the current setting of data_order
158 */
Decoder_adjustWiresData(GCElement * g)159 static void Decoder_adjustWiresData(GCElement *g)
160 {
161 int N,L,i;
162 double dx,dy,wx,wy;
163 GWire *w;
164 GPadLoc *pd = &g->typeinfo->Pad[DECODER_OUT].Loc[g->orient];
165
166
167 wx = wy = dx = dy = 0;
168 N = wire_numOnPad(g->wires[DECODER_OUT]);
169 L = iabs(pd->x1-pd->x2) + iabs(pd->y1-pd->y2); /* Length of pad (assumed non-diagonal) */
170
171 wx = g->xpos + pd->x1;
172 wy = g->ypos + pd->y1;
173
174 switch (g->orient) {
175 case 0 :
176 dx = (double)L/(double)(N+1);
177 if (g->u.mux.data_order) {
178 wx = g->xpos + pd->x2;
179 dx = -dx;
180 }
181 break;
182 case 1 :
183 dy = (double)L/(double)(N+1);
184 if (!g->u.mux.data_order) {
185 wy = g->ypos + pd->y2;
186 dy = -dy;
187 }
188 break;
189 case 2 :
190 dx = (double)L/(double)(N+1);
191 if (!g->u.mux.data_order) {
192 wx = g->xpos + pd->x2;
193 dx = -dx;
194 }
195 break;
196 case 3 :
197 dy = (double)L/(double)(N+1);
198 if (g->u.mux.data_order) {
199 wy = g->ypos + pd->y2;
200 dy = -dy;
201 }
202 break;
203 }
204
205 for (i = 0,w = g->wires[DECODER_OUT];w;i++, w = w->next) {
206 wx += dx;
207 wy += dy;
208 wire_move(w->nodes,(int)wx-w->nodes->x,(int)wy-w->nodes->y,VERTICAL|HORIZONTAL);
209 }
210 }
211
212 /*
213 * Adjust the wires on a mux to conform to the current setting of select_side
214 */
Decoder_adjustWiresSelector(GCElement * g)215 static void Decoder_adjustWiresSelector(GCElement *g)
216 {
217 int wx,wy;
218 GPadLoc *pd = &g->typeinfo->Pad[DECODER_EN].Loc[g->orient];
219 GWire *w = g->wires[DECODER_EN];
220 GWire *ow = wire_other(w);
221
222 if (g->u.mux.select_side)
223 pd = &decoder_en_altloc[g->orient];
224
225 wx = g->xpos + pd->x2;
226 wy = g->ypos + pd->y2;
227
228 ob_touch(w);
229 wire_move(w->nodes,wx-w->nodes->x,wy-w->nodes->y,VERTICAL|HORIZONTAL);
230
231 /*
232 * If wire end is not attached, compute mirror image. Otherwise use brute force
233 * to fix the wire.
234 */
235 if (w->orient != pd->dir) {
236 w->orient = pd->dir;
237 if (!ow->gate) {
238 int cx = w->nodes->x;
239 int cy = w->nodes->y;
240 GWireNode *n;
241
242
243 for (n = w->driver->nodes;n;n = n->out) {
244 ob_touch(n);
245 if (g->orient == 0 || g->orient == 2)
246 n->x = cx - (n->x - cx);
247 else
248 n->y = cy - (n->y - cy);
249 }
250 } else
251 GWire_snap(w->driver);
252 }
253 }
254
255 /*
256 * Adjust the wires on a mux.
257 */
Decoder_adjustWires(GCElement * g)258 void Decoder_adjustWires(GCElement *g)
259 {
260 Decoder_adjustWiresData(g);
261 Decoder_adjustWiresSelector(g);
262 }
263
264
Decoder_Make(EditState ** es,GModuleDef * env,int GType,int x,int y,int r,const char * Name,int noWires,const char ** options,int nOptions)265 static GCElement *Decoder_Make(EditState **es,GModuleDef *env,int GType,
266 int x,int y,int r,const char *Name,int noWires,const char **options,int nOptions)
267 {
268 int nbits;
269 GCElement *g;
270 GWire *w;
271
272 if (!(g = Generic_Make(es,env,GType,x,y,r,Name,1,options,nOptions)))
273 return NULL;
274
275 g->u.mux.select_side = 0;
276 g->u.mux.data_order = 0;
277
278 if (!noWires) {
279 int i,j;
280 const char *Invert,*Pins;
281 int N = GCElement_numPads(g);
282
283
284 Invert = seekOption("-invert",options,nOptions);
285 Pins = seekOption("-pins",options,nOptions);
286
287 for (i = 0;i < N;i++) {
288 int Num = 0;
289
290 if (Pins) {
291 char buf[STRMAX];
292 int N;
293 if (sscanf(Pins,"%[^=]=%d",buf,&N) == 2 && strcmp(buf,GCElement_getPadName(g,i)) == 0)
294 Num = N;
295 }
296 if (!Num)
297 Num = GCElement_getPadNum(g,i);
298
299 for (j = 0;j < Num;j++) {
300 if (Invert && strcmp(Invert,GCElement_getPadName(g,i)) == 0)
301 wire_addToGate(g,i,env,1);
302 else
303 wire_addToGate(g,i,env,0);
304 }
305 }
306
307 Decoder_adjustWires(g);
308
309
310 for (i = 0,w = g->wires[DECODER_OUT];w;w = w->next,i++);
311
312 nbits = required_bits(i);
313 net_setSize(g->wires[DECODER_IN]->net,nbits);
314 }
315
316 return g;
317 }
318
Decoder_Draw_Special(GCElement * g)319 static void Decoder_Draw_Special(GCElement *g)
320 {
321 GWire *w,*w0;
322 char n[STRMAX];
323 int i;
324
325 if (g->selected)
326 XSetFont(TkGate.D,TkGate.instGC,TkGate.textbXF[TkGate.circuit->zoom_factor]->fid);
327 else
328 XSetFont(TkGate.D,TkGate.instGC,TkGate.textXF[TkGate.circuit->zoom_factor]->fid);
329
330 if (!(w0 = g->wires[DECODER_OUT])) return;
331 for (i = 0,w = w0;w->next;w = w->next,i++);
332 sprintf(n,"%d",i);
333
334 if (g->selected)
335 XSetFont(TkGate.D,TkGate.instGC,TkGate.stextbXF[TkGate.circuit->zoom_factor]->fid);
336 else
337 XSetFont(TkGate.D,TkGate.instGC,TkGate.stextXF[TkGate.circuit->zoom_factor]->fid);
338
339 switch (g->orient) {
340 case 0 :
341 dce_DrawString(TkGate.instGC,
342 w0->nodes->x,w0->nodes->y - 2,
343 AtBottom|BetweenLeftAndRight,"0");
344 dce_DrawString(TkGate.instGC,
345 w->nodes->x,w->nodes->y - 2,
346 AtBottom|BetweenLeftAndRight,n);
347 break;
348 case 1 :
349 dce_DrawString(TkGate.instGC,
350 w0->nodes->x - 2,w0->nodes->y,
351 BetweenTopAndBottom|AtRight,"0");
352 dce_DrawString(TkGate.instGC,
353 w->nodes->x - 2,w->nodes->y,
354 BetweenTopAndBottom|AtRight,n);
355 break;
356 case 2 :
357 dce_DrawString(TkGate.instGC,
358 w0->nodes->x,w0->nodes->y + 2,
359 AtTop|BetweenLeftAndRight,"0");
360 dce_DrawString(TkGate.instGC,
361 w->nodes->x,w->nodes->y + 2,
362 AtTop|BetweenLeftAndRight,n);
363 break;
364 case 3:
365 dce_DrawString(TkGate.instGC,
366 w0->nodes->x + 3,w0->nodes->y,
367 BetweenTopAndBottom|AtLeft, "0");
368 dce_DrawString(TkGate.instGC,
369 w->nodes->x + 3,w->nodes->y,
370 BetweenTopAndBottom|AtLeft,n);
371 break;
372 }
373 }
374
375
Decoder_Delete(GCElement * g,GModuleDef * env,int drawp)376 static void Decoder_Delete(GCElement *g,GModuleDef *env,int drawp)
377 {
378 Generic_Delete(g,env,drawp);
379 }
380
Decoder_Draw(GCElement * g,int md)381 static void Decoder_Draw(GCElement *g,int md)
382 {
383 Generic_Draw(g,md);
384 Decoder_Draw_Special(g);
385 }
386
387
Decoder_Rotate(GCElement * g,int centX,int centY,int rdir)388 static void Decoder_Rotate(GCElement *g, int centX, int centY,int rdir)
389 {
390 int x = g->xpos;
391 int y = g->ypos;
392
393 ob_touch(g);
394 g->xpos = rotateX(x - centX,y - centY,rdir) + centX;
395 g->ypos = rotateY(x - centX,y - centY,rdir) + centY;
396 g->orient = (g->orient + 4 + rdir) % 4;
397
398 Decoder_adjustWires(g);
399 }
400
401
Decoder_PSWrite(GPrint * P,GModLayout * L,GCElement * g)402 static void Decoder_PSWrite(GPrint *P,GModLayout *L,GCElement *g)
403 {
404 int N;
405 struct wire *w;
406
407 Generic_PSLabels(P,g);
408
409 for (N = 0, w = g->wires[DECODER_OUT];w;w = w->next) N++;
410
411 fprintf(P->p_f,"%d %d %d %d %s\n",
412 N,g->xpos,g->ypos,-g->orient*90,g->typeinfo->psprint);
413 }
414
415
Decoder_SetProp(GCElement * g,const char * prop,const void * value)416 static void Decoder_SetProp(GCElement *g,const char *prop,const void *value)
417 {
418 if (strcmp(prop,"/ss") == 0) g->u.mux.select_side = *((int*)value);
419 if (strcmp(prop,"/do") == 0) g->u.mux.data_order = *((int*)value);
420
421 if (g->wires[DECODER_EN])
422 g->wires[DECODER_EN]->orient = (g->orient + 2 + (g->u.mux.select_side ? 2 : 0) ) % 4;
423 }
424
Decoder_VersionDelta(GCElement * g,Version * V)425 static void Decoder_VersionDelta(GCElement *g,Version *V)
426 {
427 Version x1 = {"1.8.7", 1, 8, 7};
428
429 if (VersionCmp(V,&x1) >= 0)
430 return;
431
432 switch (g->orient) {
433 case D_RIGHT :
434 g->u.mux.select_side = 0;
435 g->u.mux.data_order = 0;
436 g->wires[DECODER_EN]->orient = D_LEFT;
437 break;
438 case D_UP :
439 g->u.mux.select_side = 1;
440 g->u.mux.data_order = 1;
441 g->wires[DECODER_EN]->orient = D_UP;
442 break;
443 case D_LEFT :
444 g->u.mux.select_side = 0;
445 g->u.mux.data_order = 1;
446 g->wires[DECODER_EN]->orient = D_RIGHT;
447 break;
448 case D_DOWN :
449 g->u.mux.select_side = 1;
450 g->u.mux.data_order = 0;
451 g->wires[DECODER_EN]->orient = D_DOWN;
452 break;
453 }
454 }
455
Decoder_wireSnap(GCElement * g,GWire * w,int * mod,int retry)456 static GWireNode *Decoder_wireSnap(GCElement *g,GWire *w,int *mod,int retry)
457 {
458 int p,n;
459
460 if (posongate(w,w->gate,&p,&n) == 0) {
461 GPadLoc *pd = &g->typeinfo->Pad[p].Loc[g->orient];
462 if (p == DECODER_EN && g->u.mux.select_side)
463 pd = &decoder_en_altloc[g->orient];
464
465 *mod = wire_force(w,pd->dir,retry);
466 }
467 return w->nodes;
468 }
469
Decoder_AddOutput(EditState * es,GCElement * g)470 static void Decoder_AddOutput(EditState *es,GCElement *g)
471 {
472 int i;
473 int N = GCElement_numPads(g);
474
475 for (i = 0;i < N;i++)
476 if (GCElement_getPadDir(g,i) == OUT && GCElement_getPadCanAdd(g,i))
477 break;
478
479 if (i == N)
480 return;
481
482 if (es) SetModified(MF_GATE|MF_NET);
483
484 gate_draw(g,GD_NORMAL);
485 wire_addToGate(g,i,es->env,0);
486 Decoder_adjustWires(g);
487 gate_draw(g,GD_NORMAL);
488 }
489
490 /*****************************************************************************
491 *
492 * Generate primitive cell definition for decoderes.
493 *
494 * Parameters:
495 * f File to write cell to.
496 * name Name of cell to write.
497 *
498 *****************************************************************************/
Decoder_WriteCellDef(FILE * f,GCellSpec * gcs)499 static void Decoder_WriteCellDef(FILE *f,GCellSpec *gcs)
500 {
501 int multiPad = gcs->gc_multiPad;
502 int numBits = required_bits(gcs->gc_multiPad);
503 PrimParm primParm;
504 int i;
505
506 PrimParm_init(&primParm);
507 PrimParm_intSet(&primParm,"NUMOUT",multiPad);
508 PrimParm_rangeSet(&primParm,"OUT_RANGE",multiPad);
509 PrimParm_rangeSet(&primParm,"I_RANGE",numBits);
510 PrimParm_intSet(&primParm,"I_BITS",numBits);
511
512 if (!*gcs->gc_invSpec)
513 PrimParm_invSet(&primParm,"invZ",0);
514 else if (!gcs->gc_invSpec[1]) {
515 PrimParm_invSet(&primParm,"invZ",(*gcs->gc_invSpec == 'N'));
516 } else {
517 char *s = PrimParm_get(&primParm,"invZ");
518 sprintf(s,"%d'b",multiPad);
519 s += strlen(s);
520 for (i = 0;i < multiPad;i++) {
521 *s++ = (gcs->gc_invSpec[i] == 'N') ? '1' : '0';
522 }
523 sprintf(s," ^");
524 }
525
526 Primitive_write(f,"decoder",gcs,&primParm);
527 }
528
529
init_decoder()530 void init_decoder()
531 {
532 Pixmap P;
533
534 P = Pixmap_registerFromFile("decoder","decoder.b");
535 gateinfo_iconInit(&gate_decoder_info,P,decoder_iconDims,decoder_iconBoldOffset);
536 RegisterGate(&gate_decoder_info);
537 }
538