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