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