1 /****************************************************************************
2 Copyright (C) 1987-2015 by Jeffery P. Hansen
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18 Last edit by hansen on Mon Jan 19 18:14:18 2009
19 ****************************************************************************/
20
21 #include <stdlib.h>
22
23 #include "tkgate.h"
24 #include "print.h"
25
26 /*
27 * Flags for Concat_writeWireNums
28 */
29 #define WWN_OUTFIRST 0x0
30 #define WWN_INFIRST 0x1
31 #define WWN_REVIN 0x2
32
33
34
35 #define CONCAT_WIRESPACE 10
36 #define CONCAT_HOOK 5
37
38 #define CONCAT_T_AUTO 0
39 #define CONCAT_T_FIXED 1
40 #define CONCAT_T_TRAN 2
41
42 #define AUTOCHECK_TRIES 500
43
44 void Concat_Draw(GCElement *g,int md);
45 void Concat_AddInput(EditState *es,GCElement*);
46 void Concat_RemovePort(EditState *es,GCElement*,GWire*);
47 GCElement *Concat_Make(EditState **es,GModuleDef *env,int GType,
48 int x,int y,int r,const char *Name,int noWires,const char**,int);
49 void Concat_VerSave(FILE *f,GCElement *g);
50 void Concat_SetProp(GCElement *g,const char *prop,const void *value);
51 int Concat_EditProps(GCElement *g,int isLoadDialog);
52
53 void Concat_GetExtents(GCElement *g,TargetDev_e target,int *minx,int *miny,int *maxx,int *maxy,int *bd);
54 int Concat_HitDistance(GCElement *g,int x,int y);
55 void Concat_PSWrite(GPrint *P,GModLayout*,GCElement *g);
56 GCElement *Concat_Copy(GModuleDef *M,GCElement *g,int x,int y,unsigned flags);
57
58 static int xBitLab[] = {0,0,0,0};
59 static int yBitLab[] = {0,8,0,0};
60 static int jBitLab[] = {RJ,RJ,LJ,RJ};
61
62 GPadLoc concat_in_loc[] = {
63 {-5,-11,-5,11,D_LEFT},
64 {-11,5,11,5,D_DOWN},
65 {5,11,5,-11,D_RIGHT},
66 {11,-5,-11,-5,D_UP}};
67
68 GPadLoc concat_out_loc[] = {
69 {1,0,1,0,D_RIGHT},
70 {0,-1,0,-1,D_UP},
71 {-1,0,-1,0,D_LEFT},
72 {0,1,0,1,D_DOWN}};
73
74 static char *psConcat[] = {
75 "%",
76 "% [() ...] l x y o concat",
77 "%",
78 "/psconcat {",
79 " dup 5 1 roll",
80 " startgate",
81 " dup 2 div -5 exch moveto",
82 " 5 0 rlineto",
83 " dup neg 0 exch rlineto",
84 " -5 0 rlineto",
85 " stroke",
86 " 8 rfont",
87 " exch -180 eq {",
88 " 180 rotate",
89 " 2 div neg 6 exch 12 add moveto",
90 " {",
91 " gsave show grestore",
92 " 0 10 rmoveto",
93 " } forall",
94 " } {",
95 " 2 div -6 exch 8 sub moveto",
96 " {",
97 " gsave dup stringwidth pop neg 0 rmoveto show grestore",
98 " 0 -10 rmoveto",
99 " } forall",
100 " } ifelse",
101 " grestore",
102 "} def",
103 0
104 };
105
106 GGateInfo gate_concat_info = {
107 GC_CONCAT,
108 "CONCAT",
109 "concat",0x0,
110 "psconcat",psConcat,
111 -1,-1,
112
113 {{"w", {"gm.io",0}, {"gm.io.merge",0,0,500}, "gat_make CONCAT"},
114 {0}},
115
116 0,
117
118 2,{{"I",IN,1,2,concat_in_loc,1},{"Z",OUT,2,1,concat_out_loc,0}},
119 {{5,-20,LJ},{-5,-5,RJ},{-5,-20,RJ},{-7,15,RJ}},
120 {1,1,0,1},
121
122 {0},
123
124 Concat_Make,
125 Nop_WriteCellDef,
126 Generic_Init,
127 Generic_Delete,
128 Concat_GetExtents,
129 Concat_HitDistance,
130 Concat_Draw,
131 Generic_Move,
132 Concat_Copy,
133 Concat_AddInput,
134 Concat_AddInput,
135 Err_AddInOut,
136 Generic_Rotate,
137 Concat_RemovePort,
138 Err_ChangePin,
139 Nop_SimInitFunc,
140 Nop_SimHitFunc,
141 Concat_PSWrite,
142 Concat_EditProps,
143 Concat_VerSave,
144 Concat_SetProp
145 };
146
Concat_adjustWires(GCElement * g)147 static void Concat_adjustWires(GCElement *g)
148 {
149 int N,L,i,wx,wy,dx,dy;
150 GWire *w;
151 int d = g->u.cat.portDir ? -1 : 1;
152
153 wx = wy = dx = dy = 0;
154
155 N = wire_numOnPad(g->wires[CONCAT_IN]);
156 L = CONCAT_WIRESPACE*(N+1);
157
158
159 switch (g->orient) {
160 case 0 :
161 wx = g->xpos - CONCAT_HOOK;
162 wy = g->ypos + d*L/2;
163 dx = 0;
164 dy = -d*CONCAT_WIRESPACE;
165 break;
166 case 1 :
167 wx = g->xpos + d*L/2;
168 wy = g->ypos + CONCAT_HOOK;
169 dx = -d*CONCAT_WIRESPACE;
170 dy = 0;
171 break;
172 case 2 :
173 wx = g->xpos + CONCAT_HOOK;
174 wy = g->ypos - d*L/2;
175 dx = 0;
176 dy = d*CONCAT_WIRESPACE;
177 break;
178 case 3 :
179 wx = g->xpos - d*L/2;
180 wy = g->ypos - CONCAT_HOOK;
181 dx = d*CONCAT_WIRESPACE;
182 dy = 0;
183 break;
184 }
185
186 for (i = 0,w = g->wires[CONCAT_IN];w;i++, w = w->next) {
187 wx += dx;
188 wy += dy;
189 wire_move(w->nodes,wx-w->nodes->x,wy-w->nodes->y,VERTICAL|HORIZONTAL);
190 }
191 }
192
Concat_Make(EditState ** es,GModuleDef * env,int GType,int x,int y,int r,const char * Name,int noWires,const char ** options,int nOptions)193 GCElement *Concat_Make(EditState **es,GModuleDef *env,int GType,
194 int x,int y,int r,const char *Name,int noWires,const char **options,int nOptions)
195 {
196 GWire *w;
197 GCElement *g;
198
199 if (!(g = Generic_Make(es,env,GType,x,y,r,Name,noWires,options,nOptions)))
200 return NULL;
201
202 ob_touch(g);
203 g->u.cat.portDir = 0;
204 g->u.cat.drivePort = -1;
205 g->u.cat.type = CONCAT_T_AUTO;
206
207 if (es && (g->orient & 0x2)) g->u.cat.portDir = 1;
208
209
210 if (!noWires) {
211 w = wire_drivee(g->wires[CONCAT_OUT]);
212 net_setSize(w->net,2);
213
214 Concat_adjustWires(g);
215 }
216
217 return g;
218 }
219
Concat_Copy(GModuleDef * M,GCElement * g,int x,int y,unsigned flags)220 GCElement *Concat_Copy(GModuleDef *M,GCElement *g,int x,int y,unsigned flags)
221 {
222 GCElement *c_g = Generic_Copy(M,g,x,y,flags);
223 ob_touch(c_g);
224 c_g->u.cat.portDir = g->u.cat.portDir;
225 c_g->u.cat.drivePort = g->u.cat.drivePort;
226 c_g->u.cat.type = g->u.cat.type;
227
228 return c_g;
229 }
230
Concat_GetExtents(GCElement * g,TargetDev_e target,int * minx,int * miny,int * maxx,int * maxy,int * bd)231 void Concat_GetExtents(GCElement *g,TargetDev_e target, int *minx,int *miny,int *maxx,int *maxy,int *bd)
232 {
233 int N = wire_numOnPad(g->wires[CONCAT_IN]);
234 int L = (N > 0) ? (CONCAT_WIRESPACE*(N+1)) : 2*CONCAT_WIRESPACE;
235 int gx = g->xpos;
236 int gy = g->ypos;
237
238 if (bd) *bd = 0;
239
240
241 switch (g->orient) {
242 case 0 :
243 case 2 :
244 *minx = gx - 5;
245 *maxx = gx + 5;
246 *miny = gy-L/2-5;
247 *maxy = gy+L/2-5;
248 break;
249 case 1 :
250 case 3 :
251 *minx = gx-L/2-5;
252 *maxx = gx+L/2-5;
253 *miny = gy - 5;
254 *maxy = gy + 5;
255 break;
256 }
257 }
258
Concat_HitDistance(GCElement * g,int x,int y)259 int Concat_HitDistance(GCElement *g,int x,int y)
260 {
261 int N = wire_numOnPad(g->wires[CONCAT_IN]);
262 int L = (N > 0) ? (CONCAT_WIRESPACE*(N+1)) : 2*CONCAT_WIRESPACE;
263 int gx = g->xpos;
264 int gy = g->ypos;
265
266 switch (g->orient) {
267 case 0 :
268 case 2 :
269 if (y >= gy-L/2-5 && y <= gy+L/2+5) y = gy;
270 break;
271 case 1 :
272 case 3 :
273 if (x >= gx-L/2-5 && x <= gx+L/2+5) x = gx;
274 break;
275 }
276 return distance(x,y,gx,gy);
277 }
278
Concat_Draw(GCElement * g,int md)279 void Concat_Draw(GCElement *g,int md)
280 {
281 int N = wire_numOnPad(g->wires[CONCAT_IN]);
282 int L;
283 int x,y;
284 GWire *w;
285 int lsb;
286 int iod;
287 int atype;
288
289 x = ctow_x(g->xpos);
290 y = ctow_y(g->ypos);
291
292 L = (N > 0) ? (CONCAT_WIRESPACE*(N+1)) : 2*CONCAT_WIRESPACE;
293
294 switch (g->orient) {
295 case 0 :
296 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x,y+L/2,x,y-L/2);
297 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x,y+L/2+1,x-CONCAT_HOOK,y+L/2+1);
298 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x,y-L/2-1,x-CONCAT_HOOK,y-L/2-1);
299 if (g->selected) {
300 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x-1,y+L/2,x-1,y-L/2);
301 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x,y+L/2+2,x-CONCAT_HOOK,y+L/2+2);
302 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x,y-L/2-2,x-CONCAT_HOOK,y-L/2-2);
303 }
304 break;
305 case 1 :
306 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x+L/2,y,x-L/2,y);
307 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x+L/2+1,y,x+L/2+1,y+CONCAT_HOOK);
308 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x-L/2-1,y,x-L/2-1,y+CONCAT_HOOK);
309 if (g->selected) {
310 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x+L/2,y+1,x-L/2,y+1);
311 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x+L/2+2,y,x+L/2+2,y+CONCAT_HOOK);
312 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x-L/2-2,y,x-L/2-2,y+CONCAT_HOOK);
313 }
314 break;
315 case 2 :
316 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x,y+L/2,x,y-L/2);
317 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x,y+L/2+1,x+CONCAT_HOOK,y+L/2+1);
318 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x,y-L/2-1,x+CONCAT_HOOK,y-L/2-1);
319 if (g->selected) {
320 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x+1,y+L/2,x+1,y-L/2);
321 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x,y+L/2+2,x+CONCAT_HOOK,y+L/2+2);
322 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x,y-L/2-2,x+CONCAT_HOOK,y-L/2-2);
323 }
324 break;
325 case 3 :
326 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x+L/2,y,x-L/2,y);
327 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x+L/2+1,y,x+L/2+1,y-CONCAT_HOOK);
328 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x-L/2-1,y,x-L/2-1,y-CONCAT_HOOK);
329 if (g->selected) {
330 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x+L/2,y-1,x-L/2,y-1);
331 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x+L/2+2,y,x+L/2+2,y-CONCAT_HOOK);
332 ZDrawLine(TkGate.D,TkGate.W,TkGate.instGC,x-L/2-2,y,x-L/2-2,y-CONCAT_HOOK);
333 }
334 break;
335 }
336
337 gate_drawWires(g,md);
338
339 if (g->selected)
340 XSetFont(TkGate.D,TkGate.instGC,TkGate.stextbXF[TkGate.circuit->zoom_factor]->fid);
341 else
342 XSetFont(TkGate.D,TkGate.instGC,TkGate.stextXF[TkGate.circuit->zoom_factor]->fid);
343
344 if (g->u.cat.drivePort == CONCAT_OUT)
345 iod = OUT;
346 else if (g->u.cat.drivePort == CONCAT_IN)
347 iod = IN;
348 else {
349 iod = ANY;
350 }
351
352 if (g->u.cat.type == CONCAT_T_AUTO) {
353 atype = IODT_PLAIN;
354 } else if (g->u.cat.type == CONCAT_T_FIXED)
355 atype = IODT_BOXED;
356 else {
357 atype = IODT_BOXED;
358 iod = TRI;
359 }
360
361 DrawPinIOMark(g->wires[CONCAT_OUT],
362 ((g->typeinfo->Pad[CONCAT_OUT].Loc[0].dir + g->orient) % 4), iod,atype);
363
364 lsb = 0;
365 for (w = g->wires[CONCAT_IN];w;w = w->next) {
366 char buf[STRMAX];
367
368 if (w->net->n_nbits == 1)
369 sprintf(buf,"%d",lsb);
370 else
371 sprintf(buf,"%d:%d",lsb+w->net->n_nbits-1,lsb);
372 lsb += w->net->n_nbits;
373
374 x = w->nodes->x + xBitLab[g->orient];
375 y = w->nodes->y + yBitLab[g->orient];
376
377 dce_DrawString(TkGate.instGC,x,y,jBitLab[g->orient],buf);
378 }
379
380 if (g->ename && g->show_name)
381 gate_drawgatename(g,g->ename);
382 }
383
Concat_AddInput(EditState * es,GCElement * g)384 void Concat_AddInput(EditState *es,GCElement *g)
385 {
386 GWire *e1,*e2;
387
388 gate_draw(g,0);
389
390 wire_new(es->env,&e1,&e2);
391
392 ob_touch(g);
393 ob_touch(e1->nodes);
394 ob_touch(e2->nodes);
395
396 e1->nodes->x = e2->nodes->x = 0;
397 e1->nodes->y = e2->nodes->y = 0;
398
399 g->wires[CONCAT_IN] = wire_append(g->wires[CONCAT_IN],e1);
400 e1->gate = g;
401 e1->orient = g->typeinfo->Pad[CONCAT_IN].Loc[g->orient].dir;
402
403 switch (e1->orient) {
404 case D_RIGHT :
405 e2->nodes->x += TKGATE_STUBLEN;
406 break;
407 case D_UP :
408 e2->nodes->y -= TKGATE_STUBLEN;
409 break;
410 case D_LEFT :
411 e2->nodes->x -= TKGATE_STUBLEN;
412 break;
413 case D_DOWN :
414 e2->nodes->y += TKGATE_STUBLEN;
415 break;
416 }
417
418 wire_finalizeNet(e1);
419 Concat_adjustWires(g);
420
421 gate_draw(g,0);
422 }
423
Concat_RemovePort(EditState * es,GCElement * g,GWire * w)424 void Concat_RemovePort(EditState *es,GCElement *g,GWire *w)
425 {
426 Generic_RemovePort(es,g,w);
427 Concat_adjustWires(g);
428 }
429
Concat_EditProps(GCElement * g,int isLoadDialog)430 int Concat_EditProps(GCElement *g,int isLoadDialog)
431 {
432 Tcl_Interp *tcl = TkGate.tcl;
433
434 Generic_EditProps(g,isLoadDialog);
435 if (isLoadDialog) {
436 DoTcl("set ::edgat_catdir %d",g->u.cat.portDir);
437
438 switch (g->u.cat.type) {
439 case CONCAT_T_FIXED : DoTcl("set ::edgat_sigdir %d",g->u.cat.drivePort); break;
440 case CONCAT_T_AUTO : DoTcl("set ::edgat_sigdir 2"); break;
441 case CONCAT_T_TRAN : DoTcl("set ::edgat_sigdir 3"); break;
442 }
443 } else {
444 const char *p;
445 if ((p = Tcl_GetVar(tcl,"edgat_catdir",TCL_GLOBAL_ONLY))) {
446 int eb;
447
448 if (sscanf(p,"%d",&eb) == 1 && eb != g->u.cat.portDir) {
449 ob_touch(g);
450 gate_draw(g,0);
451 g->u.cat.portDir = eb;
452 Concat_adjustWires(g);
453 gate_draw(g,0);
454 }
455 }
456 if ((p = Tcl_GetVar(tcl,"edgat_sigdir",TCL_GLOBAL_ONLY))) {
457 int sd;
458 int newtype = g->u.cat.type;
459 int newdrive = g->u.cat.drivePort;
460
461 if (sscanf(p,"%d",&sd) == 1) {
462 switch (sd) {
463 case 0 :
464 case 1 :
465 newtype = CONCAT_T_FIXED; newdrive = sd;
466 break;
467 case 2 :
468 newtype = CONCAT_T_AUTO;
469 if (g->u.cat.type != CONCAT_T_AUTO)
470 newdrive = -1;
471 break;
472 case 3 :
473 newtype = CONCAT_T_TRAN;
474 break;
475 }
476 }
477
478 if (newtype != g->u.cat.type || newdrive != g->u.cat.drivePort) {
479 ob_touch(g);
480 gate_draw(g,GD_NOWIRE);
481 g->u.cat.type = newtype;
482 g->u.cat.drivePort = newdrive;
483 gate_draw(g,GD_NOWIRE);
484 }
485 }
486 }
487
488 return 0;
489 }
490
491
Concat_SetProp(GCElement * g,const char * prop,const void * value)492 void Concat_SetProp(GCElement *g,const char *prop,const void *value)
493 {
494 if (strcmp(prop,"/dr") == 0) {
495 int n = *((int*)value);
496 ob_touch(g);
497 g->u.cat.portDir = n;
498 } else if (strcmp(prop,"/tp") == 0) {
499 int n = *((int*)value);
500 ob_touch(g);
501 g->u.cat.type = n;
502 } else if (strcmp(prop,"/drp") == 0) {
503 int n = *((int*)value);
504 ob_touch(g);
505 g->u.cat.drivePort = n;
506 }
507 }
508
Concat_GateParmList(FILE * f,GCElement * g)509 int Concat_GateParmList(FILE *f,GCElement *g)
510 {
511 GWire *outw = g->wires[CONCAT_OUT];
512 GWire *w;
513 int first_pin;
514
515 first_pin = 1;
516 fprintf(f," ({");
517
518 for (w = g->wires[CONCAT_IN];w;w = w->next) {
519 if (!first_pin)
520 fprintf(f,", ");
521 first_pin = 0;
522
523 fprintf(f,"%s",w->net->n_signame);
524 }
525 fprintf(f,"}, %s);",outw->net->n_signame);
526 return 0;
527 }
528
529 /*****************************************************************************
530 *
531 * Write the list of ports on the 'multi-port' pad in the correct order.
532 *
533 * Parameters:
534 * f File on which to write
535 * g Device from which ports should be found.
536 *
537 * Writes the ports on the CONCAT_IN pad to the output file.
538 *
539 *****************************************************************************/
Concat_writeMPorts(FILE * f,GCElement * g)540 static void Concat_writeMPorts(FILE *f,GCElement *g)
541 {
542 int first_pin = 1;
543 GWire **wires;
544 GWire *w;
545 int n = 0;
546 int i;
547
548 for (w = g->wires[CONCAT_IN];w;w = w->next) n++;
549 wires = (GWire**)malloc(sizeof(GWire*)*n);
550 for (w = g->wires[CONCAT_IN], i = 0;w;w = w->next, i++) wires[i] = w;
551
552 for (i = n-1;i >= 0;i--) {
553 if (!first_pin) fprintf(f,", ");
554 first_pin = 0;
555 fprintf(f,"%s",wires[i]->net->n_signame);
556 }
557 free(wires);
558 }
559
560 /*****************************************************************************
561 *
562 * Write the wire numbers for the ports on a concat gate.
563 *
564 *****************************************************************************/
Concat_writeWireNums(FILE * f,GCElement * g,unsigned flags)565 static void Concat_writeWireNums(FILE *f,GCElement *g,unsigned flags)
566 {
567 GWire **wires;
568 GWire *w;
569 int n = 0;
570 int i;
571
572 for (w = g->wires[CONCAT_IN];w;w = w->next) n++;
573 wires = (GWire**)malloc(sizeof(GWire*)*n);
574
575 for (w = g->wires[CONCAT_IN],i=0;w;w = w->next, i++) wires[i] = w;
576
577 fprintf(f," /w:[");
578
579 if (!(flags & WWN_INFIRST))
580 fprintf(f," %d",g->wires[CONCAT_OUT]->nidx);
581
582 if ((flags & WWN_REVIN)) {
583 for (i = 0;i < n;i++)
584 fprintf(f," %d",wires[i]->nidx);
585 } else {
586 for (i = n-1;i >= 0;i--)
587 fprintf(f," %d",wires[i]->nidx);
588 }
589
590 if ((flags & WWN_INFIRST))
591 fprintf(f," %d",g->wires[CONCAT_OUT]->nidx);
592
593 fprintf(f," ]");
594
595 free(wires);
596 }
597
598
599 /*****************************************************************************
600 *
601 * Save concat device in verilog format
602 *
603 * Paramaters:
604 * f File to write to.
605 * g Device to write (must be concat)
606 *
607 *****************************************************************************/
Concat_VerSave(FILE * f,GCElement * g)608 void Concat_VerSave(FILE *f,GCElement *g)
609 {
610 int nbits = g->wires[CONCAT_OUT]->net->n_nbits;
611 int did_output = 0;
612
613 if (g->u.cat.type == CONCAT_T_TRAN) {
614 /* fall through to !did_output block */
615 } else if (g->u.cat.drivePort == CONCAT_IN) {
616 fprintf(f," assign {");
617 Concat_writeMPorts(f,g);
618 fprintf(f,"} = %s; //: CONCAT %s ",g->wires[CONCAT_OUT]->net->n_signame,g->ename);
619 VerilogBasicGateComment(f,g,VGC_NOWIRES);
620 Concat_writeWireNums(f,g,WWN_INFIRST);
621 fprintf(f," /dr:%d /tp:%d /drp:%d",g->u.cat.portDir,g->u.cat.type,g->u.cat.drivePort);
622 fprintf(f,"\n");
623 did_output = 1;
624 } else if (g->u.cat.drivePort == CONCAT_OUT) {
625 fprintf(f," assign %s = {",g->wires[CONCAT_OUT]->net->n_signame);
626 Concat_writeMPorts(f,g);
627 fprintf(f,"}; //: CONCAT %s ",g->ename);
628 VerilogBasicGateComment(f,g,VGC_NOWIRES);
629 Concat_writeWireNums(f,g,WWN_OUTFIRST);
630 fprintf(f," /dr:%d /tp:%d /drp:%d",g->u.cat.portDir,g->u.cat.type,g->u.cat.drivePort);
631 fprintf(f,"\n");
632 did_output = 1;
633 }
634
635 if (!did_output) {
636 fprintf(f," tran %s[%d:%d]",g->ename,nbits-1,0);
637 Concat_GateParmList(f,g);
638 VerilogBasicGateComment(f,g,VGC_NOWIRES|VGC_DOMARK);
639 fprintf(f," /dr:%d /tp:%d /drp:%d",g->u.cat.portDir,g->u.cat.type,g->u.cat.drivePort);
640 Concat_writeWireNums(f,g,WWN_INFIRST|WWN_REVIN);
641 fprintf(f,"\n");
642 }
643 }
644
Concat_PSWrite(GPrint * P,GModLayout * L,GCElement * g)645 void Concat_PSWrite(GPrint *P,GModLayout *L,GCElement *g)
646 {
647 int N = wire_numOnPad(g->wires[CONCAT_IN]);
648 int len = (N > 0) ? (CONCAT_WIRESPACE*(N+1)) : 2*CONCAT_WIRESPACE;
649 char buf[STRMAX];
650 int *wire_nbits;
651 int nwires = 0;
652 int nbits = 0;
653 int ncount;
654 GWire *w;
655
656 Generic_PSLabels(P,g);
657
658 /*
659 ** We need to collect bit-widths of wires into an array, since we don't
660 ** know it which order we will be going through them.
661 */
662 for (w = g->wires[CONCAT_IN];w;w = w->next)
663 {
664 nbits += w->net->n_nbits;
665 nwires++;
666 }
667
668 wire_nbits = malloc(nwires * sizeof(int));
669
670 nwires = 0;
671 for (w = g->wires[CONCAT_IN];w;w = w->next) {
672 wire_nbits[nwires++] = w->net->n_nbits;
673 }
674
675 /*
676 ** Now use this information to print the wires.
677 */
678 fprintf(P->p_f,"[\n");
679 if (g->u.cat.portDir) {
680 int lsb = 0;
681 for (ncount = 0; ncount < nwires; ncount++) {
682 if (wire_nbits[ncount] == 1)
683 sprintf(buf,"%d",lsb);
684 else
685 sprintf(buf,"%d:%d",lsb+wire_nbits[ncount]-1,lsb);
686 fprintf(P->p_f," (%s)\n",buf);
687 lsb += wire_nbits[ncount];
688 }
689 } else {
690 int msb = nbits-1;
691 int ncount = nwires;
692 for (ncount = nwires - 1;ncount >= 0; ncount--) {
693 if (wire_nbits[ncount] == 1)
694 sprintf(buf,"%d",msb);
695 else
696 sprintf(buf,"%d:%d",msb,msb-wire_nbits[ncount]+1);
697 fprintf(P->p_f," (%s)\n",buf);
698 msb -= wire_nbits[ncount];
699 }
700 }
701
702 fprintf(P->p_f,"] %d %d %d %d psconcat\n",len,g->xpos,g->ypos,-g->orient*90);
703 free(wire_nbits);
704 }
705
706 /*****************************************************************************
707 *
708 * Return the port number of the driver (or -1 if not set)
709 *
710 *****************************************************************************/
concat_isDriver(GCElement * g,GWire * w)711 static int concat_isDriver(GCElement *g,GWire *w)
712 {
713 switch (g->u.cat.type) {
714 case CONCAT_T_AUTO :
715 if (g->u.cat.newDrivePort == CONCAT_IN)
716 return w != g->wires[CONCAT_OUT];
717 else if (g->u.cat.newDrivePort == CONCAT_OUT)
718 return w == g->wires[CONCAT_OUT];
719 return 0;
720 case CONCAT_T_FIXED :
721 if (g->u.cat.drivePort == CONCAT_IN)
722 return w != g->wires[CONCAT_OUT];
723 else if (g->u.cat.drivePort == CONCAT_OUT)
724 return w == g->wires[CONCAT_OUT];
725 return 0;
726 case CONCAT_T_TRAN :
727 return 0;
728 }
729
730 return 0;
731 }
732
733
734 /*****************************************************************************
735 *
736 * Test wires on net for drivers
737 *
738 * Parameters:
739 * net Net that we are testing.
740 *
741 * Returns: Non-zero if the net has a driver
742 *
743 *****************************************************************************/
concat_hasDriver(GWire * w)744 static int concat_hasDriver(GWire *w)
745 {
746 int p,n;
747
748 w = wire_other(w);
749 if (w->gate) {
750 GCElement *g = w->gate;
751 int i;
752
753 switch (g->typeinfo->code) {
754 case GC_CONCAT :
755 return concat_isDriver(g,w);
756 case GC_JOINT :
757 for (i = 0;i < 4;i++)
758 if (g->wires[i] && g->wires[i] != w) {
759 if (concat_hasDriver(g->wires[i]))
760 return 1;
761 }
762 break;
763 case GC_TAP :
764 if (w == g->wires[TAP_IN]) {
765 if (concat_hasDriver(g->wires[TAP_OUT]))
766 return 1;
767 } else if (w == g->wires[TAP_OUT]) {
768 if (concat_hasDriver(g->wires[TAP_IN]))
769 return 1;
770 } else
771 return 1;
772 break;
773 case GC_BLOCK :
774 if (posongate(w,w->gate,&p,&n) == 0) {
775 if (w->gate->typeinfo->Pad[p].iotype == OUT)
776 return 1;
777 }
778 break;
779 default :
780 if (posongate(w,w->gate,&p,&n) == 0) {
781 if (w->gate->typeinfo->Pad[p].iotype == OUT || w->gate->typeinfo->Pad[p].iotype == TRI)
782 return 1;
783 }
784 break;
785 }
786 }
787
788 return 0;
789 }
790
791
792 /*****************************************************************************
793 *
794 * Scan module and update direction on any auto concat elements.
795 *
796 * Parameters
797 * M Module to scan
798 * doDraw Redraw any concat elements that changed.
799 *
800 * Note: although we modify the direction member(s) on auto concat elements,
801 * we do not consider this an ob_touch() since we can easily recompute it.
802 *
803 *****************************************************************************/
Concat_updateAutos(GModuleDef * M,int doDraw)804 void Concat_updateAutos(GModuleDef *M,int doDraw)
805 {
806 HashElem *he;
807 int count = 0;
808 GCElement **concats = 0;
809 int i,j;
810
811 #if 0
812 printf("Concat_updateAutos\n");
813 #endif
814
815
816 /*
817 * Count the AUTO wire merge devices and reset the new drive ports
818 * to unknown.
819 */
820 for (he = Hash_first(M->m_gates);he;he = Hash_next(M->m_gates,he)) {
821 GCElement *g = HashElem_obj(he);
822
823 /*
824 * If gate is not a concat with auto directioning, ignore it.
825 */
826 if (g->typeinfo != &gate_concat_info) continue;
827 if (g->u.cat.type != CONCAT_T_AUTO) continue;
828
829 g->u.cat.newDrivePort = -1;
830 count++;
831 }
832 if (!count) return;
833
834 /*
835 * Build temporary array for concat elements and reset counter
836 */
837 concats = (GCElement**) malloc(sizeof(GCElement*)*count);
838 count = 0;
839
840 /*
841 * Collect the wiremerge devices in the array.
842 */
843 for (he = Hash_first(M->m_gates);he;he = Hash_next(M->m_gates,he)) {
844 GCElement *g = HashElem_obj(he);
845
846 /*
847 * If gate is not a concat with auto directioning, ignore it.
848 */
849 if (g->typeinfo != &gate_concat_info) continue;
850 if (g->u.cat.type != CONCAT_T_AUTO) continue;
851 concats[count++] = g;
852 }
853
854 /*
855 * Cycle through wire merge devices up to AUTOCHECK_TRIES times to
856 * set the direction.
857 */
858 for (j = 0;j < AUTOCHECK_TRIES;j++) {
859 int changed = 0;
860 GWire *w;
861
862 #if 0
863 printf(" try %d\n",j);
864 #endif
865
866 for (i = 0;i < count;i++) {
867 GCElement *g = concats[i];
868 int in_has_driver = 0;
869 int out_has_driver = 0;
870 int new_port;
871
872 for (w = g->wires[CONCAT_IN];w;w = w->next) {
873 if (concat_hasDriver(w))
874 in_has_driver = 1;
875 }
876 if (concat_hasDriver(g->wires[CONCAT_OUT]))
877 out_has_driver = 1;
878
879 if (in_has_driver && !out_has_driver) {
880 new_port = CONCAT_OUT;
881 } else if (out_has_driver && !in_has_driver) {
882 new_port = CONCAT_IN;
883 } else if (out_has_driver && in_has_driver) {
884 new_port = -1;
885 } else {
886 new_port = -1;
887 }
888
889 #if 0
890 printf(" %s(in:%d out:%d): %d => %d\n",
891 g->ename,
892 in_has_driver, out_has_driver,
893 g->u.cat.newDrivePort, new_port);
894 #endif
895
896 if (g->u.cat.newDrivePort != new_port) {
897 g->u.cat.newDrivePort = new_port;
898 changed = 1;
899 }
900 }
901 /*
902 * If nothing could be updated, end loop.
903 */
904 if (!changed) break;
905 }
906
907 for (i = 0;i < count;i++) {
908 GCElement *g = concats[i];
909 if (g->u.cat.drivePort != g->u.cat.newDrivePort) {
910 if (doDraw)
911 gate_draw(g,GD_NOWIRE);
912 g->u.cat.drivePort = g->u.cat.newDrivePort;
913 if (doDraw)
914 gate_draw(g,GD_NOWIRE);
915 }
916 }
917
918 free(concats);
919 }
920
init_concat()921 void init_concat()
922 {
923 RegisterGate(&gate_concat_info);
924 }
925