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