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 Sun Feb 22 16:55:03 2009
19 ****************************************************************************/
20 
21 #ifdef __cplusplus
22 #include <cstdlib>
23 #include <cstring>
24 #else
25 #include <stdlib.h>
26 #include <string.h>
27 #endif
28 
29 #include <unistd.h>
30 
31 #include "tkgate.h"
32 #include "print.h"
33 #include "yybasic.h"
34 
35 #define BLOCK_STUBLEN	15
36 
37 
38 #define NUMSQRS 10
39 #define NUMSTEPS 15
40 
41 #define on_edge(x,y,bx1,by1,bx2,by2) (bx1 == bx2 ? \
42    ((abs((bx1)-(x)) < 10) && ((y) > (by1)) && ((y) < (by2))) : \
43    ((abs((by1)-(y)) < 10) && ((x) > (bx1)) && ((x) < (bx2))))
44 
45 GPadLoc block_right_loc[]  = {{0,0,0,0,D_RIGHT}};
46 GPadLoc block_top_loc[]    = {{0,0,0,0,D_UP}};
47 GPadLoc block_left_loc[]   = {{0,0,0,0,D_LEFT}};
48 GPadLoc block_bottom_loc[] = {{0,0,0,0,D_DOWN}};
49 
50 extern int baderp;
51 extern int startrekp;
52 extern int GlobalElementCount;
53 
54 GCElement *Block_Make(EditState **es,GModuleDef *env,int GType,
55 		      int x,int y,int r,const char *Name,int noWire,const char **options,int nOptions);
56 int Block_HitDistance(GCElement *g,int x,int y);
57 void Block_Init(GCElement *g);
58 void Block_Move(GCElement *g,int x,int y);
59 int Block_SimHitFunc(EditState*,GCElement*);
60 
61 void Block_Delete(GCElement *g,GModuleDef *env,int drawp);
62 void Block_Draw(GCElement *g,int md);
63 void Block_GetExtents(GCElement *g,TargetDev_e target,int *minx,int *miny,int *maxx,int *maxy,int *bd);
64 GCElement *Block_Copy(GModuleDef *,GCElement *g,int x,int y,unsigned flags);
65 int Block_EditProps(GCElement *g,int isLoadDialog);
66 void Block_VerSave(FILE*,GCElement*);
67 void Block_Rotate(GCElement*,int,int,int rdir);
68 int Block_HitDistance(GCElement*g,int,int);
69 void Block_AddInput(EditState *es,GCElement *g);
70 void Block_AddOutput(EditState *es,GCElement *g);
71 void Block_AddTri(EditState *es,GCElement *g);
72 void Block_ChangePin(EditState *es,GCElement *g);
73 void Block_PSWrite(GPrint *P,GModLayout*,GCElement *g);
74 GWireNode *Block_wireSnap(GCElement *g,GWire *w,int *mod,int retry);
75 
76 void Block_setParmPort(GCElement *g,const char *parmName,const char *newValue);
77 void Block_unsetParmPort(GCElement *g,const char *parmName);
78 const char *Block_getParmPort(GCElement *g,const char *name);
79 
80 
81 /*
82      ANY TRI IN  OUT
83      <>  <>  <   >	Right
84      ^v  ^v  v   ^      Up
85      <>  <>  >   <	Left
86      ^v  ^v  v   ^	Down
87 */
88 
89 GGateInfo gate_block_info = {
90   GC_BLOCK,
91   "MODULE",
92   "block",0x0,
93   "barf",0,
94   -1,-1,
95 
96   {{"B",	{"gm.mod",2},		{"gm.mod.inst",0,0,100},	"gat_make MODULE"},
97    {0}},
98 
99   0,
100 
101   12,{{"Ti",IN,0,0,block_top_loc},
102 	{"Li",IN,0,0,block_left_loc},
103 	{"Bi",IN,0,0,block_bottom_loc},
104 	{"Ri",IN,0,0,block_right_loc},
105 	{"To",OUT,0,0,block_top_loc},
106 	{"Lo",OUT,0,0,block_left_loc},
107 	{"Bo",OUT,0,0,block_bottom_loc},
108 	{"Ro",OUT,0,0,block_right_loc},
109 	{"Tt",TRI,0,0,block_top_loc},
110 	{"Lt",TRI,0,0,block_left_loc},
111 	{"Bt",TRI,0,0,block_bottom_loc},
112 	{"Rt",TRI,0,0,block_right_loc}},
113   {{0,0,CT},{0,0,CT},{0,0,CT},{0,0,CT}},
114   {0,1,0,0,1},
115 
116   {0},
117 
118   Block_Make,
119   Nop_WriteCellDef,
120   Block_Init,
121   Block_Delete,
122   Block_GetExtents,
123   Block_HitDistance,
124   Block_Draw,
125   Block_Move,
126   Block_Copy,
127   Block_AddInput,
128   Block_AddOutput,
129   Block_AddTri,
130   Block_Rotate,
131   Err_RemovePort,
132   Block_ChangePin,
133   Nop_SimInitFunc,
134   Block_SimHitFunc,
135   Block_PSWrite,
136   Block_EditProps,
137   Block_VerSave,
138   0,
139   0,
140   Block_wireSnap
141 };
142 
143 
144 /*
145    Replicate the wire list of a block
146 */
block_repwirelist(GModuleDef * M,GCElement * g,GWire * w,int nx,int ny,int x,int y)147 static GWire *block_repwirelist(GModuleDef *M,GCElement *g,GWire *w,int nx,int ny,int x,int y)
148 {
149   GWire *nw;
150   GWire *cw;
151   GWire *oew;
152 
153   nw = NULL;
154   for (;w;w = w->next) {
155     if (M) {
156       GWire *w1,*w2;
157 
158       wire_new(M,&w1,&w2);
159       cw = w->nodes->in ? w2 : w1;
160       oew = (!w->nodes->in) ? w2 : w1;
161     } else {
162       GWire *w1,*w2;
163 
164       wire_new(NULL,&w1,&w2);
165       cw = w->nodes->in ? w2 : w1;
166       oew = (!w->nodes->in) ? w2 : w1;
167     }
168     ob_touch(cw);
169     ob_touch(cw->nodes);
170     ob_touch(cw->net);
171     ob_touch(oew);
172 
173     cw->orient = w->orient;
174     cw->gate = g;
175 
176     cw->net->n_dtype = w->net->n_dtype;
177     net_setSize(cw->net,w->net->n_nbits);
178 
179     cw->offset = w->offset;
180     oew->wtype = cw->wtype = w->wtype;
181     cw->nodes->x = w->nodes->x + nx - x;
182     cw->nodes->y = w->nodes->y + ny - y;
183     cw->next = nw;
184     nw = cw;
185     cw->name = ob_strdup(w->name);
186 
187     block_canonicalizewire(g,cw);
188 
189     cw = w->nodes->out ? cw->nodes->out->end : cw->nodes->in->end;
190     ob_touch(cw->nodes);
191 
192     if (cw->nodes->x == nw->nodes->x)
193       cw->nodes->y = nw->nodes->y > cw->nodes->y ? nw->nodes->y - BLOCK_STUBLEN : nw->nodes->y + BLOCK_STUBLEN;
194     else
195       cw->nodes->x = nw->nodes->x > cw->nodes->x ? nw->nodes->x - BLOCK_STUBLEN : nw->nodes->x + BLOCK_STUBLEN;
196 
197     wire_finalizeNet(cw);
198   }
199   return nw;
200 }
201 
block_replicatewires(GCElement * ng,GCElement * g,GModuleDef * M)202 static void block_replicatewires(GCElement *ng,GCElement *g,GModuleDef *M)
203 {
204   int N = GCElement_numPads(g);
205   int i;
206 
207   ob_touch(ng);
208   for (i = 0;i < N;i++)
209     ng->wires[i] =  block_repwirelist(M,ng,g->wires[i],
210 				      ng->xpos,ng->ypos,g->xpos,g->ypos);
211 }
212 
213 /*
214 Creates a duplicated copy of block g.  (Assuming g is a block)
215 */
Block_Copy(GModuleDef * M,GCElement * g,int x,int y,unsigned flags)216 GCElement *Block_Copy(GModuleDef *M,GCElement *g,int x,int y,unsigned flags)
217 {
218   GCElement *ng;
219 
220   ng = gate_new(x,y,g->orient,g->typeinfo->code);
221   if (M)
222     gate_add(M,ng);
223 
224   ob_touch(ng);
225   ng->u.block.gheight = g->u.block.gheight;
226   ng->u.block.gwidth = g->u.block.gwidth;
227   ng->orient = g->orient;
228 
229   if (g->ename)
230     gate_setName(ng,g->ename,M);
231   ng->u.block.moduleName = ob_strdup(g->u.block.moduleName);
232   ng->enumb = GlobalElementCount++;
233   ng->show_name = g->show_name;
234 
235   if (!(flags & REP_NOWIRES))
236     block_replicatewires(ng,g,M);
237 
238   return ng;
239 }
240 
Block_Make(EditState ** es,GModuleDef * PM,int GType,int x,int y,int r,const char * Name,int noWire,const char ** options,int nOptions)241 GCElement *Block_Make(EditState **es,GModuleDef *PM,int GType,
242 		      int x,int y,int r,const char *Name,int noWire,
243 		      const char **options,int nOptions)
244 {
245   GCElement *g,*copy;
246   const char *Func,*Size,*DoInit;
247   int W,H;
248 
249   if (!(g = Generic_Make(es,PM,GType,x,y,r,Name,noWire,options,nOptions)))
250     return NULL;
251 
252   Func = seekOption("-func",options,nOptions);		/* The block function */
253   Size = seekOption("-size",options,nOptions);		/* The initial size */
254   DoInit = seekOption("-doinit",options,nOptions);	/* Should we automatically copy bock description? */
255 
256 
257   ob_touch(g);
258 
259   if (Func) {
260     g->u.block.moduleName = ob_strdup(Func);
261 
262     /*
263      * This option is used by the drag-and-drop module creation feature.
264      */
265     if (DoInit && *DoInit == '1') {
266       /** @TODO to remove */
267       /* GModuleDef *M; */
268 
269       env_checkname(g);
270       /** @TODO to remove */
271       /* M = env_findModule(g->u.block.moduleName); */
272 
273       copy = env_getInterface(g);			/* Get copy of the block description */
274 
275       if (copy) {
276 	if (GCElement_getType(copy) == GC_SYMBLOCK) {
277 	  g = SymBlock_convert(g,copy->u.block.symbol,PM,1);
278 	} else {					/* Standard block */
279 	  g->u.block.gwidth = copy->u.block.gwidth;
280 	  g->u.block.gheight = copy->u.block.gheight;
281 	  g->xpos -= g->u.block.gwidth/2;
282 	  g->ypos -= g->u.block.gheight/2;
283 	  block_replicatewires(g,copy,(*es)->env);
284 	}
285       }
286     }
287   } else if (es) {
288     GGateInfo *gi = g->typeinfo;
289     int ok;
290     const char *temp;
291     /** @TODO to remove */
292     /* GModuleDef *M; */
293 
294     g->selected = 1;
295     g->top = 0;
296     g->bottom = 0;
297     g->right = 0;
298     g->left = 0;
299 
300     g->u.block.moduleName = ob_strdup("");
301     gate_draw(g,GD_NORMAL);
302 
303     Tcl_SetVar(TkGate.tcl,"edgat_newBlock","1",TCL_GLOBAL_ONLY);
304     (*gi->EditProps)(g,1);
305     DoTcl("EditGate::post MODULE");
306     if ((temp = Tcl_GetVar(TkGate.tcl,"edgat_ok",TCL_GLOBAL_ONLY)) && sscanf(temp,"%d",&ok) == 1 && ok)
307       (*gi->EditProps)(g,0);
308     else {
309       gate_delete(g,(*es)->env,1);
310       return 0;
311     }
312     Tcl_SetVar(TkGate.tcl,"edgat_newBlock","0",TCL_GLOBAL_ONLY);
313 
314     env_checkname(g);
315     /** @TODO to remove */
316     /* M = env_findModule(g->u.block.moduleName); */
317 
318     copy = env_getInterface(g);
319     if (copy) {
320       if (GCElement_getType(copy) == GC_SYMBLOCK) {
321 	g = SymBlock_convert(g,copy->u.block.symbol,PM,1);
322       } else {						/* Standard block */
323 	g->u.block.gwidth = copy->u.block.gwidth;
324 	g->u.block.gheight = copy->u.block.gheight;
325 	g->xpos -= g->u.block.gwidth/2;
326 	g->ypos -= g->u.block.gheight/2;
327 	block_replicatewires(g,copy,(*es)->env);
328       }
329     }
330     gate_draw(g,GD_NORMAL);
331 
332     if (PM->m_isSpecial)
333       SetModified(MF_MODULE|MF_SYNCONLY);
334     else
335       SetModified(MF_MODULE);
336   } else {
337     g->u.block.moduleName = 0;
338   }
339 
340   if (Size && sscanf(Size,"%dx%d",&W,&H) == 2) {
341     g->u.block.gwidth = W;
342     g->u.block.gheight = H;
343   }
344 
345   return g;
346 }
347 
block_hitPort(GCElement * g,int x,int y)348 GWire *block_hitPort(GCElement *g,int x,int y)
349 {
350   GWire *best_w = 0;
351   int best_dist = MAXPORTRANGE+1;
352   int N = GCElement_numPads(g);
353   int i;
354 
355   for (i = 0;i < N;i++) {
356     GWire *w;
357 
358     for (w = g->wires[i];w;w = w->next) {
359       int d = distance(x,y,w->nodes->x,w->nodes->y);
360 
361       if (d < best_dist) {
362 	best_dist = d;
363 	best_w = w;
364       }
365     }
366   }
367 
368   if (best_w) {
369     /*
370      * If a corner is closer than a port, don't select the port.
371      */
372     if (distance(g->xpos                    ,g->ypos                     ,x,y) < best_dist) best_w = 0;
373     if (distance(g->xpos + g->u.block.gwidth,g->ypos                     ,x,y) < best_dist) best_w = 0;
374     if (distance(g->xpos                    ,g->ypos + g->u.block.gheight,x,y) < best_dist) best_w = 0;
375     if (distance(g->xpos + g->u.block.gwidth,g->ypos + g->u.block.gheight,x,y) < best_dist) best_w = 0;
376   }
377 
378   return best_w;
379 }
380 
Block_HitDistance(GCElement * g,int x,int y)381 int Block_HitDistance(GCElement *g,int x,int y)
382 {
383   if ((x > g->xpos - 10) &&
384       (x < g->xpos + g->u.block.gwidth + 10) &&
385       (y > g->ypos - 10) &&
386       (y < g->ypos + g->u.block.gheight + 10)) {
387 
388     return GATERANGE-1;		/* Hit on smaller objects if overlaping */
389   } else
390     return NOHIT;		/* Out of range */
391 }
392 
393 /*****************************************************************************
394  *
395  * Check to see if (x,y) is on the edge of g, ad return the edge.
396  *
397  * Parameters:
398  *      g		Gate to test
399  *      x,y		Coordinates to test.
400  *
401  *****************************************************************************/
Block_HitEdge(GCElement * g,int x,int y)402 int Block_HitEdge(GCElement *g,int x,int y)
403 {
404   int dx_left = x-g->xpos;
405   int dx_right = x-(g->xpos + g->u.block.gwidth);
406   int dy_top = y-g->ypos;
407   int dy_bottom = y-(g->ypos + g->u.block.gheight);
408 
409   dx_left = abs(dx_left);
410   dx_right = abs(dx_right);
411   dy_top = abs(dy_top);
412   dy_bottom = abs(dy_bottom);
413 
414   /*
415    * Ensure that (x,y) is inside the box
416    */
417   if (x < g->xpos || x > g->xpos+g->u.block.gwidth)
418     return PSIDE_UNKNOWN;
419   if (y < g->ypos || y > g->ypos+g->u.block.gheight)
420     return PSIDE_UNKNOWN;
421 
422   if (dx_left <= 10 && dx_left <= dy_top && dx_left <= dy_bottom)
423     return PSIDE_LEFT;
424   else if (dx_right <= 10 && dx_right <= dy_top && dx_right <= dy_bottom)
425     return PSIDE_RIGHT;
426   else if (dy_top <= 10)
427     return PSIDE_TOP;
428   else if (dy_bottom <= 10)
429     return PSIDE_BOTTOM;
430 
431   return PSIDE_UNKNOWN;
432 }
433 
Block_HitComponent(GCElement * g,int x,int y)434 int Block_HitComponent(GCElement *g,int x,int y)
435 {
436   GWire *w;
437 
438   ob_touch(g);
439   g->left = 0;
440   g->right = 0;
441   g->top = 0;
442   g->bottom = 0;
443 
444   w = block_hitPort(g,x,y);
445   if (w && !TkGate.circuit->wsel) {
446 
447     TkGate.circuit->wsel = w;
448     return GATERANGE-2;
449   }
450 
451   ob_touch(g);
452   g->left = 0;
453   g->right = 0;
454   g->top = 0;
455   g->bottom = 0;
456 
457   if ((x > g->xpos - 10) &&
458       (x < g->xpos + g->u.block.gwidth + 10) &&
459       (y > g->ypos - 10) &&
460       (y < g->ypos + g->u.block.gheight + 10)) {
461     if (x < g->xpos + 10) {
462       g->left = 1;
463     }
464     if (x > g->xpos + g->u.block.gwidth - 10) {
465       g->right = 1;
466     }
467     if (y < g->ypos + 10) {
468       g->top = 1;
469     }
470     if (y > g->ypos + g->u.block.gheight - 10) {
471       g->bottom = 1;
472     }
473     return GATERANGE-1;		/* Hit on smaller objects if overlaping */
474   } else
475     return NOHIT;		/* Out of range */
476 }
477 
Block_Init(GCElement * g)478 void Block_Init(GCElement *g)
479 {
480   ob_touch(g);
481   g->u.block.gwidth = MINSIZE;
482   g->u.block.gheight = MINSIZE;
483 }
484 
485 /*
486     Draw the names and I/O direction arrows for one 'pad' of
487     a logic block.
488 */
block_drawnamelist(GWire * w,int s,int d,int iod)489 void block_drawnamelist(GWire *w,int s,int d,int iod)
490 {
491   int p,x,y;
492   XFontStruct *F;
493 
494 #if 0
495   printf("block_drawnamelist(%s, %d, %d, %d)\n",w ? w->name : "(nil)",s,d,iod);
496 #endif
497 
498   if (s) {
499     XSetFont(TkGate.D,TkGate.modportGC, TkGate.stextbXF[TkGate.circuit->zoom_factor]->fid);
500     F = TkGate.stextbXF[1];
501   } else {
502     XSetFont(TkGate.D,TkGate.modportGC, TkGate.stextXF[TkGate.circuit->zoom_factor]->fid);
503     F = TkGate.stextXF[1];
504   }
505 
506 
507   for (;w;w = w->next) {
508     if (w->name) {
509       block_getwirexy(w,d,&x,&y,&p);
510       RelPosDrawString(TkGate.painterW,F,TkGate.modportGC,x,y,w->name,p);
511     }
512     DrawPinIOMark(w,d,iod,IODT_PORT);
513   }
514 }
515 
Block_Delete(GCElement * g,GModuleDef * PM,int drawp)516 void Block_Delete(GCElement *g,GModuleDef *PM,int drawp)
517 {
518   Generic_Delete(g,PM,drawp);
519 }
520 
Block_GetExtents(GCElement * g,TargetDev_e target,int * minx,int * miny,int * maxx,int * maxy,int * bd)521 void Block_GetExtents(GCElement *g,TargetDev_e target,int *minx,int *miny,int *maxx,int *maxy,int *bd)
522 {
523   *minx = g->xpos;
524   *miny = g->ypos;
525   *maxx = g->xpos + g->u.block.gwidth;
526   *maxy = g->ypos + g->u.block.gheight;
527 
528   if (bd) *bd = 30;
529 }
530 
531 /* Draw a logic block */
Block_Draw(GCElement * g,int md)532 void Block_Draw(GCElement *g,int md)
533 {
534   int N = GCElement_numPads(g);
535   int i;
536 
537   ZDrawRectangle(TkGate.D,TkGate.W,TkGate.moduleGC,
538 		 ctow_x(g->xpos),ctow_y(g->ypos),
539 		 g->u.block.gwidth,g->u.block.gheight);
540 
541   for (i = 0;i < N;i++) {
542     GWire *w = g->wires[i];
543 
544     if (md != GD_NOWIRE)
545       wire_drawlist(w,(md == GD_NOINWIRE) ? g : 0);
546     block_drawnamelist(g->wires[i],g->selected,
547 		       g->typeinfo->Pad[i].Loc[0].dir,
548 		       g->typeinfo->Pad[i].iotype);
549   }
550 
551   if (g->selected) {
552     ZDrawRectangle(TkGate.D,TkGate.W,TkGate.moduleGC,
553 		   ctow_x(g->xpos+1),ctow_y(g->ypos+1),
554 		   g->u.block.gwidth-2,g->u.block.gheight-2);
555   }
556 
557 
558   if (g->ename && g->show_name) {
559     char B[STRMAX];
560 
561     if (g->selected)
562       XSetFont(TkGate.D,TkGate.moduleGC, TkGate.stextbXF[TkGate.circuit->zoom_factor]->fid);
563     else
564       XSetFont(TkGate.D,TkGate.moduleGC, TkGate.stextXF[TkGate.circuit->zoom_factor]->fid);
565 
566     sprintf(B,"(%s)",g->ename);
567     dce_DrawString(TkGate.moduleGC,g->xpos + (g->u.block.gwidth / 2),
568 		   g->ypos + (g->u.block.gheight / 2)+fontheight(TkGate.stextXF[1]),
569 		   BetweenLeftAndRight | BetweenTopAndBottom,B);
570   }
571   if (g->u.block.moduleName) {
572     if (g->selected)
573       XSetFont(TkGate.D,TkGate.moduleGC, TkGate.textbXF[TkGate.circuit->zoom_factor]->fid);
574     else
575       XSetFont(TkGate.D,TkGate.moduleGC, TkGate.textXF[TkGate.circuit->zoom_factor]->fid);
576 
577 
578     dce_DrawString(TkGate.moduleGC,g->xpos + (g->u.block.gwidth / 2),
579 		   g->ypos + (g->u.block.gheight / 2),
580 		   BetweenLeftAndRight | BetweenTopAndBottom,
581 		   g->u.block.moduleName);
582   }
583 }
584 
585 /* Move a block */
Block_Move(GCElement * g,int x,int y)586 void Block_Move(GCElement *g,int x,int y)
587 {
588   int ports_fixed = block_isFixedPort(g);
589   int N = GCElement_numPads(g);
590   int i;
591   int min_width = MINSIZE;
592   int min_height = MINSIZE;
593 
594   if (g->top || g->bottom || g->left || g->right || TkGate.circuit->wsel) {
595     if (block_isIntfProtected(g)) {
596       message(0,msgLookup("err.protintf"),g->u.block.moduleName);
597       return;
598     }
599   }
600 
601   if (TkGate.circuit->wsel) {
602     int pad = block_getPad(g,TkGate.circuit->wsel);
603 
604     switch (pad) {
605     case BLOCK_TIN :
606     case BLOCK_TOUT :
607     case BLOCK_TTRI :
608     case BLOCK_BIN :
609     case BLOCK_BOUT :
610     case BLOCK_BTRI :
611       if (TkGate.circuit->wsel->nodes->x + x < g->xpos + 3)
612 	x = g->xpos + 3 - TkGate.circuit->wsel->nodes->x;
613       if (TkGate.circuit->wsel->nodes->x + x > g->xpos + g->u.block.gwidth - 3)
614 	x = g->xpos + g->u.block.gwidth - 3 - TkGate.circuit->wsel->nodes->x;
615       y = 0;
616       break;
617     case BLOCK_LIN :
618     case BLOCK_LOUT :
619     case BLOCK_LTRI :
620     case BLOCK_RIN :
621     case BLOCK_ROUT :
622     case BLOCK_RTRI :
623       if (TkGate.circuit->wsel->nodes->y + y < g->ypos + 3)
624 	y = g->ypos + 3 - TkGate.circuit->wsel->nodes->y;
625       if (TkGate.circuit->wsel->nodes->y + y > g->ypos + g->u.block.gheight - 3)
626 	y = g->ypos + g->u.block.gheight - 3 - TkGate.circuit->wsel->nodes->y;
627       x = 0;
628       break;
629     default :
630       return;
631       break;
632     }
633     wire_move(TkGate.circuit->wsel->nodes,x,y,FULL);
634     block_setWireEnd(g,TkGate.circuit->wsel,pad);
635     SetModified(MF_INTERFACE);
636     return;
637   }
638 
639   ob_touch(g);
640 
641   /*
642    * If fixed ports, compute minimum size.
643    */
644   if (ports_fixed) {
645     for (i = 0;i < N;i++) {
646       GWire *w;
647       for (w = g->wires[i];w;w = w->next) {
648 	block_setWireEnd(g,w,i);
649 
650 	if (g->typeinfo->Pad[i].Loc->dir == D_LEFT || g->typeinfo->Pad[i].Loc->dir == D_RIGHT) {
651 	  int height = w->nodes->y - g->ypos + 15;
652 	  if (height > min_height) min_height = height;
653 	} else {
654 	  int width = w->nodes->x - g->xpos + 15;
655 	  if (width > min_width) min_width = width;
656 	}
657       }
658     }
659   }
660 
661   if (g->top) {
662     if (g->u.block.gheight - y < min_height)
663       y = g->u.block.gheight - min_height;
664     g->u.block.gheight -= y;
665     g->ypos += y;
666     for (i = 0;i < N;i++) {
667       if (g->typeinfo->Pad[i].Loc->dir == D_LEFT || g->typeinfo->Pad[i].Loc->dir == D_RIGHT)
668 	block_scalewirelist(g->wires[i],g,1,ports_fixed);
669       if (g->typeinfo->Pad[i].Loc->dir == D_UP)
670 	block_movewirelist(g->wires[i],0,y);
671     }
672 
673     SetModified(MF_INTERFACE|MF_FORCE);
674   } else if (g->bottom) {
675     if (g->u.block.gheight + y < min_height)
676       y = min_height - g->u.block.gheight;
677     g->u.block.gheight += y;
678 
679     for (i = 0;i < N;i++) {
680       if (g->typeinfo->Pad[i].Loc->dir == D_LEFT || g->typeinfo->Pad[i].Loc->dir == D_RIGHT)
681 	block_scalewirelist(g->wires[i],g,1,ports_fixed);
682       if (g->typeinfo->Pad[i].Loc->dir == D_DOWN)
683 	block_movewirelist(g->wires[i],0,y);
684     }
685 
686     SetModified(MF_INTERFACE|MF_FORCE);
687   }
688 
689   if (g->left) {
690     if (g->u.block.gwidth - x < min_width)
691       x = g->u.block.gwidth - min_width;
692     g->u.block.gwidth -= x;
693     g->xpos += x;
694 
695     for (i = 0;i < N;i++) {
696       if (g->typeinfo->Pad[i].Loc->dir == D_UP || g->typeinfo->Pad[i].Loc->dir == D_DOWN)
697 	block_scalewirelist(g->wires[i],g,0,ports_fixed);
698       if (g->typeinfo->Pad[i].Loc->dir == D_LEFT)
699 	block_movewirelist(g->wires[i],x,0);
700     }
701 
702     SetModified(MF_INTERFACE|MF_FORCE);
703   } else if (g->right) {
704     if (g->u.block.gwidth + x < min_width)
705       x = min_width - g->u.block.gwidth;
706     g->u.block.gwidth += x;
707 
708     for (i = 0;i < N;i++) {
709       if (g->typeinfo->Pad[i].Loc->dir == D_UP || g->typeinfo->Pad[i].Loc->dir == D_DOWN)
710 	block_scalewirelist(g->wires[i],g,0,ports_fixed);
711       if (g->typeinfo->Pad[i].Loc->dir == D_RIGHT)
712 	block_movewirelist(g->wires[i],x,0);
713     }
714 
715     SetModified(MF_INTERFACE|MF_FORCE);
716   } else if  (!g->top && !g->bottom) {
717     for (i = 0;i < N;i++)
718       block_movewirelist(g->wires[i],x,y);
719     g->xpos += x;
720     g->ypos += y;
721   }
722 
723 }
724 
Block_AddInput(EditState * es,GCElement * g)725 void Block_AddInput(EditState *es,GCElement *g)
726 {
727   message(1,msgLookup("err.oldportact"));
728 }
729 
Block_AddTri(EditState * es,GCElement * g)730 void Block_AddTri(EditState *es,GCElement *g)
731 {
732   message(1,msgLookup("err.oldportact"));
733 }
734 
Block_AddOutput(EditState * es,GCElement * g)735 void Block_AddOutput(EditState *es,GCElement *g)
736 {
737   message(1,msgLookup("err.oldportact"));
738 }
739 
Block_ChangePin(EditState * es,GCElement * g)740 void Block_ChangePin(EditState *es,GCElement *g)
741 {
742   message(1,msgLookup("err.oldportact"));
743 }
744 
Block_PSDrawWireName(GPrint * P,GWire * w,int Dir,int IODir)745 void Block_PSDrawWireName(GPrint *P,GWire *w,int Dir,int IODir)
746 {
747   if (w->name) {
748     HtmlFont font[1];
749     int x,y,p;
750     Icon *arrow;
751     GateFont gateFont = {FF_HELVETICA,FP_ROMAN};
752 
753     block_getwirexy(w,Dir,&x,&y,&p);
754     PSDrawText(P,HtmlFont_init(font,gateFont,8),x,y,w->name,p);
755     GetPinIOMark(w,Dir,IODir,IODT_PORT,&x,&y,&arrow);
756     switch (IODir) {
757     case IN :
758       fprintf(P->p_f,"%d %d %d arrow\n",x,y,(Dir+2)%4);
759       break;
760     case OUT :
761       fprintf(P->p_f,"%d %d %d arrow\n",x,y,Dir);
762       break;
763     case TRI :
764     case ANY :
765     default:
766       fprintf(P->p_f,"%d %d %d tri\n",x,y,Dir%2);
767       break;
768     }
769   }
770 }
771 
Block_PSWrite(GPrint * P,GModLayout * L,GCElement * g)772 void Block_PSWrite(GPrint *P,GModLayout *L,GCElement *g)
773 {
774   int N = GCElement_numPads(g);
775   int i;
776   GWire *w;
777   HtmlFont font[1];
778   GateFont gateFont = {FF_HELVETICA,FP_ROMAN};
779 
780   fprintf(P->p_f,"%d %d %d %d box\n",g->xpos,g->ypos,
781 	  g->u.block.gwidth,g->u.block.gheight);
782 
783   for (i = 0;i < N;i++)
784     for (w = g->wires[i];w;w = w->next)
785       Block_PSDrawWireName(P,w,g->typeinfo->Pad[i].Loc[0].dir,
786 			   g->typeinfo->Pad[i].iotype);
787 
788   if (g->ename && g->show_name) {
789     char B[STRMAX];
790     int h;
791 
792     if (TkGate.tcl)
793       h = fontheight(TkGate.stextXF[1]);
794     else
795       h = 8;
796 
797     sprintf(B,"(%s)",g->ename);
798     PSDrawText(P,HtmlFont_init(font,gateFont,8),
799 	       g->xpos + (g->u.block.gwidth / 2),
800 	       g->ypos + (g->u.block.gheight / 2)+h,
801 	       B,BetweenLeftAndRight | BetweenTopAndBottom);
802   }
803   if (g->u.block.moduleName) {
804     PSDrawText(P,HtmlFont_init(font,gateFont, 10),
805 	       g->xpos + (g->u.block.gwidth / 2),
806 	       g->ypos + (g->u.block.gheight / 2),
807 	       g->u.block.moduleName,
808 	       BetweenLeftAndRight | BetweenTopAndBottom);
809 
810   }
811 }
812 
Block_EditParmProps(GCElement * g,int isLoadDialog)813 void Block_EditParmProps(GCElement *g, int isLoadDialog)
814 {
815   GModuleDef *m = env_findModule(g->u.block.moduleName);
816 
817   if (isLoadDialog) {
818     Tcl_UnsetVar(TkGate.tcl,"edgat_modParms",TCL_GLOBAL_ONLY);
819     if (m && m->m_parmPorts) {
820       HashElem *he;
821       for (he = Hash_first(m->m_parmPorts);he;he = Hash_next(m->m_parmPorts,he)) {
822 	const char *parmName = SHashElem_key(he);
823 	const char *value = Block_getParmPort(g,parmName);
824 	if (!value)
825 	  value = (const char*)HashElem_obj(he);
826 
827 	Tcl_SetVar2(TkGate.tcl,"edgat_modParms",parmName,value,TCL_GLOBAL_ONLY);
828       }
829     }
830   } else {
831     if (m && m->m_parmPorts) {
832       HashElem *he;
833       for (he = Hash_first(m->m_parmPorts);he;he = Hash_next(m->m_parmPorts,he)) {
834 	const char *parmName = SHashElem_key(he);
835 	const char *defaultValue = (char*)HashElem_obj(he);
836 	const char *newValue = Tcl_GetVar2(TkGate.tcl,"edgat_modParms",parmName,TCL_GLOBAL_ONLY);
837 
838 	if (newValue && strcmp(defaultValue,newValue) != 0)
839 	  Block_setParmPort(g,parmName,newValue);
840 	else
841 	  Block_unsetParmPort(g,parmName);
842       }
843     }
844   }
845 }
846 
847 
Block_EditProps(GCElement * g,int isLoadDialog)848 int Block_EditProps(GCElement *g,int isLoadDialog)
849 {
850   Tcl_Interp *tcl = TkGate.tcl;
851 
852   if (isLoadDialog) {
853     Tcl_SetVar(TkGate.tcl,"edgat_blockFunc",
854 	       g->u.block.moduleName,TCL_GLOBAL_ONLY);
855     Generic_EditProps(g,isLoadDialog);
856     Block_EditParmProps(g, isLoadDialog);
857   } else {
858     char buf[STRMAX];
859     const char *p;
860 
861     Generic_EditProps(g,isLoadDialog);
862     if ((p = Tcl_GetVar(tcl,"edgat_blockFunc",TCL_GLOBAL_ONLY)) && *p && strcmp(p,g->u.block.moduleName) != 0) {
863       int i;
864       ob_touch(g);
865       ob_free(g->u.block.moduleName);
866       pickValidName(buf,p,"func",0);
867       g->u.block.moduleName = ob_strdup(buf);
868       for (i = 0;i < g->u.block.numModParms;i++)
869 	ob_free(g->u.block.modParms[i]);
870       g->u.block.numModParms = 0;
871       if (g->u.block.modParms) ob_free(g->u.block.modParms);
872       g->u.block.modParms = 0;
873     } else
874       Block_EditParmProps(g, isLoadDialog);
875     SetModified(MF_INTERFACE);
876   }
877 
878   return 0;
879 }
880 
881 /*****************************************************************************
882  *
883  * Save module parameter data for a module instance.
884  *
885  * Parameters:
886  *     f		File in which to save module parameter data
887  *     g		Module instance from which to save module parameter data.
888  *
889  *****************************************************************************/
Block_VerSaveModParms(FILE * f,GCElement * g)890 void Block_VerSaveModParms(FILE *f,GCElement *g)
891 {
892   GModuleDef *m = env_findModule(g->u.block.moduleName);
893   HashElem *he;
894   int n = 0;
895 
896   if (!m || !m->m_parmPorts || g->u.block.numModParms == 0) return;
897 
898   for (he = Hash_first(m->m_parmPorts);he;he = Hash_next(m->m_parmPorts,he)) {
899     char buf[STRMAX];
900     const char *parmName = SHashElem_key(he);
901     const char *defaultValue = (char*)HashElem_obj(he);
902     const char *value = Block_getParmPort(g,parmName);
903     if (!value || strcmp(value,defaultValue) == 0) continue;
904 
905     if (n == 0)
906       fprintf(f," #(");
907     else
908       fprintf(f,", ");
909 
910     fprintf(f,".%s(",parmName);
911     if (isVerilogConstant(value)) {
912       fprintf(f,"%s",value);
913     } else if (*value == '"') {
914       int l = strlen(value);
915       /*If the string is already enclosed in quotes, then don't requote it. */
916       if (l == 0)
917 	fprintf(f,"\"\"");
918       else if (l == 1)
919 	fprintf(f,"\"%s\"",value);
920       else if (value[0] == '"' && value[l-1] == '"' && value[l-2] != '\\') {
921 	char buf2[STRMAX];
922 	strcpy(buf2,value+1);
923 	buf2[l-2] = 0;
924 	sprintf(buf,"%s",quoteChars(buf,buf2,"\"\\"));
925 	fprintf(f,"\"%s\"",buf);
926       } else
927 	fprintf(f,"\"%s\"",quoteChars(buf,value,"\"\\"));
928     } else {
929       fprintf(f,"\"%s\"",quoteChars(buf,value,"\"\\"));
930     }
931     fprintf(f,")");
932     n++;
933   }
934 
935   if (n > 0)
936     fprintf(f,")");
937 }
938 
939 /*****************************************************************************
940  *
941  * Save data for a module instance.
942  *
943  * Parameters:
944  *     f		File in which to save module instance
945  *     g		Module instance to be saved
946  *
947  *****************************************************************************/
Block_VerSave(FILE * f,GCElement * g)948 void Block_VerSave(FILE *f,GCElement *g)
949 {
950   int N = GCElement_numPads(g);
951   GWire *w;
952   int i,j;
953   int first_pin;
954   static char dirchar[] = "?=><";
955 
956   fprintf(f,"  %s",g->u.block.moduleName);
957   Block_VerSaveModParms(f,g);
958   fprintf(f," %s",g->ename);
959 
960   first_pin = 1;
961   fprintf(f," (");
962   for (i = 0;i < N;i++) {
963     for (w = g->wires[i], j=0;w;w = w->next, j++) {
964       if (first_pin)
965 	first_pin = 0;
966       else
967 	fprintf(f,", ");
968       fprintf(f,".%s(%s)",w->name,w->net->n_signame);
969     }
970   }
971   fprintf(f,");");
972 
973   fprintf(f,"   //: @(%d, %d) /sz:(%d, %d)",g->xpos,g->ypos,g->u.block.gwidth,g->u.block.gheight);
974 
975   if (g->orient != 0)
976     fprintf(f," /R:%d",g->orient);
977 
978   if (!g->show_name)
979     fprintf(f," /sn:%d",g->show_name);
980   if (g->anchored)
981     fprintf(f," /anc:1");
982 
983   fprintf(f," /p:[");
984   for (i = 0;i < N;i++) {
985     for (w = g->wires[i], j=0;w;w = w->next, j++) {
986       fprintf(f," %s%d%c%d",
987 	      GCElement_getPadName(g,i),j,
988 	      dirchar[GCElement_getPadDir(g,i)],
989 	      w->nidx);
990     }
991   }
992   fprintf(f," ]");
993 
994   fprintf(f,"\n");
995 }
996 
block_scalewirelist(GWire * w,GCElement * g,int isY,int portsFixed)997 void block_scalewirelist(GWire *w,GCElement *g,int isY,int portsFixed)
998 {
999   for (;w;w = w->next) {
1000     int dx = 0;
1001     int dy = 0;
1002 
1003     if (portsFixed) {
1004       if (isY) {
1005 	dy = w->offset.num  + g->ypos - w->nodes->y;
1006 	w->offset.den = g->u.block.gheight;
1007       } else {
1008 	dx = w->offset.num + g->xpos - w->nodes->x;
1009 	w->offset.den = g->u.block.gwidth;
1010       }
1011     } else {
1012       if (isY) {
1013 	dy = (g->u.block.gheight*w->offset.num)/w->offset.den+g->ypos-w->nodes->y;
1014       } else {
1015 	dx = (g->u.block.gwidth*w->offset.num)/w->offset.den+g->xpos-w->nodes->x;
1016       }
1017     }
1018 
1019     wire_move(w->nodes,dx,dy,FULL);
1020   }
1021 }
1022 
1023 
block_movewirelist(GWire * w,int dx,int dy)1024 void block_movewirelist(GWire *w,int dx,int dy)
1025 {
1026   for (;w;w = w->next) {
1027     GWire *ow = wire_other(w);
1028     GCElement *g = w->gate;
1029 
1030     if (ow->gate && ow->gate == g) {
1031       if (w->driver == w) {
1032 	GWireNode *n;
1033 
1034 	for (n = w->driver->nodes;n;n = n->out) {
1035 	  ob_touch(n);
1036 	  n->x += dx;
1037 	  n->y += dy;
1038 	}
1039       }
1040     } else
1041       wire_move(w->nodes,dx,dy,FULL);
1042   }
1043 }
1044 
block_getPortDir(GCElement * g,GWire * w)1045 int block_getPortDir(GCElement *g,GWire *w)
1046 {
1047   int N = GCElement_numPads(g);
1048   int i;
1049 
1050   for (i = 0;i < N;i++) {
1051     GWire *bw;
1052 
1053     for (bw = g->wires[i];bw;bw = bw->next)
1054       if (bw == w)
1055 	return GCElement_getPadDir(g,i);
1056   }
1057   return 0;
1058 }
1059 
block_getPad(GCElement * g,GWire * w)1060 int block_getPad(GCElement *g,GWire *w)
1061 {
1062   int N = GCElement_numPads(g);
1063   int i;
1064 
1065   for (i = 0;i < N;i++) {
1066     GWire *bw;
1067 
1068     for (bw = g->wires[i];bw;bw = bw->next)
1069       if (bw == w)
1070 	return i;
1071   }
1072   return -1;
1073 }
1074 
1075 /*
1076  * Try to guess a name for a port with the specified characteristics.
1077  */
guessPortName(char * buf,GCElement * g,int orient,int dir,int nbits)1078 void guessPortName(char *buf,GCElement *g,int orient,int dir,int nbits)
1079 {
1080   int N = GCElement_numPads(g);
1081   GWire *w =0;
1082   int i;
1083   GWire *best_w = 0;	/* Best matching wire so far */
1084   int best_score = 0;
1085 
1086   *buf = 0;
1087 
1088   for (i = 0;i < N;i++) {
1089     for (w = g->wires[i];w;w = w->next) {
1090       int score = 0;
1091       int n;
1092 
1093       if (g->typeinfo->Pad[i].iotype != dir) continue;		/* Must be at least same I/O dir */
1094       if (!w->name) continue;
1095 
1096       if (w->orient == orient) score += 5000;			/* Same orientation */
1097       if (w->net->n_nbits == nbits) score += 1000;		/* Same bit size */
1098 
1099       if (sscanf(w->name,"%*[A-Za-z_]%d",&n) == 1)
1100 	score += n + 500;
1101       else
1102 	score += *w->name;
1103 
1104       if (score > best_score) {
1105 	best_w = w;
1106 	best_score = score;
1107       }
1108     }
1109   }
1110 
1111   /*
1112    * We found a best similar port, use it to guess a name.
1113    */
1114   if (best_w) {
1115     DoTcl("PortEntry::generateNextNameFrom %s",best_w->name);
1116     if (*(Tcl_GetStringResult(TkGate.tcl)))
1117       strcpy(buf,Tcl_GetStringResult(TkGate.tcl));
1118   }
1119 
1120   if (!*buf) {
1121     switch (dir) {
1122     case IN :
1123       strcpy(buf,"I0");
1124       break;
1125     case OUT :
1126       strcpy(buf,"IO0");
1127       break;
1128     case TRI :
1129     default :
1130       strcpy(buf,"Z0");
1131       break;
1132     }
1133   }
1134 }
1135 
1136 /*****************************************************************************
1137  *
1138  * Set the name of port 'w' on block 'g'.
1139  *
1140  *****************************************************************************/
block_setPortName(GCElement * g,GWire * w,EditState * es)1141 int block_setPortName(GCElement *g,GWire *w,EditState *es)
1142 {
1143   static char Buf[STRMAX];
1144   int x,y;
1145   int dir;
1146   int nbits;
1147   const char *sdir = "";
1148   const char *sigName;
1149   const char *portName;
1150   int ok;
1151 
1152   if (block_isIntfProtected(g)) {
1153     message(0,msgLookup("err.protintf"),g->u.block.moduleName);
1154     return 0;
1155   }
1156 
1157   dir = block_getPortDir(w->gate,w);
1158   sdir = iotypeStr(dir);
1159 
1160   Tcl_SetVar(TkGate.tcl,"edport_sig",w->net->n_signame,TCL_GLOBAL_ONLY);
1161   if (w->name)
1162     Tcl_SetVar(TkGate.tcl,"edport_port",w->name,TCL_GLOBAL_ONLY);
1163   else {
1164     guessPortName(Buf,g,w->orient,dir,1);
1165     Tcl_SetVar(TkGate.tcl,"edport_port",Buf,TCL_GLOBAL_ONLY);
1166   }
1167 
1168   Tcl_SetVar(TkGate.tcl,"edport_type",sdir,TCL_GLOBAL_ONLY);
1169   sprintf(Buf,"%d",w->net->n_nbits);
1170   Tcl_SetVar(TkGate.tcl,"edport_bits",Buf,TCL_GLOBAL_ONLY);
1171 
1172   x = w->nodes->x;
1173   y = w->nodes->y;
1174 
1175   if (editstate_getInterfaceMode() == INTFMODE_NONE)
1176     DoTcl("PortEdit::post [offsetgeometry . %d %d] -ismodule 1",ctow_x(x+125),ctow_y(y+50));
1177   else
1178     DoTcl("PortEdit::post [offsetgeometry . %d %d] -ismodule 1 -showsig 0",ctow_x(x+125),ctow_y(y+50));
1179 
1180   if (strcmp(Tcl_GetStringResult(TkGate.tcl),"1") == 0) {
1181     const char *numBits;
1182     int new_dir;
1183 
1184 
1185     sigName = Tcl_GetVar(TkGate.tcl,"edport_sig",TCL_GLOBAL_ONLY);
1186     portName = Tcl_GetVar(TkGate.tcl,"edport_port",TCL_GLOBAL_ONLY);
1187     numBits = Tcl_GetVar(TkGate.tcl,"edport_bits",TCL_GLOBAL_ONLY);
1188     sdir = Tcl_GetVar(TkGate.tcl,"edport_type",TCL_GLOBAL_ONLY);
1189 
1190     if (!sigName || sscanf(numBits,"%d",&nbits) != 1)
1191       nbits = w->net->n_nbits;
1192 
1193     new_dir = strIOType(sdir);
1194     if (new_dir < 0) new_dir = dir;
1195 
1196     /*
1197      * Change direction 1 or 2 times to make direction match.
1198      */
1199     if (new_dir != dir) {
1200       block_changedir(w->nodes,es);
1201       dir = block_getPortDir(w->gate,w);
1202       if (dir != new_dir) {
1203 	block_changedir(w->nodes,es);
1204 	dir = block_getPortDir(w->gate,w);
1205       }
1206     }
1207 
1208     SetModified(MF_INTERFACE);
1209 
1210     ok = 1;
1211   } else {
1212     sigName = w->net->n_signame;
1213     portName = w->name ? w->name : DEFAULT_PORT_NAME;
1214     nbits = w->net->n_nbits;
1215 
1216     ok = 0;
1217   }
1218 
1219 
1220   Block_Draw(w->gate,0);
1221   if (strcmp(w->net->n_signame,sigName) != 0) net_rename(w->net,sigName,GNet_getShowName(w->net));
1222 
1223   if (strcmp(portName,DEFAULT_PORT_NAME) == 0 || !*portName) {
1224     guessPortName(Buf,g,w->orient,dir,nbits);
1225     portName = Buf;
1226   }
1227   pickValidName(Buf,portName,"P",0);
1228 
1229   ob_touch(w);
1230   w->name = ob_strdup(Buf);
1231   net_setSize(w->net,nbits);
1232   Block_Draw(w->gate,0);
1233 
1234   SynchronizeInterface();
1235 
1236   return ok;
1237 }
1238 
block_getwirexy(GWire * w,int d,int * x,int * y,int * p)1239 void block_getwirexy(GWire *w,int d,int *x,int *y,int *p)
1240 {
1241   int h;
1242 
1243   if (TkGate.tcl)
1244     h = fontheight(TkGate.stextXF[1]);
1245   else
1246     h = 8;
1247 
1248   switch (d) {
1249   case D_UP :
1250     *x = w->nodes->x;
1251     *y = w->nodes->y + (7*h)/8;
1252     *p = BetweenLeftAndRight | BetweenTopAndBottom;
1253     break;
1254   case D_LEFT :
1255     *x = w->nodes->x + 4;
1256     *y = w->nodes->y + 3;
1257     *p = AtLeft | BetweenTopAndBottom;
1258     break;
1259   case D_DOWN :
1260     *x = w->nodes->x;
1261     *y = w->nodes->y - (2*h)/3;
1262     *p = BetweenLeftAndRight | BetweenTopAndBottom;
1263     break;
1264   case D_RIGHT :
1265     *x = w->nodes->x - 4;
1266     *y = w->nodes->y + 3;
1267     *p = AtRight | BetweenTopAndBottom;
1268     break;
1269   }
1270 }
1271 
1272 /* Used by box exploder */
propogate(int ux[NUMSQRS],int uy[NUMSQRS],int lx[NUMSQRS],int ly[NUMSQRS],int n)1273 static void propogate(int ux[NUMSQRS],int uy[NUMSQRS],int lx[NUMSQRS],int ly[NUMSQRS],int n)
1274 {
1275   int i;
1276 
1277   for (;n;n--)
1278     for (i = NUMSQRS-1;i;i--) {
1279       ux[i-1] = ux[i];
1280       uy[i-1] = uy[i];
1281       lx[i-1] = lx[i];
1282       ly[i-1] = ly[i];
1283     }
1284 }
1285 
1286 /* Do explosion look on box */
block_explode(GCElement * g)1287 void block_explode(GCElement *g)
1288 {
1289   int ux[NUMSQRS],uy[NUMSQRS],lx[NUMSQRS],ly[NUMSQRS],n;
1290   int bd;
1291 
1292 #if 1
1293   (*g->typeinfo->GetExtents)(g,TD_X11,&ux[NUMSQRS-1],&uy[NUMSQRS-1],&lx[NUMSQRS-1],&ly[NUMSQRS-1],&bd);
1294 #else
1295   ux[NUMSQRS-1] = ctow_x(g->xpos);
1296   uy[NUMSQRS-1] = ctow_y(g->ypos);
1297   lx[NUMSQRS-1] = ux[NUMSQRS-1] + g->u.block.gwidth;
1298   ly[NUMSQRS-1] = uy[NUMSQRS-1] + g->u.block.gheight;
1299 #endif
1300 
1301   propogate(ux,uy,lx,ly,NUMSQRS-1);
1302   for (n = NUMSTEPS;n;n--) {
1303     XClearArea(TkGate.D,TkGate.W,ux[0],uy[0],lx[0]-ux[0],ly[0]-uy[0],0);
1304     propogate(ux,uy,lx,ly,1);
1305     ux[NUMSQRS-1] -= ux[NUMSQRS-1] / n;
1306     uy[NUMSQRS-1] -= uy[NUMSQRS-1] / n;
1307     lx[NUMSQRS-1] += (TkGate.width - lx[NUMSQRS-1]) / n;
1308     ly[NUMSQRS-1] += (TkGate.height - ly[NUMSQRS-1]) / n;
1309     box(wtoc_x(ux[NUMSQRS-1]),wtoc_y(uy[NUMSQRS-1]),
1310 	lx[NUMSQRS-1]-ux[NUMSQRS-1],ly[NUMSQRS-1]-uy[NUMSQRS-1]);
1311     XFlush(TkGate.D);
1312     usleep(1);
1313   }
1314   FlagRedraw();
1315 }
1316 
block_setWireEnd(GCElement * g,GWire * w,int pad)1317 void block_setWireEnd(GCElement *g,GWire *w,int pad)
1318 {
1319   GWireNode *n = w->nodes;
1320 
1321   ob_touch(w);
1322   switch (pad) {
1323   case BLOCK_TIN :
1324   case BLOCK_TOUT :
1325   case BLOCK_TTRI :
1326     w->offset.num = n->x - g->xpos;
1327     w->offset.den = g->u.block.gwidth;
1328     w->orient = RIGHT;
1329     break;
1330   case BLOCK_LIN :
1331   case BLOCK_LOUT :
1332   case BLOCK_LTRI :
1333     w->offset.num = n->y - g->ypos;
1334     w->offset.den = g->u.block.gheight;
1335     w->orient = DOWN;
1336     break;
1337   case BLOCK_BIN :
1338   case BLOCK_BOUT :
1339   case BLOCK_BTRI :
1340     w->offset.num = n->x - g->xpos;
1341     w->offset.den = g->u.block.gwidth;
1342     w->orient = LEFT;
1343     break;
1344   case BLOCK_RIN :
1345   case BLOCK_ROUT :
1346   case BLOCK_RTRI :
1347     w->offset.num = n->y - g->ypos;
1348     w->offset.den = g->u.block.gheight;
1349     w->orient = UP;
1350     break;
1351   default :
1352     logError(ERL_ERROR,"Illegal pad number for wire on block.");
1353   }
1354 }
1355 
addbendnode(GWireNode * n)1356 void addbendnode(GWireNode *n)
1357 {
1358   GWireNode *nn;
1359 
1360   nn = new_GWireNode();
1361   ob_touch(nn);
1362   ob_touch(n);
1363 
1364   nn->x = n->x;
1365   nn->y = n->y;
1366   if (n->in) {
1367     ob_touch(nn->in);
1368 
1369     nn->in = n->in;
1370     nn->in->out = nn;
1371     n->in = nn;
1372     nn->out = n;
1373   } else {
1374     ob_touch(nn->out);
1375 
1376     nn->out = n->out;
1377     nn->out->in = nn;
1378     n->out = nn;
1379     nn->in = n;
1380   }
1381 }
1382 
quadrent(GCElement * g,int x,int y)1383 static int quadrent(GCElement *g,int x,int y)
1384 {
1385   if ((y - g->ypos)*g->u.block.gwidth > (x - g->xpos)*g->u.block.gheight) {
1386     if ((g->ypos+g->u.block.gheight-y)*g->u.block.gwidth >
1387 	(x - g->xpos)*g->u.block.gheight) {
1388       return D_LEFT;
1389     } else {
1390       return D_DOWN;
1391     }
1392   } else {
1393     if ((g->ypos+g->u.block.gheight-y)*g->u.block.gwidth >
1394 	(x - g->xpos)*g->u.block.gheight) {
1395       return D_UP;
1396     } else {
1397       return D_RIGHT;
1398     }
1399   }
1400 }
1401 
nquadrent(GCElement * g,GWireNode * n)1402 static int nquadrent(GCElement *g,GWireNode *n)
1403 {
1404   return quadrent(g,n->x,n->y);
1405 }
1406 
block_connect(GCElement * g,GWireNode * n,int iotype)1407 int block_connect(GCElement *g,GWireNode *n,int iotype)
1408 {
1409   int p,q;
1410 
1411   ob_touch(n->end);
1412   n->end->gate = g;
1413 
1414   switch (p = nquadrent(g,n)) {
1415   case D_UP :
1416     q = BLOCK_TIN;
1417     break;
1418   case D_DOWN :
1419     q = BLOCK_BIN;
1420     break;
1421   case D_LEFT :
1422     q = BLOCK_LIN;
1423     break;
1424   case D_RIGHT :
1425     q = BLOCK_RIN;
1426     break;
1427   default :
1428     return -1;
1429   }
1430 
1431   switch (iotype) {
1432   case IN :
1433     break;
1434   case OUT :
1435     q += 4;
1436     break;
1437   case TRI :
1438     q += 8;
1439     break;
1440   }
1441 
1442   ob_touch(g);
1443   g->wires[q] = block_addwire(n->end,g->wires[q]);
1444   block_setWireEnd(g,n->end,q);
1445 
1446   SetModified(MF_NET|MF_INTERFACE);
1447 
1448   switch (p) {
1449   case D_UP :
1450     wire_move(n,0,g->ypos - 1 - n->y,n->stype);
1451     if (!(wireorient(n,0) & 1))
1452       addbendnode(n);
1453     break;
1454   case D_LEFT :
1455     wire_move(n,g->xpos - 1 - n->x,0,n->stype);
1456     if (wireorient(n,0) & 1)
1457       addbendnode(n);
1458     break;
1459   case D_DOWN :
1460     wire_move(n,0,(g->ypos + g->u.block.gheight+1) - n->y,n->stype);
1461     if (!(wireorient(n,0) & 1))
1462       addbendnode(n);
1463     break;
1464   case D_RIGHT :
1465     wire_move(n,(1 + g->xpos + g->u.block.gwidth) - n->x,0,n->stype);
1466     if (wireorient(n,0) & 1)
1467       addbendnode(n);
1468     break;
1469   default :
1470     return -1;
1471   }
1472 
1473   wire_finalizeNet(n->end);
1474 
1475   return p;
1476 }
1477 
block_addwire(GWire * w,GWire * wl)1478 GWire *block_addwire(GWire *w,GWire *wl)
1479 {
1480   ob_touch(w);
1481   w->next = wl;
1482   return w;
1483 }
1484 
1485 /*
1486  * Primitive function to disconnect wire
1487  */
block_deletewire(GWire * w)1488 void block_deletewire(GWire *w)
1489 {
1490   int n,p;
1491   GCElement *g;
1492   static int xdel[] = {3,0,-3,0};
1493   static int ydel[] = {0,-3,0,3};
1494 
1495   posongate(w,w->gate,&p,&n);
1496   g = w->gate;
1497 
1498   if (block_isIntfProtected(g)) {
1499     message(0,msgLookup("err.protintf"),g->u.block.moduleName);
1500     return;
1501   }
1502 
1503   ob_touch(g);
1504   ob_touch(w);
1505   ob_touch(w->nodes);
1506 
1507   gate_draw(g,GD_NOWIRE);
1508   ob_free(w->name);
1509   w->name = NULL;
1510   w->gate = NULL;
1511 
1512   g->wires[p] = wire_unattach(w,g->wires[p]);
1513   w->nodes->y += ydel[g->typeinfo->Pad[p].Loc->dir];
1514   w->nodes->x += xdel[g->typeinfo->Pad[p].Loc->dir];
1515 
1516   gate_draw(g,GD_NOWIRE);
1517 
1518   SetModified(MF_NET|MF_INTERFACE);
1519 }
1520 
1521 /*
1522  * Disconnect wire from block and do any necessary cleanup
1523  */
block_cutoffwire(GWire * w,EditState * es)1524 void block_cutoffwire(GWire *w,EditState *es)
1525 {
1526   GCElement *g = w->gate;
1527 
1528   if (block_isIntfProtected(g)) {
1529     message(0,msgLookup("err.protintf"),g->u.block.moduleName);
1530     return;
1531   }
1532 
1533   GNet_draw(w->net);
1534   block_deletewire(w);
1535   wire_nuke(w,0,es->env);
1536 }
1537 
1538 /*****************************************************************************
1539  *
1540  * Get the properties for a new port to be added to a block.
1541  *
1542  *****************************************************************************/
block_getNewPortProperties(GCElement * g,int x,int y,int orient,char * name,int * iodir,int * nbits)1543 int block_getNewPortProperties(GCElement *g,int x,int y,int orient,
1544 			       char *name,int *iodir,int *nbits)
1545 {
1546   char buf[STRMAX];
1547 
1548   sprintf(buf,"%d",*nbits);
1549   guessPortName(name,g,orient,*iodir,*nbits);
1550 
1551   Tcl_SetVar(TkGate.tcl,"edport_sig","",TCL_GLOBAL_ONLY);
1552   Tcl_SetVar(TkGate.tcl,"edport_port",name,TCL_GLOBAL_ONLY);
1553   Tcl_SetVar(TkGate.tcl,"edport_type",iotypeStr(*iodir),TCL_GLOBAL_ONLY);
1554   Tcl_SetVar(TkGate.tcl,"edport_bits",buf,TCL_GLOBAL_ONLY);
1555 
1556   DoTcl("PortEdit::post [offsetgeometry . %d %d] -ismodule 1 -showsig 0",
1557 	ctow_x(x+125),ctow_y(y+50));
1558 
1559   if (strcmp(Tcl_GetStringResult(TkGate.tcl),"1") == 0) {
1560     const char *numBits;
1561     /** @TODO to remove */
1562     /* const char *sigName; */
1563     const char *portName;
1564     const char *sdir;
1565     /** @TODO to remove */
1566     /* sigName = Tcl_GetVar(TkGate.tcl,"edport_sig",TCL_GLOBAL_ONLY); */
1567     portName = Tcl_GetVar(TkGate.tcl,"edport_port",TCL_GLOBAL_ONLY);
1568     numBits = Tcl_GetVar(TkGate.tcl,"edport_bits",TCL_GLOBAL_ONLY);
1569     sdir = Tcl_GetVar(TkGate.tcl,"edport_type",TCL_GLOBAL_ONLY);
1570 
1571     strcpy(name,portName);
1572     sscanf(numBits,"%d",nbits);
1573     *iodir = strIOType(sdir);
1574 
1575     return 1;
1576   } else
1577     return 0;
1578 }
1579 
1580 
block_newport(EditState * es,int iodir)1581 void block_newport(EditState *es,int iodir)
1582 {
1583   GCElement *g = TkGate.circuit->select;
1584   char portName[STRMAX];
1585   int nbits;
1586   int orient;
1587   GWire *w;
1588   int p;
1589 
1590   if (!block_edgehit(g,TkGate.ed->tx,TkGate.ed->ty)) return;
1591   if (g && !(TkGate.circuit->select->typeinfo->code == GC_BLOCK)) return;
1592 
1593   if (block_isIntfProtected(g)) {
1594     message(0,msgLookup("err.protintf"),g->u.block.moduleName);
1595     return;
1596   }
1597 
1598   orient = quadrent(g,TkGate.ed->tx,TkGate.ed->ty);
1599   nbits = 1;
1600   if (!block_getNewPortProperties(g,TkGate.ed->tx,TkGate.ed->ty,orient,
1601 				  portName,&iodir,&nbits))
1602     return;
1603 
1604   wire_new(es->env,0,&w);
1605   p = block_attach(es->env,g,w,w->driver,TkGate.ed->tx,TkGate.ed->ty,NULL,iodir);
1606 
1607   if (p >= 0) {
1608     pickValidName(portName,portName,"P",0);
1609 
1610     ob_touch(w);
1611     w->name = ob_strdup(portName);
1612     net_setSize(w->net,nbits);
1613 
1614     GWire_draw(w->driver);
1615     DrawPinIOMark(w,p,iodir,IODT_PORT);
1616 
1617     SetModified(MF_INTERFACE|MF_NET);
1618     SynchronizeInterface();
1619   }
1620   FlagRedraw();
1621 }
1622 
block_setdir(GWireNode * n,EditState * es,int dir)1623 void block_setdir(GWireNode *n,EditState *es,int dir)
1624 {
1625   GCElement *g;
1626   int p,x;
1627 
1628   if (!n || !n->end || !n->end->gate) return;
1629 
1630   if (n->end->gate->typeinfo->code != GC_BLOCK) {
1631     message(1,msgLookup("err.nopin"));			/* Can't change selected pin. */
1632     return;
1633   }
1634   g = n->end->gate;
1635 
1636   if (block_isIntfProtected(g)) {
1637     message(0,msgLookup("err.protintf"),g->u.block.moduleName);
1638     return;
1639   }
1640 
1641   ob_touch(g);
1642 
1643   posongate(n->end,g,&p,&x);
1644 
1645   DrawPinIOMark(n->end,g->typeinfo->Pad[p].Loc[0].dir,
1646 		g->typeinfo->Pad[p].iotype,IODT_PORT);
1647   g->wires[p] = wire_unattach(n->end,g->wires[p]);
1648 
1649   p = p % 4;
1650   if (dir == OUT)
1651     p += 4;
1652   else if (dir == TRI)
1653     p += 8;
1654 
1655   DrawPinIOMark(n->end,g->typeinfo->Pad[p].Loc[0].dir,
1656 		g->typeinfo->Pad[p].iotype,IODT_PORT);
1657   g->wires[p] = block_addwire(n->end,g->wires[p]);
1658 
1659   SetModified(MF_INTERFACE);
1660   SynchronizeInterface();
1661 }
1662 
block_changedir(GWireNode * n,EditState * es)1663 void block_changedir(GWireNode *n,EditState *es)
1664 {
1665   GCElement *g;
1666   int p,x;
1667 
1668   if (!n || !n->end || !n->end->gate) return;
1669 
1670   if (n->end->gate->typeinfo->code != GC_BLOCK) {
1671     message(1,msgLookup("err.nopin"));			/* Can't change selected pin. */
1672     return;
1673   }
1674   g = n->end->gate;
1675 
1676   if (block_isIntfProtected(g)) {
1677     message(0,msgLookup("err.protintf"),g->u.block.moduleName);
1678     return;
1679   }
1680 
1681   ob_touch(g);
1682 
1683   posongate(n->end,g,&p,&x);
1684 
1685   DrawPinIOMark(n->end,g->typeinfo->Pad[p].Loc[0].dir,
1686 		g->typeinfo->Pad[p].iotype,IODT_PORT);
1687   g->wires[p] = wire_unattach(n->end,g->wires[p]);
1688 
1689   p = (p + 4) % GCElement_numPads(g);
1690 
1691   DrawPinIOMark(n->end,g->typeinfo->Pad[p].Loc[0].dir,
1692 		g->typeinfo->Pad[p].iotype,IODT_PORT);
1693   g->wires[p] = block_addwire(n->end,g->wires[p]);
1694 
1695   SetModified(MF_INTERFACE);
1696   SynchronizeInterface();
1697 }
1698 
block_attach(GModuleDef * env,GCElement * g,GWire * w1,GWire * w2,int x,int y,const char * name,int iotype)1699 int block_attach(GModuleDef *env,GCElement *g,GWire *w1,GWire *w2,
1700 	     int x,int y,const char *name,int iotype)
1701 {
1702   int p;
1703 
1704   ob_touch(w1);
1705   ob_touch(w1->nodes);
1706   ob_touch(w2->nodes);
1707 
1708   w1->nodes->x = x;
1709   w1->nodes->y = y;
1710   w1->gate = g;
1711 
1712   p = -1;
1713   switch (nquadrent(g,w1->nodes)) {
1714   case D_UP :
1715     w1->nodes->y = g->ypos - 1;
1716     w2->nodes->y = w1->nodes->y - BLOCK_STUBLEN;
1717     w1->nodes->x = w2->nodes->x = x;
1718     break;
1719   case D_LEFT :
1720     w1->nodes->x = g->xpos-1;
1721     w2->nodes->x = w1->nodes->x - BLOCK_STUBLEN;
1722     w1->nodes->y = w2->nodes->y = y;
1723     break;
1724   case D_DOWN :
1725     w1->nodes->y = g->ypos + g->u.block.gheight + 1;
1726     w2->nodes->y = w1->nodes->y + BLOCK_STUBLEN;
1727     w1->nodes->x = w2->nodes->x = x;
1728     break;
1729   case D_RIGHT :
1730     w1->nodes->x = g->xpos + g->u.block.gwidth + 1;
1731     w2->nodes->x = w1->nodes->x + BLOCK_STUBLEN;
1732     w1->nodes->y = w2->nodes->y = y;
1733     break;
1734   default :
1735     return -1;
1736   }
1737   p = block_connect(g,w1->nodes,iotype);
1738   SetModified(MF_INTERFACE);
1739 
1740   if (name && w1) w1->name = ob_strdup(name);
1741 
1742   return p;
1743 }
1744 
block_edgehit(GCElement * g,int x,int y)1745 int block_edgehit(GCElement *g,int x,int y)
1746 {
1747   int bx,by,bw,bh;
1748   int e1,e2,e3,e4;
1749 
1750   bx = g->xpos;
1751   by = g->ypos;
1752   bw = g->u.block.gwidth;
1753   bh = g->u.block.gheight;
1754 
1755   e1 = on_edge(x,y,bx+2,by,bx+bw-2,by);
1756   e2 = on_edge(x,y,bx,by+2,bx,by+bh-2);
1757   e3 = on_edge(x,y,bx+bw,by+2,bx+bw,by+bh-2);
1758   e4 = on_edge(x,y,bx+2,by+bh,bx+bw-2,by+bh);
1759 
1760   return e1 || e2 || e3 || e4;
1761 }
1762 
block_canonicalizewire(GCElement * g,GWire * w)1763 void block_canonicalizewire(GCElement *g,GWire *w)
1764 {
1765   GWireNode *n;
1766 
1767   n = w->nodes->out ? w->nodes->out : w->nodes->in;
1768 
1769   ob_touch(n);
1770   ob_touch(w->nodes);
1771 
1772   switch (w->orient) {
1773   case 0 :
1774     w->nodes->x = g->xpos + g->u.block.gwidth + 1;
1775     n->x = w->nodes->x + BLOCK_STUBLEN;
1776     n->y = w->nodes->y;
1777     break;
1778   case 1 :
1779     w->nodes->y = g->ypos - 1;
1780     n->y = w->nodes->y - BLOCK_STUBLEN;
1781     n->x = w->nodes->x;
1782     break;
1783   case 2 :
1784     w->nodes->x = g->xpos - 1;
1785     n->x = w->nodes->x - BLOCK_STUBLEN;
1786     n->y = w->nodes->y;
1787     break;
1788   case 3 :
1789     w->nodes->y = g->ypos + g->u.block.gheight + 1;
1790     n->y = w->nodes->y + BLOCK_STUBLEN;
1791     n->x = w->nodes->x;
1792     break;
1793   }
1794 }
1795 
block_reportname(GCElement * g)1796 char *block_reportname(GCElement *g)
1797 {
1798   static char B[STRMAX];
1799 
1800   if (g->ename)
1801     sprintf(B,"block %s",g->ename);
1802   else
1803     sprintf(B,"unnamed %s block",g->u.block.moduleName);
1804   return B;
1805 }
1806 
Block_SimHitFunc(EditState * es,GCElement * g)1807 int Block_SimHitFunc(EditState *es,GCElement *g)
1808 {
1809   EditState_selectGate(es,TkGate.ed->tx,TkGate.ed->ty);
1810   return 1;
1811 }
1812 
block_isDataProtected(GCElement * g)1813 int block_isDataProtected(GCElement *g)
1814 {
1815   GModuleDef *M = env_findModule(g->u.block.moduleName);
1816   if (M)
1817     return GModuleDef_isDataProtected(M);
1818   return 0;
1819 }
1820 
block_isIntfProtected(GCElement * g)1821 int block_isIntfProtected(GCElement *g)
1822 {
1823   GModuleDef *M = env_findModule(g->u.block.moduleName);
1824   if (M)
1825     return GModuleDef_isIntfProtected(M);
1826   return 0;
1827 }
1828 
block_isFixedPort(GCElement * g)1829 int block_isFixedPort(GCElement *g)
1830 {
1831   GModuleDef *M = env_findModule(g->u.block.moduleName);
1832   if (M)
1833     return (M->m_pptype == PPT_FIXED);
1834   return 0;
1835 }
1836 
Block_Rotate(GCElement * g,int centX,int centY,int rdir)1837 void Block_Rotate(GCElement *g,int centX, int centY,int rdir)
1838 {
1839   int x = g->xpos + g->u.block.gwidth/2;
1840   int y = g->ypos + g->u.block.gheight/2;
1841   int nx,ny,t,i,j;
1842 
1843   ob_touch(g);
1844   nx = rotateX(x - centX,y - centY, rdir) + centX;
1845   ny = rotateY(x - centX,y - centY, rdir) + centY;
1846 
1847   t = g->u.block.gwidth;
1848   g->u.block.gwidth = g->u.block.gheight;
1849   g->u.block.gheight = t;
1850 
1851   g->xpos = nx - g->u.block.gwidth/2;
1852   g->ypos = ny - g->u.block.gheight/2;
1853   g->orient = (g->orient + 4 + rdir) % 4;
1854 
1855   /*
1856    * We need to shift the pads that the wires are attached to.
1857    */
1858   if (rdir > 0) {
1859     for (j = 0;j < 3;j++) {
1860       int offset = 4*j;
1861       GWire *tw;
1862 
1863       tw = g->wires[offset+3];
1864       for (i = 2;i >= 0;i--) {
1865 	g->wires[offset+i+1] = g->wires[offset+i];
1866       }
1867       g->wires[offset] = tw;
1868     }
1869   } else {
1870     for (j = 0;j < 3;j++) {
1871       int offset = 4*j;
1872       GWire *tw;
1873 
1874       tw = g->wires[offset];
1875       for (i = 0;i <= 2;i++) {
1876 	g->wires[offset+i] = g->wires[offset+i+1];
1877       }
1878       g->wires[offset+3] = tw;
1879     }
1880   }
1881 
1882   SetModified(MF_INTERFACE);
1883   SynchronizeInterface();
1884 }
1885 
wire_blockforce(GWire * w,int p,int retry)1886 void wire_blockforce(GWire *w,int p,int retry)
1887 {
1888   switch (p) {
1889   case BLOCK_TIN :
1890   case BLOCK_TOUT :
1891     wire_force(w,1,retry);
1892     break;
1893   case BLOCK_BIN :
1894   case BLOCK_BOUT :
1895     wire_force(w,3,retry);
1896     break;
1897   case BLOCK_LIN :
1898   case BLOCK_LOUT :
1899     wire_force(w,2,retry);
1900     break;
1901   case BLOCK_RIN :
1902   case BLOCK_ROUT :
1903     wire_force(w,0,retry);
1904     break;
1905   }
1906 }
1907 
Block_wireSnap(GCElement * g,GWire * w,int * mod,int retry)1908 GWireNode *Block_wireSnap(GCElement *g,GWire *w,int *mod,int retry)
1909 {
1910   int p,n;
1911 
1912   if (posongate(w,w->gate,&p,&n) != 0)
1913     return w->nodes;
1914   wire_blockforce(w,p,retry);
1915   return w->nodes;
1916 }
1917 
1918 /*****************************************************************************
1919  *
1920  * Set a parameter port for an instance of a module.
1921  *
1922  * Parameters:
1923  *      g		Instance on which to set value
1924  *      name		Name of parameter
1925  *      value		New value of parameter
1926  *
1927  * Parameters are stored internally as an array of name/value pairs with the
1928  * syntax "name=value".
1929  *
1930  *****************************************************************************/
Block_setParmPort(GCElement * g,const char * name,const char * value)1931 void Block_setParmPort(GCElement *g,const char *name,const char *value)
1932 {
1933   char buf[STRMAX];
1934   int i;
1935 
1936   if (!name) {
1937     yyerror("missing parameter name on instance '%s'.",g->ename);
1938     return;
1939   }
1940 
1941   /*
1942    * If 'name' is already a parameter, just change its value.
1943    */
1944   for (i = 0;i < g->u.block.numModParms;i++) {
1945     int len = strlen(name);
1946     if (strncmp(g->u.block.modParms[i],name,len) == 0 && g->u.block.modParms[i][len] == '=') {
1947       if (strcmp(g->u.block.modParms[i]+len+1,value) != 0) {
1948 	ob_free(g->u.block.modParms[i]);
1949 	sprintf(buf,"%s=%s",name,value);
1950 	ob_touch(g->u.block.modParms);
1951 	g->u.block.modParms[i] = ob_strdup(buf);
1952 	return;
1953       }
1954     }
1955   }
1956 
1957   /*
1958    * Add the parameter as a new parameter
1959    */
1960   ob_touch(g);
1961 
1962   if (g->u.block.numModParms == 0) {
1963     g->u.block.modParms = (char**) ob_malloc(sizeof(char*)*8,"char**");
1964   } else if ((g->u.block.numModParms % 8) == 0) {
1965     g->u.block.modParms = (char**) ob_realloc(g->u.block.modParms,sizeof(char*)*(g->u.block.numModParms+8));
1966   }
1967 
1968   sprintf(buf,"%s=%s",name,value);
1969   ob_touch(g->u.block.modParms);
1970   g->u.block.modParms[g->u.block.numModParms++] = ob_strdup(buf);
1971 }
1972 
Block_unsetParmPort(GCElement * g,const char * name)1973 void Block_unsetParmPort(GCElement *g,const char *name)
1974 {
1975   int i;
1976   for (i = 0;i < g->u.block.numModParms;i++) {
1977     int len = strlen(name);
1978     if (strncmp(g->u.block.modParms[i],name,len) == 0 && g->u.block.modParms[i][len] == '=') {
1979       ob_touch(g);
1980       ob_touch(g->u.block.modParms);
1981       ob_free(g->u.block.modParms[i]);
1982       g->u.block.modParms[i] = g->u.block.modParms[--g->u.block.numModParms];
1983     }
1984   }
1985 }
1986 
Block_getParmPort(GCElement * g,const char * name)1987 const char *Block_getParmPort(GCElement *g,const char *name)
1988 {
1989   int i;
1990   for (i = 0;i < g->u.block.numModParms;i++) {
1991     int len = strlen(name);
1992     if (strncmp(g->u.block.modParms[i],name,len) == 0 && g->u.block.modParms[i][len] == '=') {
1993       return g->u.block.modParms[i]+len+1;
1994     }
1995   }
1996   return 0;
1997 }
1998 
1999 /*****************************************************************************
2000  *
2001  * Get all wires from a pad and put them into an array.
2002  *
2003  * Parameters:
2004  *      g		Block or symbol block instance
2005  *      p		Pad number to extract (or -1 for all)
2006  *      wa		Array of wires for return
2007  *      n		Allocated length of array
2008  *
2009  *****************************************************************************/
block_getPadWires(GCElement * g,int p,GWire ** wa,int n)2010 int block_getPadWires(GCElement *g,int p,GWire **wa,int n)
2011 {
2012   GWire *w;
2013   int count = 0;
2014   int isSymbol = (GCElement_getType(g) == GC_SYMBLOCK);
2015 
2016   if (p < 0) {
2017     int np = GCElement_numPads(g);
2018     for (p = 0;p < np;p++) {
2019       for (w = g->wires[p];w;w = w->next) {
2020 	if (count < n) {
2021 	  wa[count] = w;
2022 	  if (isSymbol) {
2023 	    const char *name = GCElement_getPadName(g,p);
2024 	    ob_touch(w);
2025 	    w->name = ob_strdup(name);
2026 	  }
2027 	}
2028 	count++;
2029       }
2030     }
2031   } else {
2032     for (w = g->wires[p];w;w = w->next) {
2033       if (count < n) {
2034 	wa[count] = w;
2035 	if (isSymbol) {
2036 	  const char *name = GCElement_getPadName(g,p);
2037 	  ob_touch(w);
2038 	  w->name = ob_strdup(name);
2039 	}
2040       }
2041       count++;
2042     }
2043   }
2044 
2045   return count;
2046 }
2047 
2048 /*****************************************************************************
2049  *
2050  * Comparison function for qsort()ing array of wires by name
2051  *
2052  *****************************************************************************/
wireNameCmp(const void * _w1,const void * _w2)2053 static int wireNameCmp(const void *_w1,const void *_w2)
2054 {
2055   GWire *w1 = *(GWire**)_w1;
2056   GWire *w2 = *(GWire**)_w2;
2057 
2058   if (!w1->name || !w2->name) return 0;
2059 
2060   return strcmp(w1->name,w2->name);
2061 }
2062 
block_isIsomorphic_symblockports(GCElement * g1,GCElement * g2)2063 int block_isIsomorphic_symblockports(GCElement *g1,GCElement *g2)
2064 {
2065   return 0;
2066 }
2067 
block_isIsomorphic_blockports(GCElement * g1,GCElement * g2)2068 int block_isIsomorphic_blockports(GCElement *g1,GCElement *g2)
2069 {
2070   int i,j,n;
2071 
2072   /*
2073    * Now check port positions
2074    */
2075   n = GCElement_numPads(g1);
2076   for (i = 0;i < n;i++) {
2077     int k = 4*(i/4) + ((i+g1->orient)%4);
2078     int pd1 = GCElement_getPadDir(g1,k);
2079     int pd2 = GCElement_getPadDir(g2,i);
2080     /** @TODO to remove */
2081     /*
2082     const char *pn1 = GCElement_getPadName(g1,k);
2083     const char *pn2 = GCElement_getPadName(g2,i);
2084     */
2085     GWire *pw1[1024];
2086     GWire *pw2[1024];
2087     int npw1 = block_getPadWires(g1,k,pw1,1024);
2088     int npw2 = block_getPadWires(g2,i,pw2,1024);
2089 
2090     if (pd1 != pd2) return 0; /* Pad directions differ */
2091     if (npw1 != npw2) return 0; /* # wires on pad differ */
2092 
2093     qsort(pw1,npw1,sizeof(GWire*),wireNameCmp);
2094     qsort(pw2,npw2,sizeof(GWire*),wireNameCmp);
2095 
2096     for (j = 0;j < npw1;j++) {
2097       GWire *w1 = pw1[j];
2098       GWire *w2 = pw2[j];
2099       int x1,y1,x2,y2,cx,cy;
2100 
2101       if (w1->name && w2->name && strcmp(w1->name,w2->name) != 0) {
2102 #if 0
2103 	printf("port %s != %s\n",w1->name,w2->name);
2104 #endif
2105 	return 0;
2106       }
2107 
2108       if (GNet_getNBits(w1->net) != GNet_getNBits(w2->net)) {
2109 #if 0
2110 	printf("port %d != %d\n",GNet_getNBits(w1->net), GNet_getNBits(w2->net));
2111 #endif
2112 	return 0;
2113       }
2114 
2115       x1 = w1->nodes->x - g1->xpos - g1->u.block.gwidth/2;
2116       y1 = w1->nodes->y - g1->ypos - g1->u.block.gheight/2;
2117 
2118       cx = w2->nodes->x - g2->xpos - g2->u.block.gwidth/2;
2119       cy = w2->nodes->y - g2->ypos - g2->u.block.gheight/2;
2120 
2121       x2 = rotateX(cx,cy,g1->orient);
2122       y2 = rotateY(cx,cy,g1->orient);
2123 
2124       if (x1 != x2 || y1 != y2) {
2125 #if 0
2126 	printf("port %s@(%d,%d)  !=  %s@(%d,%d)\n",
2127 	       w1->name,x1,y1,w2->name,x2,y2);
2128 #endif
2129 	return 0;
2130       }
2131     }
2132   }
2133 
2134   return 1;
2135 }
2136 
2137 
2138 /*****************************************************************************
2139  *
2140  * Test to see if g1 and g2 are isomorphic.
2141  *
2142  * Parameters:
2143  *       g1,g2		Elements to be compared
2144  *
2145  *****************************************************************************/
block_isIsomorphic(GCElement * g1,GCElement * g2)2146 int block_isIsomorphic(GCElement *g1,GCElement *g2)
2147 {
2148   /** @TODO to remove */
2149   /* int i,j,n; */
2150 
2151   /*
2152    * Types must match
2153    */
2154   if (GCElement_getType(g1) != GCElement_getType(g2))
2155     return 0;
2156 
2157 
2158   if (GCElement_getType(g1) == GC_BLOCK) {
2159     /*
2160      * Normal blocks must match width/height (may be rotated though)
2161      */
2162     int width = g2->u.block.gwidth;
2163     int height = g2->u.block.gheight;
2164 
2165     if (((g1->orient+4-g2->orient) % 2) == 1) {
2166       int swap = width;
2167       width = height;
2168       height = swap;
2169     }
2170 
2171     if (g1->u.block.gheight != height)
2172       return 0;
2173     if (g1->u.block.gwidth != width)
2174       return 0;
2175   } else {
2176     /*
2177      * Symbol blocks must match symbol data
2178      */
2179     if (g1->u.block.symbol != g2->u.block.symbol)
2180       return 0;
2181   }
2182 
2183   /*
2184    * Check number of pads
2185    */
2186   if (GCElement_numPads(g1) != GCElement_numPads(g2))
2187     return 0;
2188 
2189   if (GCElement_getType(g1) == GC_BLOCK)
2190     return block_isIsomorphic_blockports(g1,g2);
2191   else
2192     return block_isIsomorphic_symblockports(g1,g2);
2193 }
2194 
findArrayPort(GWire ** pw,int npw,const char * name)2195 static int findArrayPort(GWire **pw,int npw,const char *name)
2196 {
2197   int i;
2198 
2199   for (i = 0;i < npw;i++)
2200     if (pw[i] && strcmp(pw[i]->name,name) == 0)
2201       return i;
2202 
2203   return -1;
2204 }
2205 
2206 /*****************************************************************************
2207  *
2208  * Updates the interface of a module instance with the registered interface.
2209  *
2210  * Paramaters:
2211  *      g		module instance to be updated
2212  *      m		parent module of g
2213  *
2214  *****************************************************************************/
block_updateInterface(GCElement * g,GModuleDef * m)2215 void block_updateInterface(GCElement *g,GModuleDef *m)
2216 {
2217   GCElement *ug = env_getInterface(g);	/* Get current interface */
2218   GWire *pw[1024];
2219   int npw,n;
2220   GWire *w;
2221   int i;
2222   int draw_p = (TkGate.circuit->es->env == m);
2223   int px,py;
2224   PHash *resizeTable;
2225 
2226   /*
2227    * Nothing to update to.
2228    */
2229   if (!ug) return;
2230 
2231   /*
2232    * Don't update if the existing interface matches.
2233    */
2234   if (block_isIsomorphic(g,ug)) {
2235     return;
2236   }
2237 
2238   if (draw_p)
2239     gate_draw(g,GD_NOWIRE);
2240 
2241   /*
2242    * Get all of the ports on the old interface
2243    */
2244   npw = block_getPadWires(g,-1,pw,1024);
2245   qsort(pw,npw,sizeof(GWire*),wireNameCmp);
2246 
2247   ob_touch(g);
2248 
2249   /*
2250    * Detach all of the current wires
2251    */
2252   n = GCElement_numPads(g);
2253 #if 0
2254   printf("detaching gate at (%d,%d)\n",g->xpos,g->ypos);
2255 #endif
2256   for  (i = 0;i < n;i++) {
2257 #if 0
2258     printf("  detach %s: (%d, %d)\n", g->wires[i]->name, g->wires[i]->nodes->x, g->wires[i]->nodes->y);
2259 #endif
2260     g->wires[i] = 0;
2261   }
2262   for  (i = 0;i < npw;i++) {
2263     ob_touch(pw[i]);
2264     pw[i]->gate = 0;
2265     pw[i]->next = 0;
2266   }
2267 
2268   /*
2269    * Update core block parameters
2270    */
2271   g->typeinfo = ug->typeinfo;
2272   g->u.block = ug->u.block;
2273   if (GCElement_getType(g) == GC_SYMBLOCK) {
2274     GModSymbol_attach(g->u.block.symbol);
2275   }
2276 
2277   /*
2278    * Swap block size for rotation if necessary and get the relative center point (px,py)
2279    */
2280   if (GCElement_getType(ug) == GC_BLOCK) {
2281     g->xpos += g->u.block.gwidth/2;
2282     g->ypos += g->u.block.gheight/2;
2283 
2284     if ((g->orient % 2) != 0) {
2285       int swap = g->u.block.gwidth;
2286       g->u.block.gwidth = g->u.block.gheight;
2287       g->u.block.gheight = swap;
2288       px = ug->u.block.gheight/2;
2289       py = ug->u.block.gwidth/2;
2290     } else {
2291       px = ug->u.block.gwidth/2;
2292       py = ug->u.block.gheight/2;
2293     }
2294     g->xpos -= g->u.block.gwidth/2;
2295     g->ypos -= g->u.block.gheight/2;
2296   } else {
2297     px = py = 0;
2298   }
2299 
2300   /*
2301    * Reattach ports
2302    */
2303 #if 0
2304   printf("attaching gate at (%d,%d)\n",g->xpos,g->ypos);
2305 #endif
2306   n = GCElement_numPads(ug);
2307   resizeTable = NULL;
2308   for  (i = 0;i < n;i++) {
2309     /*
2310      * Get pad and direction information.
2311      */
2312     GPadInfo *pad = &ug->typeinfo->Pad[i];
2313     /** @TODO to remove */
2314     /*
2315     int dir = GCElement_getPadDir(ug,i);
2316     */
2317     int iodir = pad->iotype;
2318     int j = 4*(i/4) + ((i+g->orient)%4);
2319 
2320     /*
2321      * Do action for all ports on the canonical interface
2322      */
2323     for (w = ug->wires[i];w;w = w->next) {
2324       int p = findArrayPort(pw,npw,w->name);			/* Find wire on original block */
2325       int orient = (g->orient + w->orient) % 4;			/* Required orientation */
2326       int x,y;
2327 
2328       if (GCElement_getType(ug) == GC_BLOCK) {
2329 	int cx = w->nodes->x - ug->xpos - ug->u.block.gwidth/2;	/* x-position relative to center */
2330 	int cy = w->nodes->y - ug->ypos - ug->u.block.gheight/2;/* y-position relative to center */
2331 
2332 	x = g->xpos + rotateX(cx,cy,g->orient) + px;
2333 	y = g->ypos + rotateY(cx,cy,g->orient) + py;
2334       } else {
2335 	int cx = w->nodes->x - ug->xpos;
2336 	int cy = w->nodes->y - ug->ypos;
2337 
2338 	x = g->xpos + rotateX(cx,cy,g->orient);
2339 	y = g->ypos + rotateY(cx,cy,g->orient);
2340       }
2341 #if 0
2342       printf("  attach %s: (%d, %d)\n", ug->wires[i]->name, x, y);
2343 #endif
2344 
2345       if (p < 0) {
2346 	GWire *nw;
2347 	wire_new(m,0,&nw);
2348 	p = block_attach(m,g,nw,nw->driver,x,y,w->name,iodir);
2349 	net_setSize(nw->net,GNet_getNBits(w->net));
2350 	if (draw_p)
2351 	  GWire_draw(nw->driver);
2352       } else {
2353 	if (draw_p)
2354 	  GWire_draw(pw[p]->driver);
2355 
2356 	if (((orient+4-pw[p]->orient) % 2) == 1) {
2357 	  GWire_insertNode(pw[p]);
2358 	}
2359 
2360 	pw[p]->orient = orient;
2361 	pw[p]->next = g->wires[j];
2362 	g->wires[j] = pw[p];
2363 	pw[p]->gate = g;
2364 
2365 	wire_moveto(pw[p]->nodes,x,y);
2366 	GWire_snap(pw[p]->driver);
2367 
2368 	if (GNet_getNBits(pw[p]->net) != GNet_getNBits(w->net)) {
2369 	  if (!resizeTable)
2370 	    resizeTable = new_PHash_noob();
2371 	  PHash_insert(resizeTable,pw[p]->net,(void*)(long)GNet_getNBits(w->net));
2372 	}
2373 
2374 	if (draw_p)
2375 	  GWire_draw(pw[p]->driver);
2376 
2377 	pw[p] = 0;
2378       }
2379     }
2380   }
2381 
2382   /*
2383    * Delete wires that are no longer used.
2384    */
2385   for (i = 0;i < npw;i++)
2386     if (pw[i]) {
2387       if (!wire_shorten(pw[i],m,draw_p))
2388 	GWire_draw(pw[i]->driver);
2389     }
2390 
2391   /*
2392    * Update sizes of any nets that have changed size
2393    */
2394   if (resizeTable) {
2395     HashElem *he;
2396 
2397     for (he = Hash_first(resizeTable);he;he = Hash_next(resizeTable,he)) {
2398       GNet *n = (GNet*)PHashElem_key(he);
2399       GNet_draw(n);
2400       net_setSize(n,(unsigned)(long)HashElem_obj(he));
2401       GNet_draw(n);
2402     }
2403     delete_PHash(resizeTable);
2404   }
2405 
2406 
2407   if (draw_p)
2408     gate_draw(g,GD_NOWIRE);
2409 }
2410 
init_block()2411 void init_block()
2412 {
2413   /*****************************************************************************
2414    * Register gate data.
2415    *****************************************************************************/
2416   RegisterGate(&gate_block_info);
2417 }
2418