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:18:37 2009
19 ****************************************************************************/
20
21 #ifdef __cplusplus
22 #include <cstdlib>
23 #else
24 #include <stdlib.h>
25 #endif
26
27 #include "tkgate.h"
28 #include "print.h"
29
30 GCElement *Tap_Make(EditState **es,GModuleDef *env,int GType,
31 int x,int y,int r,const char *Name,int noWires,const char**,int);
32 void Tap_Draw(GCElement *g,int md);
33 void Tap_Init(GCElement *g);
34 void Tap_PSWrite(GPrint *P,GModLayout*,GCElement *g);
35 void Tap_Delete(GCElement *g,GModuleDef *env,int drawp);
36 void Tap_VerSave(FILE *f,GCElement *g);
37 void Tap_SetProp(GCElement *g,const char *prop,const void *value);
38 int Tap_EditProps(GCElement *g,int isLoadDialog);
39 GCElement *Tap_Copy(GModuleDef *M,GCElement *g,int x,int y,unsigned flags);
40 void Tap_VersionDelta(GCElement*,Version*);
41 GWireNode *Tap_wireSnap(GCElement *g,GWire *w,int *mod,int retry);
42
43 #if 0
44 static iconDimensions tap_iconDims[] = {
45 {0, 0, 3, 7, 1, 3},
46 {8, 0, 7, 3, 3, 1},
47 {4, 0, 3, 7, 1, 3},
48 {8, 4, 7, 3, 3, 1},
49 };
50 #endif
51
52 static iconDimensions tap_iconDims[] = {
53 {0, 0, 3, 7, 2, 3},
54 {8, 0, 7, 3, 3, 2},
55 {4, 0, 3, 7, 2, 3},
56 {8, 4, 7, 3, 3, 2},
57 };
58 static int tap_iconBoldOffset = 8;
59
60 GPadLoc tap_in_loc[] = {
61 {-3,0,-3,0,D_UP},
62 {0,2,0,2,D_LEFT},
63 {2,0,2,0,D_DOWN},
64 {0,-3,0,-3,D_RIGHT}};
65
66 GPadLoc tap_out_loc[] = {
67 {-3,1,-3,1,D_DOWN},
68 {1,2,1,2,D_RIGHT},
69 {2,-1,2,-1,D_UP},
70 {-1,-3,-1,-3,D_LEFT}};
71 #if 0
72 GPadLoc tap_tap_loc[] = {
73 {2,0,2,0,D_RIGHT},
74 {0,-2,0,-2,D_UP},
75 {-2,0,-2,0,D_LEFT},
76 {0,2,0,2,D_DOWN}};
77 #endif
78 GPadLoc tap_tap_loc[] = {
79 {2,0,2,0,D_RIGHT},
80 {0,-2,0,-2,D_UP},
81 {-2,0,-2,0,D_LEFT},
82 {0,2,0,2,D_DOWN}};
83
84
85 static char *psTap[] = {
86 "%",
87 "% A Splice",
88 "/pstap {",
89 " [[-2 0][0 -1][-1 0][0 -2]] adjstartgate",
90 " -4 -3 moveto",
91 " -2 -3 lineto",
92 " 2 0 lineto",
93 " -2 3 lineto",
94 " -4 3 lineto",
95 " 8 rfont",
96 " 4 4 moveto show",
97 " closepath fill",
98 " grestore",
99 "} def",
100 0
101 };
102
103
104 GGateInfo gate_tap_info = {
105 GC_TAP,
106 "TAP",
107 "tran",0x0,
108 "pstap",psTap,
109 -1,-1,
110
111 {{0}},
112
113 tap_iconDims,
114
115 3,{{"Z",OUT,1,1,tap_tap_loc},
116 {"I",TRI,8,1,tap_in_loc},
117 {"D",TRI,8,1,tap_out_loc}},
118 {{5,-5,LJ},{-5,-5,RJ},{-5,-5,RJ},{-5,10,RJ}},
119 {1,1},
120
121 {0},
122
123 Tap_Make,
124 Nop_WriteCellDef,
125 Tap_Init,
126 Tap_Delete,
127 Generic_GetExtents,
128 Generic_HitDistance,
129 Tap_Draw,
130 Generic_Move,
131 Tap_Copy,
132 Err_AddInput,
133 Err_AddOutput,
134 Err_AddInOut,
135 Generic_Rotate,
136 Err_RemovePort,
137 Err_ChangePin,
138 Nop_SimInitFunc,
139 Nop_SimHitFunc,
140 Tap_PSWrite,
141 Tap_EditProps,
142 Tap_VerSave,
143 Tap_SetProp,
144 Tap_VersionDelta,
145 Tap_wireSnap
146 };
147
Tap_Make(EditState ** es,GModuleDef * env,int GType,int x,int y,int r,const char * Name,int noWires,const char ** options,int nOptions)148 GCElement *Tap_Make(EditState **es,GModuleDef *env,int GType,
149 int x,int y,int r,const char *Name,int noWires,const char **options,int nOptions)
150 {
151 GCElement *g;
152 const char *Side,*Range;
153
154 if (!(g = Generic_Make(es,env,GType,x,y,r,Name,noWires,options,nOptions)))
155 return NULL;
156
157 Side = seekOption("-side",options,nOptions);
158 Range = seekOption("-range",options,nOptions);
159
160 if (!Side || sscanf(Side,"%d",&g->u.tap.spliceside) != 1)
161 g->u.tap.spliceside = 0;
162
163 if (!Range || sscanf(Range,"%d:%d",&g->u.tap.msb,&g->u.tap.lsb) != 2) {
164 if (g->wires[TAP_TAP])
165 g->u.tap.msb = g->wires[TAP_TAP]->net->n_nbits - 1;
166 else
167 g->u.tap.msb = 0;
168 g->u.tap.lsb = 0;
169 }
170
171 return g;
172 }
173
Tap_Copy(GModuleDef * M,GCElement * g,int x,int y,unsigned flags)174 GCElement *Tap_Copy(GModuleDef *M,GCElement *g,int x,int y,unsigned flags)
175 {
176 GCElement *ng;
177
178 ng = Generic_Copy(M,g,x,y,flags);
179 ob_touch(ng);
180
181 ng->u.tap.msb = g->u.tap.msb;
182 ng->u.tap.lsb = g->u.tap.lsb;
183 ng->u.tap.spliceside = g->u.tap.spliceside;
184
185 return ng;
186 }
187
Tap_Init(GCElement * g)188 void Tap_Init(GCElement *g)
189 {
190 ob_touch(g);
191 g->u.tap.msb = g->u.tap.lsb = 0;
192 g->u.tap.spliceside = 0;
193 }
194
195 /*
196 * Deleting a tap differs in that instead of cutting off all of the wires, the
197 * TAP_IN and TAP_OUT connections need to be reattached. However, if these
198 * wires are not connected to anything, then the whole structure should be
199 * deleted.
200 */
Tap_Delete(GCElement * g,GModuleDef * M,int drawp)201 void Tap_Delete(GCElement *g,GModuleDef *M,int drawp)
202 {
203 GWire *iw = g->wires[TAP_IN];
204 GWire *ow = g->wires[TAP_OUT];
205 GWire *o_iw;
206 GWire *o_ow;
207 GNet *net;
208
209 net = iw ? iw->net : (ow ? ow->net : 0);
210 if (drawp) GNet_draw(net);
211
212 if (iw) {
213 ob_touch(iw);
214 iw->gate = 0;
215 o_iw = wire_other(iw);
216 } else
217 o_iw = 0;
218
219 if (ow) {
220 ob_touch(ow);
221 ow->gate = 0;
222 o_ow = wire_other(ow);
223 } else
224 o_ow = 0;
225
226
227 ob_touch(g);
228 g->wires[TAP_IN] = 0;
229 g->wires[TAP_OUT] = 0;
230
231 if (iw && ow) {
232 if (o_iw->gate || o_ow->gate) {
233 /*
234 * If either end is connected to a gate, rejoin the wires
235 */
236
237 ob_touch(M);
238 M->m_wires = wire_unlink(M->m_wires,iw);
239 M->m_wires = wire_unlink(M->m_wires,ow);
240
241 if (iw->nodes->out && ow->nodes->out)
242 join_treereverse(ow);
243
244 if (iw->nodes->out && ow->nodes->in) {
245 ob_touch(ow->nodes);
246 ob_touch(iw->nodes);
247 ob_touch(o_iw);
248 ow->nodes->out = iw->nodes;
249 iw->nodes->in = ow->nodes;
250 o_iw->driver = ow->driver;
251 } else if (ow->nodes->out && iw->nodes->in) {
252 ob_touch(ow->nodes);
253 ob_touch(iw->nodes);
254 ob_touch(o_iw);
255 ow->nodes->in = iw->nodes;
256 iw->nodes->out = ow->nodes;
257 o_ow->driver = iw->driver;
258 } else
259 printf("huh! at %s, %d\n",__FILE__, __LINE__);
260
261 iw->nodes->x = ow->nodes->x;
262 iw->nodes->y = ow->nodes->y;
263
264 ob_touch(iw->nodes);
265 ob_touch(ow->nodes);
266 ob_touch(net);
267 ow->nodes->end = 0;
268 iw->nodes->end = 0;
269
270 GWire_snap(wirenode_driver(ow->nodes));
271
272 if (net->n_driver == iw) {
273 net->n_driver = o_iw;
274 } else if (net->n_driver == ow) {
275 net->n_driver = o_ow;
276 }
277 wire_free(iw);
278 wire_free(ow);
279 wire_finalizeNet(net->n_driver);
280 if (drawp) GNet_draw(net);
281 } else {
282 /*
283 * Wire is not connected to anything else, delete it entirely.
284 */
285 #if 0
286 GWire_draw(iw->driver);
287 GWire_draw(ow->driver);
288 #endif
289 wire_nuke(iw,0,M);
290 wire_nuke(ow,0,M);
291 }
292 }
293 Generic_Delete(g,M,drawp);
294 }
295
296 /* Used by Draw and PSDraw */
297 static short dx[] = {-1,0,1,0};
298 static short dy[] = {0,1,0,-1};
299
Tap_Draw(GCElement * g,int md)300 void Tap_Draw(GCElement *g,int md)
301 {
302 int o,x,y;
303 char buf[STRMAX];
304
305 if (!g->u.tap.spliceside)
306 mk_gate(g->xpos,g->ypos,g->typeinfo,g->orient,g->selected);
307 else {
308 mk_gate(g->xpos+5*dx[g->orient],g->ypos+5*dy[g->orient],
309 g->typeinfo,(g->orient+2)%4,g->selected);
310 }
311
312 gate_drawWires(g,md);
313
314 if (!g->ename) return;
315
316
317 o = (g->orient + 2*g->u.tap.spliceside) % 4;
318 if (g->u.tap.spliceside) {
319 x = g->xpos+5*dx[g->orient];
320 y = g->ypos+5*dy[g->orient];
321 } else {
322 x = g->xpos;
323 y = g->ypos;
324 }
325
326 if (g->u.tap.lsb == g->u.tap.msb)
327 sprintf(buf,"%d",g->u.tap.msb);
328 else
329 sprintf(buf,"%d:%d",g->u.tap.msb,g->u.tap.lsb);
330
331 if (g->selected)
332 XSetFont(TkGate.D,TkGate.instGC,TkGate.stextbXF[TkGate.circuit->zoom_factor]->fid);
333 else
334 XSetFont(TkGate.D,TkGate.instGC,TkGate.stextXF[TkGate.circuit->zoom_factor]->fid);
335 dce_DrawString(TkGate.instGC,x + g->typeinfo->lpos[o].x,
336 y + g->typeinfo->lpos[o].y,
337 g->typeinfo->lpos[o].just,buf);
338 }
339
Tap_PSWrite(GPrint * P,GModLayout * L,GCElement * g)340 void Tap_PSWrite(GPrint *P,GModLayout *L,GCElement *g)
341 {
342 int O;
343 char buf[STRMAX];
344
345 O = (g->orient + (g->u.tap.spliceside ? 2 : 0)) % 4;
346
347 Generic_PSLabels(P,g);
348
349 if (g->u.tap.lsb == g->u.tap.msb)
350 sprintf(buf,"%d",g->u.tap.msb);
351 else
352 sprintf(buf,"%d:%d",g->u.tap.msb,g->u.tap.lsb);
353
354 if (!g->u.tap.spliceside)
355 fprintf(P->p_f,"(%s) %d %d %d %s\n",buf,g->xpos,g->ypos,-O*90,g->typeinfo->psprint);
356 else
357 fprintf(P->p_f,"(%s) %d %d %d %s\n",buf,g->xpos+7*dx[g->orient],g->ypos+7*dy[g->orient],
358 -O*90,g->typeinfo->psprint);
359 }
360
Tap_VerSave(FILE * f,GCElement * g)361 void Tap_VerSave(FILE *f,GCElement *g)
362 {
363 if (g->u.tap.msb != g->u.tap.lsb)
364 fprintf(f," assign %s = %s[%d:%d]; //: TAP %s",
365 g->wires[TAP_TAP]->net->n_signame,
366 g->wires[TAP_IN]->net->n_signame,
367 g->u.tap.msb,g->u.tap.lsb,
368 g->ename);
369 else
370 fprintf(f," assign %s = %s[%d]; //: TAP %s",
371 g->wires[TAP_TAP]->net->n_signame,
372 g->wires[TAP_IN]->net->n_signame,
373 g->u.tap.msb,
374 g->ename);
375
376 VerilogBasicGateComment(f,g,0);
377 fprintf(f," /ss:%d",g->u.tap.spliceside);
378 fprintf(f,"\n");
379 }
380
Tap_SetProp(GCElement * g,const char * prop,const void * value)381 void Tap_SetProp(GCElement *g,const char *prop,const void *value)
382 {
383 if (strcmp(prop,"/ss") == 0) {
384 int n = *((int*)value);
385 ob_touch(g);
386 g->u.tap.spliceside = n;
387 }
388 }
389
Tap_EditProps(GCElement * g,int isLoadDialog)390 int Tap_EditProps(GCElement *g,int isLoadDialog)
391 {
392 Tcl_Interp *tcl = TkGate.tcl;
393
394 ob_touch(g);
395
396 Generic_EditProps(g,isLoadDialog);
397 if (isLoadDialog) {
398 if (g->u.tap.msb == g->u.tap.lsb)
399 DoTcl("set ::edgat_tap \"%d\"",g->u.tap.msb);
400 else
401 DoTcl("set ::edgat_tap \"%d:%d\"",g->u.tap.msb,g->u.tap.lsb);
402 } else {
403 const char *p;
404 int msb,lsb;
405
406 if ((p = Tcl_GetVar(tcl,"edgat_tap",TCL_GLOBAL_ONLY))) {
407 if (sscanf(p,"%d:%d",&msb,&lsb) == 2) {
408 g->u.tap.msb = msb;
409 g->u.tap.lsb = lsb;
410 } else if (sscanf(p,"%d",&msb) == 1) {
411 g->u.tap.msb = g->u.tap.lsb = msb;
412 }
413 }
414 }
415 return 0;
416 }
417
418 /*
419 * Tweek positions of wires for versions before 1.6
420 */
Tap_VersionDelta(GCElement * g,Version * V)421 void Tap_VersionDelta(GCElement *g,Version *V)
422 {
423 Version x1 = {"1.6", 1, 6, 0};
424 int dx = 0,dy = 0,o;
425 GWire *w = g->wires[TAP_TAP];
426
427 if (VersionCmp(V,&x1) >= 0)
428 return;
429
430 o = wireorient(w->nodes,0);
431
432 if (g->u.tap.spliceside)
433 o = (o+2)%4;
434
435 switch (o) {
436 case 0 :
437 dx = -1;
438 dy = 0;
439 break;
440 case 1 :
441 dx = 0;
442 dy = -1;
443 break;
444 case 2 :
445 dx = -1;
446 dy = 0;
447 break;
448 case 3 :
449 dx = 0;
450 dy = -1;
451 break;
452 }
453
454 ob_touch(w->nodes);
455 w->nodes->x += dx;
456 w->nodes->y += dy;
457 }
458
Tap_wireSnap(GCElement * g,GWire * w,int * mod,int retry)459 GWireNode *Tap_wireSnap(GCElement *g,GWire *w,int *mod,int retry)
460 {
461 int p,n;
462 static short dx[] = {-9,0,9,0};
463 static short dy[] = {0,9,0,-9};
464
465 if (posongate(w,w->gate,&p,&n) != 0)
466 return w->nodes;
467
468 switch (p) {
469 case TAP_IN :
470 case TAP_OUT :
471 *mod = wire_force(w,
472 w->gate->typeinfo->Pad[p].Loc[w->gate->orient].dir,
473 retry);
474 break;
475 case TAP_TAP :
476 if (w->gate->u.tap.spliceside !=
477 (w->gate->typeinfo->Pad[p].Loc[w->gate->orient].dir !=
478 wireorient(w->nodes,0))) {
479
480 gate_draw(w->gate,0);
481 ob_touch(w->gate);
482 w->gate->u.tap.spliceside =
483 w->gate->typeinfo->Pad[p].Loc[w->gate->orient].dir!=
484 wireorient(w->nodes,0);
485
486 gate_draw(w->gate,0);
487 if (w->gate->u.tap.spliceside)
488 wire_move(w->nodes,dx[w->gate->orient],
489 dy[w->gate->orient],VERTICAL | HORIZONTAL);
490 else
491 wire_move(w->nodes,-dx[w->gate->orient],
492 -dy[w->gate->orient],VERTICAL | HORIZONTAL);
493 }
494 break;
495 }
496
497 return w->nodes;
498 }
499
500
501 /*
502 Change the joint at the end of 'branch' into a splice.
503 */
tap_transmute(GWire * branch,EditState * es)504 void tap_transmute(GWire *branch,EditState *es)
505 {
506 /** @TODO to remove*/
507 /* GModuleDef *env; */
508 GWire *in,*out;
509 GCElement *g;
510 int i,o;
511 int tap_dx = 0,tap_dy = 0;
512
513 g = branch->gate;
514 /** @TODO to remove */
515 /* env = es->env; */
516 #ifdef JOIN_DRAW
517 gate_draw(g,0);
518 #endif
519 in = out = NULL;
520
521 for (i = 0;i < 4;i++)
522 if (g->wires[i] &&
523 (g->wires[i] != branch)) {
524 if (out)
525 in = g->wires[i];
526 else
527 out = g->wires[i];
528 }
529
530 ob_touch(g);
531 g->typeinfo = GGateInfo_codeLookup(GC_TAP);
532 g->wires[TAP_IN] = in;
533 g->wires[TAP_OUT] = out;
534 g->wires[TAP_TAP] = branch;
535
536 g->u.tap.msb = g->wires[TAP_TAP]->net->n_nbits - 1;
537 g->u.tap.lsb = 0;
538
539 o = wireorient(out->nodes,0);
540 g->orient = (o=(o+1)%4);
541 g->u.tap.spliceside =
542 g->typeinfo->Pad[TAP_TAP].Loc[o].dir !=
543 wireorient(branch->nodes,0);
544
545 switch (o) {
546 case 0 :
547 g->xpos += 3;
548 wire_move(out->nodes,0,-2,FULL|NOSTRAIGHTEN);
549 wire_move(in->nodes,0,1,FULL|NOSTRAIGHTEN);
550 tap_dx = g->u.tap.spliceside ? -2 : 3;
551 tap_dy = 0;
552 break;
553 case 1 :
554 g->ypos -= 2;
555 wire_move(out->nodes,-2,0,FULL|NOSTRAIGHTEN);
556 wire_move(in->nodes,1,0,FULL|NOSTRAIGHTEN);
557 tap_dx = 0;
558 tap_dy = g->u.tap.spliceside ? 2 : -3;
559 break;
560 case 2 :
561 g->xpos -= 2;
562 wire_move(out->nodes,0,1,FULL|NOSTRAIGHTEN);
563 wire_move(in->nodes,0,-2,FULL|NOSTRAIGHTEN);
564 tap_dx = g->u.tap.spliceside ? 2 : -3;
565 tap_dy = 0;
566 break;
567 case 3 :
568 g->ypos += 3;
569 wire_move(out->nodes,1,0,FULL|NOSTRAIGHTEN);
570 wire_move(in->nodes,-2,0,FULL|NOSTRAIGHTEN);
571 tap_dx = 0;
572 tap_dy = g->u.tap.spliceside ? -2 : 3;
573 break;
574 }
575 wire_move(branch->nodes,tap_dx,tap_dy,FULL|NOSTRAIGHTEN);
576
577
578 GWire_snap(branch);
579 GWire_snap(out);
580 GWire_snap(in->driver);
581 #ifdef JOIN_DRAW
582 gate_draw(g,0);
583 #endif
584 }
585
init_tap()586 void init_tap()
587 {
588 Pixmap P;
589
590 P = Pixmap_registerFromFile("tap","tap.b");
591 gateinfo_iconInit(&gate_tap_info,P,tap_iconDims,tap_iconBoldOffset);
592 RegisterGate(&gate_tap_info);
593 }
594