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