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