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