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 Feb 23 20:48:29 2009
19 ****************************************************************************/
20 /****************************************************************************
21  *
22  * This file contains functions related to the automatic module instance
23  * generation functions.
24  *
25  ***************************************************************************/
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <pwd.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <assert.h>
32 #include <string.h>
33 #include "tkgate.h"
34 
35 #define IGEN_DEBUG 0
36 
37 #define VPITCH  16			/* Space between ports on vertical edges */
38 #define HPITCH  40			/* Space between ports on horizontal edges */
39 #define VMARGIN 16			/* Minimum spacing before labels start on vertical side */
40 #define HMARGIN 20			/* Minimum spacing before labels start on horizontal side */
41 
42 #define NAMEPAD 10			/* Minimum padding on sides of module name label */
43 
44 /*
45  * Map an I/O type and a module side to a block port number.
46  */
blockPortNum(int iotype,int side)47 int blockPortNum(int iotype,int side)
48 {
49   return ((iotype+1) % 3)*4 + ((side+3)%4);
50 }
51 
52 /*
53  * Return a string representing the side a port is on.
54  */
igen_sideStr(int side)55 const char *igen_sideStr(int side)
56 {
57   switch (side) {
58   case PSIDE_TOP :
59     return "top";
60   case PSIDE_BOTTOM :
61     return "bottom";
62   case PSIDE_LEFT :
63     return "left";
64   case PSIDE_RIGHT :
65     return "right";
66   }
67   return "unknown";
68 }
69 
igen_strToSide(const char * side)70 int igen_strToSide(const char *side)
71 {
72   if (strcmp(side,"top") == 0)
73     return PSIDE_TOP;
74   else if (strcmp(side,"bottom") == 0)
75     return PSIDE_BOTTOM;
76   else if (strcmp(side,"left") == 0)
77     return PSIDE_LEFT;
78   else if (strcmp(side,"right") == 0)
79     return PSIDE_RIGHT;
80   else
81     return -1;
82 }
83 
84 /*
85  * Create a new IGPort object.  Note that we use malloc() instead of ob_malloc() since IGPort
86  * objects are only used temporarilly
87  */
new_IGPort(const char * name,int iotype,int side,int bits,int n)88 IGPort *new_IGPort(const char *name,int iotype,int side,int bits,int n)
89 {
90   IGPort *igp = (IGPort*) malloc(sizeof(IGPort));
91   igp->igp_name = strdup(name);
92   igp->igp_iotype = iotype;
93   igp->igp_side = side;
94   igp->igp_bits = bits;
95   igp->igp_pos = n;
96   igp->igp_offset = -1;
97   igp->igp_keep = 0;
98   igp->igp_x = 0;
99   igp->igp_y = 0;
100   return igp;
101 }
102 
delete_IGPort(IGPort * igp)103 void delete_IGPort(IGPort *igp)
104 {
105   free(igp->igp_name);
106   free(igp);
107 }
108 
109 
igp_getName(const IGPort * igp)110 const char *igp_getName(const IGPort *igp)
111 {
112   return igp->igp_name;
113 }
114 
igp_getSize(const IGPort * igp)115 int igp_getSize(const IGPort *igp)
116 {
117   return igp->igp_bits;
118 }
119 
igp_getPos(const IGPort * igp)120 int igp_getPos(const IGPort *igp)
121 {
122   return igp->igp_pos;
123 }
124 
igp_setPos(IGPort * igp,int pos)125 void igp_setPos(IGPort *igp,int pos)
126 {
127   igp->igp_pos = pos;
128 }
129 
igp_getType(const IGPort * igp)130 int igp_getType(const IGPort *igp)
131 {
132   return igp->igp_iotype;
133 }
134 
igp_getSide(const IGPort * igp)135 int igp_getSide(const IGPort *igp)
136 {
137   return igp->igp_side;
138 }
139 
igp_getTypeStr(const IGPort * igp)140 const char *igp_getTypeStr(const IGPort *igp)
141 {
142   return iotypeStr(igp->igp_iotype);
143 }
144 
igp_getSideStr(const IGPort * igp)145 const char *igp_getSideStr(const IGPort *igp)
146 {
147   return igen_sideStr(igp->igp_side);
148 }
149 
150 /*
151  * Compare two ports for the purpose of sorting.  Ports on the same side of the module
152  * are sorted first, then the name is sorted.  Names are sorted alphebetically with the
153  * following exceptions:
154  *
155  * 1) case insensitive
156  * 2) leading '_' is ignored (but will be placed after an identical name without '_')
157  * 3) If a name is of the form 'AAnn' where 'AA' is a string of letters, and 'nn' is
158  *    a string of numbers, then the 'nn' part will be sorted in numeric order.  For
159  *    example, you will get the order: F7, F8, F9, F10, F11, F12 instead of the
160  *    strict alphnumeric order: F10, F11, F12, F7, F8.
161  */
alpha_port_compare(const void * vA,const void * vB)162 static int alpha_port_compare(const void *vA,const void *vB)
163 {
164   const IGPort *A = *(IGPort**)vA;
165   const IGPort *B = *(IGPort**)vB;
166   const char *nameA,*endA;
167   const char *nameB,*endB;
168   int numA;
169   int numB;
170   int negA = 0, negB = 0;
171   int c;
172 
173   /*
174    * Sort by side first
175    */
176   if (igp_getSide(A) != igp_getSide(B))
177     return igp_getSide(A) - igp_getSide(B);
178 
179   /*
180    * Get names and position to first character after the '_'.
181    */
182   nameA = igp_getName(A);
183   nameB = igp_getName(B);
184   if (*nameA == '_') { negA = 1; nameA++; }
185   if (*nameB == '_') { negB = 1; nameB++; }
186 
187   /*
188    * The 'endX' pointers point to null at the end of the string, or to the first of the
189    * terminating sequence of digits.
190    */
191   endA = nameA + strlen(nameA);
192   endB = nameB + strlen(nameB);
193   while (endA > nameA && isdigit(endA[-1])) { endA--; }
194   while (endB > nameB && isdigit(endB[-1])) { endB--; }
195 
196   /*
197    * If the non-numeric parts are of unequal length, then do a standard comparison.
198    */
199   if ( (endA-nameA) != (endB-nameB) ) {
200     c = strcasecmp(nameA,nameB);
201     if (c == 0) return negA - negB;
202     return c;
203   }
204 
205   /*
206    * Compare non-numeric part.  If not an exact match then return which is greater.
207    */
208   c = strncasecmp(nameA,nameB,endA-nameA);
209   if (c != 0)
210     return c;
211 
212   if (negA != negB) {
213     return negA - negB;
214   }
215 
216   if (sscanf(endA,"%d",&numA) == 0)
217     return 1;
218   if (sscanf(endB,"%d",&numB) == 0)
219     return -1;
220 
221   return numA - numB;
222 }
223 
224 /*
225  * Compare ports based on side and position.
226  */
port_compare(const void * va,const void * vb)227 static int port_compare(const void *va,const void *vb)
228 {
229   IGPort *A = *(IGPort**)va;
230   IGPort *B = *(IGPort**)vb;
231 
232   /*
233    * Sort by side first
234    */
235   if (igp_getSide(A) != igp_getSide(B))
236     return igp_getSide(A) - igp_getSide(B);
237 
238   /*
239    * Sort by offset second
240    */
241   return A->igp_offset - B->igp_offset;
242 }
243 
igen_sortPorts(SHash * phash)244 void igen_sortPorts(SHash *phash)
245 {
246   IGPort **port_list;
247   int N = Hash_numElems(phash);
248   int i = 0;
249   HashElem *E;
250 
251   if (N == 0) return;
252 
253   port_list = malloc(N*sizeof(IGPort*));
254 
255 
256   for (E = Hash_first(phash);E;E = Hash_next(phash,E)) {
257     port_list[i++] = (IGPort*) HashElem_obj(E);
258   }
259 
260   qsort(port_list,N,sizeof(IGPort*),alpha_port_compare);
261 
262   for (i = 0;i < N;i++)
263     igp_setPos(port_list[i],i);
264 
265   free(port_list);
266 }
267 
268 /*
269  * Get a sorted array of IGPort elements generated from the
270  * current module interface.  The length of the array is
271  * stored in N.  The returned value, if non-NULL should
272  * be freed with free()
273  */
igen_getInterfacePorts(GModuleDef * M,int * N)274 IGPort **igen_getInterfacePorts(GModuleDef *M,int *N)
275 {
276   GCElement *g = M->m_interface;
277   IGPort **portList;
278   int npads,numports,i,n;
279 
280   *N = 0;
281 
282   if (!g) return 0;
283 
284   /*
285    * Count the total number of ports on the interface
286    */
287   numports = 0;
288   npads = GCElement_numPads(g);
289   for (i = 0;i < npads;i++) {
290     GWire *w;
291     for (w = g->wires[i];w;w = w->next) numports++;
292   }
293   if (numports == 0) return 0;
294   portList = (IGPort**) malloc(sizeof(IGPort*)*numports);
295 
296   /*
297    * Initialize the current port number
298    */
299   n = 0;
300 
301   /*
302    * Collect port data.
303    */
304   for (i = 0;i < npads;i++) {
305     /*    const char *padName = GCElement_getPadName(g,i);*/
306     int iotype = GCElement_getPadDir(g,i);	/* iotype for this pad */
307     GWire *w;
308 
309     /*
310      * Extract the port data from the interface
311      */
312     for (w = g->wires[i];w;w = w->next) {
313       /*      portList[n] = new_IGPort(padName,iotype,w->orient,w->net->nbits,n);*/
314       portList[n] = new_IGPort(w->name,iotype,w->orient,w->net->n_nbits,n);
315 
316       if (GCElement_getType(g) == GC_BLOCK) {
317 	if (w->orient == PSIDE_RIGHT || w->orient == PSIDE_LEFT)
318 	  portList[n]->igp_offset = (g->u.block.gheight*w->offset.num)/w->offset.den;
319 	else
320 	  portList[n]->igp_offset = (g->u.block.gwidth*w->offset.num)/w->offset.den;
321       } else
322 	portList[n]->igp_offset = 0;
323       n++;
324     }
325   }
326 
327   /*
328    * Sort ports by their position along edge
329    */
330   qsort(portList,numports,sizeof(portList[i]),port_compare);
331 
332   /*
333    * Return the number of ports.
334    */
335   *N = numports;
336 
337   return portList;
338 }
339 
340 /*
341  * Get the list of ports used in module
342  */
igen_getModulePorts(GModuleDef * M,int * N)343 static IGPort **igen_getModulePorts(GModuleDef *M,int *N)
344 {
345   SHash *phash = new_SHash();
346   IGPort **portList;
347   HashElem *E;
348   int i;
349 
350   *N = 0;
351 
352   /*
353    * Get ports used in module definition.
354    */
355   if (GModuleDef_getType(M) == MT_NETLIST) {
356     for (i = 0, E = Hash_first(M->m_gates);E;E = Hash_next(M->m_gates,E), i++) {
357       GCElement *g = (GCElement*) HashElem_obj(E);
358       GWire *w = 0;
359       int side = 0;
360       int iotype = 0;
361 
362       switch (g->typeinfo->code) {
363       case GC_LOGICIN :
364 	w = g->wires[0];
365 	side = 2;
366 	iotype = IN;
367 	break;
368       case GC_LOGICOUT :
369 	w = g->wires[0];
370 	side = 0;
371 	iotype = OUT;
372 	break;
373       case GC_LOGICTRI :
374 	w = g->wires[0];
375 	side = 0;
376 	iotype = TRI;
377 	break;
378       }
379       if (w && !SHash_find(phash,w->net->n_signame)) {
380 	IGPort *igp = new_IGPort(w->net->n_signame,iotype,side,w->net->n_nbits,i++);
381 	SHash_insert(phash,w->net->n_signame,igp);
382       }
383     }
384   } else if (GModuleDef_getType(M) == MT_TEXTHDL) {
385     for (i = 0, E = Hash_first(M->m_nets);E;E = Hash_next(M->m_nets,E), i++) {
386       GNet *n = (GNet*) HashElem_obj(E);
387       int side = -1;
388       int iotype = 0;
389 
390       switch (n->n_dtype) {
391       case NT_INPUT :
392 	side = 2;
393 	iotype = IN;
394 	break;
395       case NT_OUTPUT :
396 	side = 0;
397 	iotype = OUT;
398 	break;
399       case NT_INOUT :
400 	side = 0;
401 	iotype = TRI;
402 	break;
403       }
404       if (side >= 0 && !SHash_find(phash,n->n_signame)) {
405 	IGPort *igp = new_IGPort(n->n_signame,iotype,side,n->n_nbits,i++);
406 	SHash_insert(phash,n->n_signame,igp);
407       }
408     }
409   }
410 
411   *N = Hash_numElems(phash);
412 
413   if (*N == 0)
414     return 0;
415 
416   portList = (IGPort**) malloc(sizeof(IGPort*)* *N);
417 
418   for (i = 0, E = Hash_first(phash);E;E = Hash_next(phash,E), i++) {
419     portList[i] = (IGPort*) HashElem_obj(E);
420   }
421 
422   /*
423    * Sort ports by their position along edge
424    */
425   qsort(portList,*N,sizeof(portList[i]),alpha_port_compare);
426 
427 
428   /*
429    * Free up temporary memory from the hash table
430    */
431   delete_SHash(phash);
432 
433   return portList;
434 }
435 
igen_freePortList(IGPort ** portList,int n)436 void igen_freePortList(IGPort **portList,int n)
437 {
438   int i;
439 
440   for (i = 0;i < n;i++) {
441     if (portList[i])
442       delete_IGPort(portList[i]);
443   }
444 
445   free(portList);
446 
447 }
448 
449 
450 /*
451  * Transfer port information from module interface to port list window.
452  */
igen_load(GModuleDef * M,char * aname)453 int igen_load(GModuleDef *M,char *aname)
454 {
455   Tcl_Interp *tcl = TkGate.tcl;
456   GCElement *g = M->m_interface;
457   IGPort **portList;
458   char ploc[STRMAX];
459   char buf[STRMAX];
460   int i,n;
461 
462   if (g && GCElement_getType(g) == GC_SYMBLOCK)
463     Tcl_SetVar2(tcl,aname,"itype","symbol",TCL_GLOBAL_ONLY);
464   else
465     Tcl_SetVar2(tcl,aname,"itype","block",TCL_GLOBAL_ONLY);
466 
467   /*
468    * Get the port list.
469    */
470   portList = igen_getInterfacePorts(M,&n);
471   if (!portList) {
472     /*
473      * No ports on this instance.
474      */
475     Tcl_SetVar2(tcl,aname,"numports","0",TCL_GLOBAL_ONLY);
476     Tcl_SetVar2(tcl,aname,"ok","1",TCL_GLOBAL_ONLY);
477     return 0;
478   }
479 
480   /*
481    * Transfer data to tcl/tk side
482    */
483   for (i = 0;i < n;i++) {
484     IGPort *igp = portList[i];
485 
486     sprintf(ploc,"port:%d",i);
487     sprintf(buf,"%s %s %d %s",
488 	    igp_getName(igp),
489 	    igp_getTypeStr(igp),
490 	    igp_getSize(igp),
491 	    igp_getSideStr(igp));
492     Tcl_SetVar2(tcl,aname,ploc,buf,TCL_GLOBAL_ONLY);
493   }
494 
495   igen_freePortList(portList,n);
496 
497   sprintf(buf,"%d",n);
498   Tcl_SetVar2(tcl,aname,"numports",buf,TCL_GLOBAL_ONLY);
499   Tcl_SetVar2(tcl,aname,"ok","1",TCL_GLOBAL_ONLY);
500 
501   return 0;
502 }
503 
getSideLabelSizes(IGPort ** ports,int numPorts,int * maxWidth,int * totalWidth)504 int getSideLabelSizes(IGPort **ports,int numPorts,int *maxWidth,int *totalWidth)
505 {
506   int j;
507 
508   if (maxWidth) *maxWidth = 0;
509   if (totalWidth) *totalWidth = 0;
510   for (j = 0;j < numPorts;j++) {
511     IGPort *igp = ports[j];
512     const char *name = igp_getName(igp);
513     int w = GKTextWidth(TkGate.stextbXF[1],name,strlen(name));
514     if (maxWidth && w > *maxWidth) *maxWidth = w;
515     if (totalWidth) *totalWidth = w;
516   }
517   return 0;
518 }
519 
520 /*
521  * Get data pertaining to user defined symbols.
522  */
igen_getIcon(GModuleDef * M,char * aname)523 int igen_getIcon(GModuleDef *M,char *aname)
524 {
525   Tcl_Interp *tcl = TkGate.tcl;
526   GCElement *g = M->m_interface;
527   GModSymbol *ms = 0;
528   int i;
529   char buf[STRMAX];
530 
531   if (g)
532     ms = g->u.block.symbol;
533 
534 #if 0
535   sel_clear(TkGate.circuit->es,1);
536 #endif
537 
538   if (ms) {
539     const char *data;
540     int x,y;
541 
542     data = GModSymbol_getNormalIcon(ms,&x,&y);
543     Tcl_SetVar2(tcl,aname,"normalIcon",(char*)data,TCL_GLOBAL_ONLY);
544     sprintf(buf,"%d %d",x,y);
545     Tcl_SetVar2(tcl,aname,"normalOffset",buf,TCL_GLOBAL_ONLY);
546 
547     data = GModSymbol_getSelectIcon(ms,&x,&y);
548     Tcl_SetVar2(tcl,aname,"selectIcon",(char*)data,TCL_GLOBAL_ONLY);
549     sprintf(buf,"%d %d",x,y);
550     Tcl_SetVar2(tcl,aname,"selectOffset",buf,TCL_GLOBAL_ONLY);
551 
552     for (i = 0;i < GModSymbol_numPorts(ms);i++) {
553       char pname[STRMAX],pvalue[STRMAX];
554       GSymPort *msp = GModSymbol_getPort(ms,i);
555       const char *ptype = iotypeStr(msp->msp_type);
556 
557       sprintf(pname,"pplace:%d",i);
558       sprintf(pvalue,"%s %d %d %s %d %d",msp->msp_name,
559 	      msp->msp_x,msp->msp_y,ptype,msp->msp_orient,msp->msp_size);
560       Tcl_SetVar2(tcl,aname,pname,pvalue,TCL_GLOBAL_ONLY);
561     }
562     sprintf(buf,"%d",GModSymbol_numPorts(ms));
563     Tcl_SetVar2(tcl,aname,"numPPlace",buf,TCL_GLOBAL_ONLY);
564   } else {
565     Tcl_SetVar2(tcl,aname,"normalIcon","",TCL_GLOBAL_ONLY);
566     Tcl_SetVar2(tcl,aname,"normalOffset","0 0",TCL_GLOBAL_ONLY);
567     Tcl_SetVar2(tcl,aname,"selectIcon","",TCL_GLOBAL_ONLY);
568     Tcl_SetVar2(tcl,aname,"selectOffset","0 0",TCL_GLOBAL_ONLY);
569     Tcl_SetVar2(tcl,aname,"numPPlace","0",TCL_GLOBAL_ONLY);
570   }
571 
572   return 0;
573 }
574 
575 /*
576  * Store data pertaining to user defined symbols.
577  */
igen_putIcon(GModuleDef * M,char * aname,char * icon)578 int igen_putIcon(GModuleDef *M,char *aname,char *icon)
579 {
580   Tcl_Interp *tcl = TkGate.tcl;
581   const char *data;
582   const char *r;
583   GModSymbol *ms;
584   GCElement *g = M->m_interface;
585   int i;
586   int N = 0;
587   int x,y;
588   int isnew = 0;
589 
590   sel_clear(TkGate.circuit->es,0);	/* caller is responsible for redisplay. */
591 
592   ms = GCElement_getSymbol(g);
593   if (!ms || ms->ms_refCount > 2) {
594     ms = new_GModSymbol();
595     GCElement_setSymbol(g, ms);
596 #if IGEN_DEBUG
597     printf("igen_putIcon %s %s rcount=%d [NEW]\n",aname,icon,ms->ms_refCount);
598 #endif
599     isnew = 1;
600   } else {
601 #if IGEN_DEBUG
602     printf("igen_putIcon %s %s rcount=%d\n",aname,icon,ms->ms_refCount);
603 #endif
604   }
605 
606 
607   if (isnew || !icon || strcmp(icon,"normal") == 0) {
608     data = Tcl_GetVar2(tcl,aname,"normalIcon",TCL_GLOBAL_ONLY);
609     r = Tcl_GetVar2(tcl,aname,"normalOffset",TCL_GLOBAL_ONLY);
610     if (data && r && sscanf(r,"%d %d",&x,&y) == 2)
611       GModSymbol_setNormalIcon(ms,data,x,y);
612   }
613 
614   if (isnew || !icon || strcmp(icon,"select") == 0) {
615     data = Tcl_GetVar2(tcl,aname,"selectIcon",TCL_GLOBAL_ONLY);
616     r = Tcl_GetVar2(tcl,aname,"selectOffset",TCL_GLOBAL_ONLY);
617     if (data && r && sscanf(r,"%d %d",&x,&y) == 2)
618       GModSymbol_setSelectIcon(ms,data,x,y);
619   }
620 
621   GModSymbol_flushPorts(ms);
622   r = Tcl_GetVar2(tcl,aname,"numPPlace",TCL_GLOBAL_ONLY);
623   if (r) sscanf(r,"%d",&N);
624 
625   for (i = 0;i < N;i++) {
626     char pname[STRMAX];
627 
628     sprintf(pname,"pplace:%d",i);
629     r = Tcl_GetVar2(tcl,aname,pname,TCL_GLOBAL_ONLY);
630     if (r) {
631       char name[STRMAX],ptype[STRMAX];
632       int x,y,orient,bsize;
633 
634       if (sscanf(r,"%s %d %d %s %d %d",
635 		 name,&x,&y,ptype,&orient,&bsize) == 6) {
636 	GModSymbol_addPort(ms,new_GSymPort(name,x,y,strIOType(ptype),orient,bsize));
637       }
638     }
639   }
640 
641   SymBlock_remakePorts(g,TkGate.circuit->mid_mod);
642   modint_syncDisplay(M);
643 
644 #if 0
645   printf("## icon=%s  mm=%p[%s]  md=%p[%s]  M=%p[%s]\n",icon,
646 	 TkGate.circuit->mid_mod,  TkGate.circuit->mid_mod->m_name,
647 	 TkGate.circuit->mid_display,  TkGate.circuit->mid_display->m_name,
648 	 TkGate.circuit->es->env,TkGate.circuit->es->env->m_name);
649 #endif
650   if (icon && strcmp(icon,"select") == 0 && TkGate.circuit->mid_display == TkGate.circuit->es->env) {
651     EditState *es = TkGate.circuit->es;
652     GCElement *g = modint_findDisplay(M->m_name);
653 
654     if (g) {
655       sel_appendGate(es,g,0);
656       sel_finish(es);
657       ob_touch(TkGate.circuit);
658       TkGate.circuit->select = g;
659     }
660   }
661 
662 
663   //  SetModified(MF_INTERFACE);
664   FlagRedraw();
665 
666   return 0;
667 }
668 
669 /*****************************************************************************
670  *
671  * Set port position information for ports on symbol blocks.
672  *
673  *****************************************************************************/
igen_setSymbolPortPositions(GModuleDef * M,IGPort ** portList,int numPorts)674 static void igen_setSymbolPortPositions(GModuleDef *M,IGPort **portList,int numPorts)
675 {
676   GCElement *g = M->m_interface;
677   GModSymbol *ms = GCElement_getSymbol(g);
678   int i,j;
679 
680   if (!ms) return;		/* No position information is available */
681 
682   for (i = 0;i < numPorts;i++) {
683     IGPort *p = portList[i];
684 
685     for (j = 0;j < ms->ms_numPorts;j++) {
686       GSymPort *msp = ms->ms_ports[j];
687       if (strcmp(p->igp_name,msp->msp_name) == 0) {
688 	p->igp_keep = 1;
689 	p->igp_x = msp->msp_x;
690 	p->igp_y = msp->msp_y;
691       }
692     }
693   }
694 }
695 
696 /*
697  * Set the port position for 'igp'.
698  */
igen_positionBlockPort(IGPort * igp,int sideCount,IGPort ** ports,int n)699 static void igen_positionBlockPort(IGPort *igp,int sideCount,IGPort **ports,int n)
700 {
701   int i;
702 
703   igp->igp_offset = -1;		/* position is unassigned */
704 
705   for (i = 0;i < n;i++) {
706     if (igp->igp_side == ports[i]->igp_side) {
707       if (sideCount-- == 0) {
708 	igp->igp_offset = ports[i]->igp_offset;
709 	return;
710       }
711     }
712   }
713 }
714 
715 /*
716  * Set the positions of all ports based on the interface position.
717  */
igen_setBlockPortPositions(GModuleDef * M,IGPort ** portList,int numPorts)718 static void igen_setBlockPortPositions(GModuleDef *M,IGPort **portList,int numPorts)
719 {
720   int numInstPorts = 0;
721   IGPort **instPorts = 0;			/* Interface ports from module instance */
722   int sideCount[PSIDE_MAX];			/* How many ports we have positioned on each side */
723   int i;
724 
725   for (i = 0;i < PSIDE_MAX;i++) sideCount[i] = 0;
726 
727   /*
728    * Get interface ports from module interface.
729    */
730   instPorts = igen_getInterfacePorts(M,&numInstPorts);
731 
732   for (i = 0;i < numPorts;i++) {
733     int side = portList[i]->igp_side;
734     igen_positionBlockPort(portList[i],sideCount[side]++,instPorts,numInstPorts);
735   }
736 
737   /*
738    * Free the instance ports
739    */
740   if (instPorts) igen_freePortList(instPorts,numInstPorts);
741 }
742 
743 /*****************************************************************************
744  *
745  * Helping function for igen_generate to get the instance ports
746  *
747  * Parameters:
748  *     M			Module for which to generate instance port list
749  *     aname			Name of tcl variable with interface data
750  *     keep			Non-zero if we are keeping positions
751  *     *numPorts		Return for number of ports found.
752  *
753  *****************************************************************************/
igen_generate_getInstPorts(GModuleDef * M,const char * aname,int * numPorts)754 static IGPort **igen_generate_getInstPorts(GModuleDef *M,const char *aname,int *numPorts)
755 {
756   IGPort **portList = 0;
757   const char *r;
758   int i;
759 
760   /*
761    * Get port count data for module
762    */
763   r = Tcl_GetVar2(TkGate.tcl,aname,"numports",TCL_GLOBAL_ONLY);
764   if (!r || sscanf(r,"%d",numPorts) != 1)
765     return 0;
766 
767   if (*numPorts > 0)
768     portList = (IGPort**) malloc((*numPorts)*sizeof(IGPort*));
769 
770   /*
771    * Get ports and put them in the portlist
772    */
773   for (i = 0;i < *numPorts;i++) {
774     char pid[STRMAX],name[STRMAX],iodirstr[STRMAX],sidestr[STRMAX];
775     int bits,side,iodir;
776 
777     /*
778      * Get port data and create an IGPort for it in portList, and compute
779      * its position.
780      */
781     sprintf(pid,"port:%d",i);
782     r = Tcl_GetVar2(TkGate.tcl,aname,pid,TCL_GLOBAL_ONLY);
783     if (!r || sscanf(r,"%s %s %d %s",name,iodirstr,&bits,sidestr) != 4) return 0;
784     iodir = strIOType(iodirstr);
785     side = igen_strToSide(sidestr);
786     portList[i] = new_IGPort(name,iodir,side,bits,i);
787   }
788 
789   return portList;
790 }
791 
792 /*****************************************************************************
793  * Helping function for igen_generate() to extend the portList to include ports
794  * from the module definition.  Only ports with names not already in the port
795  * list are added.
796  *****************************************************************************/
igen_generate_getModPorts(GModuleDef * M,IGPort ** portList,int * numPorts)797 static IGPort **igen_generate_getModPorts(GModuleDef *M,IGPort **portList,int *numPorts)
798 {
799   int numModPorts;
800   IGPort **modPorts = igen_getModulePorts(M,&numModPorts);
801   SHash *phash;
802   int i;
803 
804   /*
805    * If we have nothing to add, then just return
806    */
807   if (numModPorts <= 0) return portList;
808 
809   /*
810    * If there are no ports in the portList, then return all of the module ports
811    * we found.
812    */
813   if (!portList) {
814     *numPorts = numModPorts;
815     return modPorts;
816   }
817 
818   /*****************************************************************************/
819   /***** We now know we have both existing ports and new module ports	    ****/
820   /***** so we must now merge them.					    ****/
821   /*****************************************************************************/
822 
823 
824   /*
825    * Create a hash table to remember the names of the existing inteface ports.
826    */
827   phash = new_SHash();
828 
829   /*
830    * Expand the portlist array for the worst case
831    */
832   portList = (IGPort**) realloc(portList,(*numPorts+numModPorts)*sizeof(IGPort*));
833 
834   /*
835    * Record the names of already existing ports
836    */
837   for (i = 0;i < *numPorts;i++)
838     SHash_insert(phash,portList[i]->igp_name,portList[i]);
839 
840   /*
841    * Merge any module ports that were not existing instance ports
842    */
843   for (i = 0;i < numModPorts;i++) {
844     if (!SHash_find(phash,modPorts[i]->igp_name)) {
845       portList[(*numPorts)++] = modPorts[i];
846       modPorts[i] = 0;
847     }
848   }
849 
850   /*
851    * Free the module ports.
852    */
853   igen_freePortList(modPorts,numModPorts);
854 
855   delete_SHash(phash);
856 
857   return portList;
858 }
859 
860 /*****************************************************************************
861  *
862  * Helping function for igen_generate() to set positions for ports that are
863  * currently unpositioned on a side.  We assume that any unpositioned ports
864  * are at the end of the list after any positioned ports.
865  *
866  *****************************************************************************/
igen_generate_positionPorts(IGPort ** portList,int numPorts,int side)867 void igen_generate_positionPorts(IGPort **portList,int numPorts,int side)
868 {
869   int currentPos = -1;
870   int i;
871   int margin, pitch;
872 
873   if (side == PSIDE_LEFT || side == PSIDE_RIGHT) {
874     margin = VMARGIN;
875     pitch = VPITCH;
876   } else {
877     margin = HMARGIN;
878     pitch = HPITCH;
879   }
880 
881   for (i = 0;i < numPorts;i++) {
882     IGPort *igp = portList[i];
883 
884     if (igp_getSide(igp) != side) continue;
885 
886     if (igp->igp_offset < 0) {
887       if (currentPos < 0)
888 	currentPos = margin;
889       else
890 	currentPos += pitch;
891       igp->igp_offset = currentPos;
892     } else  if (igp->igp_offset > currentPos) {
893       currentPos = igp->igp_offset;
894     }
895   }
896 }
897 
898 /*****************************************************************************
899  *
900  * Generate module symbol
901  *
902  * Parameters:
903  *      M		Module to generate symbol for
904  *      aname		Tcl array for passing interface data
905  *      which		Source of port data ("int", "mod" or "modint")
906  *      keep		If non-zero port positions will be kept if possible.
907  *
908  *****************************************************************************/
igen_generate_symbol(GModuleDef * M,const char * aname,const char * which,int keep)909 static int igen_generate_symbol(GModuleDef *M,const char *aname,const char *which,int keep)
910 {
911   GCElement *g = M->m_interface;
912   GModSymbol *ms = GCElement_getSymbol(g);
913   IGPort **portList = 0;
914   int numPorts = 0;
915   int i,r;
916   int x,y;
917   int minx,miny,maxx,maxy;
918 
919   EditState_unselectGate(0);
920 
921   /*
922    * We are including current interface ports
923    */
924   if (strcmp(which,"int") == 0 || strcmp(which,"modint") == 0) {
925     portList = igen_generate_getInstPorts(M,aname,&numPorts);
926   }
927 
928   /*
929    * Get module ports if necessary
930    */
931   if (strcmp(which,"mod") == 0 || strcmp(which,"modint") == 0) {
932     portList = igen_generate_getModPorts(M,portList,&numPorts);
933   }
934 
935   if (keep)
936     igen_setSymbolPortPositions(M,portList,numPorts);
937 
938 
939   /*
940    * Get a module symbol object for the module interface using the following rules:
941    *    1) If the module does not have a symbol interface, create one.
942    *    2) If the reference count of the existing interface is greater than 2, copy it.
943    *    3) Otherwise, use the existing module symbol.
944    */
945   if (!ms) {
946     ms = new_GModSymbol();
947 #if IGEN_DEBUG
948     printf("igen_generate_symbol %s rcount=%d [NEW]\n",aname,ms->ms_refCount);
949 #endif
950   } else if (ms->ms_refCount > 2) {
951     ms = copy_GModSymbol(ms);
952     GCElement_setSymbol(g, ms);
953 #if IGEN_DEBUG
954     printf("igen_generate_symbol %s rcount=%d [COPY]\n",aname,ms->ms_refCount);
955 #endif
956   } else {
957 #if IGEN_DEBUG
958     printf("igen_generate_symbol %s rcount=%d [REUSE]\n",aname,ms->ms_refCount);
959 #endif
960   }
961 
962 
963   x = 0;
964   y = 0;
965   GModSymbol_getExtents(ms,0,&minx,&miny,&maxx,&maxy);
966   GModSymbol_flushPorts(ms);
967 
968   for (r = 0;r < 4;r++) {
969     int n = 0;
970     int k = 0;
971     int length;
972 
973     /*
974      * Count number of ports of rotation r
975      */
976     for (i = 0;i < numPorts;i++) {
977       IGPort *igp = portList[i];
978       if (igp_getSide(igp) == r) n++;
979     }
980 
981     if (n == 0) continue;
982 
983     if (r == 0 || r == 2)
984       length = maxy-miny;
985     else
986       length = maxx-minx;
987 
988 #if IGEN_DEBUG
989     printf("  rotation %d: n=%d length=%d   ms_i=(%d,%d)\n",r,n,length,ms->ms_ix[0][0],ms->ms_iy[0][0]);
990 #endif
991 
992     for (i = 0;i < numPorts;i++) {
993       IGPort *igp = portList[i];
994       const char *name = igp_getName(igp);
995       int iotype = igp_getType(igp);
996       int rotation = igp_getSide(igp);
997       int nbits = igp_getSize(igp);
998 
999       if (rotation != r) continue;
1000 
1001       switch (r) {
1002       case 0:
1003 	x = maxx;
1004 	y = miny + (k+1)*length/(n+1);
1005 	break;
1006       case 1:
1007 	x = minx + (k+1)*length/(n+1);
1008 	y = miny-1;
1009 	break;
1010       case 2:
1011 	x = minx-1;
1012 	y = miny + (k+1)*length/(n+1);
1013 	break;
1014       case 3:
1015 	x = minx + (k+1)*length/(n+1);
1016 	y = maxy;
1017 	break;
1018       }
1019 
1020       x += ms->ms_normal.x - ms->ms_ix[0][0];
1021       y += ms->ms_normal.y - ms->ms_iy[0][0];
1022 
1023       /*
1024        * Override port positions if marked as keep.
1025        */
1026       if (igp->igp_keep) {
1027 	x = igp->igp_x;
1028 	y = igp->igp_y;
1029       }
1030 
1031       GModSymbol_addPort(ms,new_GSymPort(name,x,y,iotype,rotation,nbits));
1032 #if IGEN_DEBUG
1033       printf("    GModSymbol_addPort(ms,new_GSymPort(%s,%d,%d,%d,%d,%d))\n",name,x,y,iotype,rotation,nbits);
1034 #endif
1035 
1036       k++;
1037     }
1038   }
1039 
1040   modint_makeSymbolInterface(M,ms);
1041   modint_syncDisplay(M);
1042 
1043   SetModified(MF_INTERFACE);
1044   FlagRedraw();
1045 
1046 
1047   igen_freePortList(portList,numPorts);
1048 
1049   return TCL_OK;
1050 }
1051 
1052 /*****************************************************************************
1053  *
1054  * Helping function for igen_generate() to do the actual construction of the
1055  * new module interface.
1056  *
1057  *****************************************************************************/
igen_generate_build(GModuleDef * M,IGPort ** portList,int numPorts,int retainSize)1058 void igen_generate_build(GModuleDef *M,IGPort **portList,int numPorts,int retainSize)
1059 {
1060   GModuleDef *MI = TkGate.circuit->mid_mod;	/* Module interface container */
1061   int width = 2*HMARGIN, height = 2*VMARGIN;	/* Size of module */
1062   GCElement *g;
1063   int labelWidth;
1064   int maxPortLabelWidth = 0;
1065   int i;
1066 
1067   /*
1068    * If we are retaining the size, set the width/height form the current
1069    * module interface.
1070    */
1071   if (retainSize) {
1072     g = M->m_interface;		/* Old module description */
1073     width = g->u.block.gwidth;			/* Old module width */
1074     height = g->u.block.gheight;		/* Old module height */
1075   }
1076 
1077   /*
1078    * Clear the old interface and get the new empty one.
1079    */
1080   EditState_unselectAll(TkGate.circuit->es);
1081   modint_setInterface(M,0);
1082   g = M->m_interface;
1083 
1084 
1085   /*
1086    * Width of the label
1087    */
1088   labelWidth = GKTextWidth(TkGate.textbXF[1],M->m_name,strlen(M->m_name));
1089 
1090   /*
1091    * Compute the and set the new size for the module
1092    */
1093   for (i = 0;i < numPorts;i++) {
1094     IGPort *igp = portList[i];
1095     int side = igp_getSide(igp);
1096     int length;
1097     int w;
1098 
1099     if (side == PSIDE_LEFT || side == PSIDE_RIGHT) {
1100       length = igp->igp_offset + VMARGIN;
1101       if (length > height) height = length;
1102 
1103       w = GKTextWidth(TkGate.stextbXF[1],igp->igp_name,strlen(igp->igp_name));
1104       if (w > maxPortLabelWidth) maxPortLabelWidth = w;
1105     } else {
1106       length = igp->igp_offset + HMARGIN;
1107       if (length > width) width = length;
1108     }
1109   }
1110 
1111   if ( maxPortLabelWidth*2+labelWidth > width) {
1112     width = maxPortLabelWidth*2+labelWidth + 15;
1113   }
1114 
1115   g->u.block.gwidth = width;
1116   g->u.block.gheight = height;
1117 
1118 
1119   /*
1120    * Attach ports to the module
1121    */
1122   for (i = 0;i < numPorts;i++) {
1123     IGPort *igp = portList[i];
1124     int iotype = igp_getType(igp);
1125     int side = igp_getSide(igp);
1126     GWire *w;
1127     int x,y;
1128 
1129     wire_new(MI,0,&w);
1130     w->net->n_nbits = igp_getSize(igp);
1131 
1132     switch (side) {
1133     case PSIDE_LEFT :
1134       x = g->xpos;
1135       y = g->ypos + igp->igp_offset;
1136       block_attach(MI,g,w,w->driver,x,y,igp_getName(igp),iotype);
1137       break;
1138     case PSIDE_RIGHT :
1139       x = g->xpos + width;
1140       y = g->ypos + igp->igp_offset;
1141       block_attach(MI,g,w,w->driver,x,y,igp_getName(igp),iotype);
1142       break;
1143     case PSIDE_TOP :
1144       x = g->xpos + igp->igp_offset;
1145       y = g->ypos;
1146       block_attach(MI,g,w,w->driver,x,y,igp_getName(igp),iotype);
1147       break;
1148     case PSIDE_BOTTOM :
1149       x = g->xpos + igp->igp_offset;
1150       y = g->ypos + height;
1151       block_attach(MI,g,w,w->driver,x,y,igp_getName(igp),iotype);
1152       break;
1153     }
1154   }
1155 }
1156 
1157 /*****************************************************************************
1158  *
1159  * Generate an initial interface.  This is an altenative interface generator
1160  * function that does not need to be called from tcl.  It is used to generate
1161  * initial interfaces from native Verilog.
1162  *
1163  *****************************************************************************/
igen_generate_initial(GModuleDef * M)1164 int igen_generate_initial(GModuleDef *M)
1165 {
1166   IGPort **portList = 0;	/* Array of all ports */
1167   int numPorts = 0;
1168   int i;
1169 
1170   portList = igen_generate_getModPorts(M,portList,&numPorts);
1171 
1172   /*
1173    * Set positions for currently unpositioned ports on each side.
1174    */
1175   for (i = 0;i < PSIDE_MAX;i++)
1176     igen_generate_positionPorts(portList,numPorts,i);
1177 
1178 
1179   /*
1180    * Do the actual construction of the new module interface
1181    */
1182   igen_generate_build(M,portList,numPorts,0);
1183   if (portList) igen_freePortList(portList,numPorts);
1184 
1185   return 0;
1186 }
1187 
1188 /*****************************************************************************
1189  *
1190  * Generate an interface
1191  *
1192  *****************************************************************************/
igen_generate(GModuleDef * M,int argc,const char * argv[])1193 int igen_generate(GModuleDef *M,int argc,const char *argv[])
1194 {
1195   char *aname = 0;		/* Array with port information */
1196   char *which = "int";		/* Which ports to use */
1197   char *pos = "keep";		/* Positioning disposition */
1198   IGPort **portList = 0;	/* Array of all ports */
1199   int numPorts = 0;
1200   int keep = 0;
1201   int i;
1202   const char *strIType;
1203 
1204   /*
1205    * Parse command parameters
1206    */
1207   for (i = 0;i < argc;i++) {
1208     if (strcmp(argv[i],"-data") == 0 && i+1 < argc)
1209       aname = (char*) argv[++i];
1210     else if (strcmp(argv[i],"-which") == 0 && i+1 < argc)
1211       which = (char*) argv[++i];
1212     else if (strcmp(argv[i],"-pos") == 0 && i+1 < argc)
1213       pos = (char*) argv[++i];
1214     else
1215       return TCL_ERROR;
1216   }
1217   keep = pos && (strcmp(pos,"keep") == 0);		/* Keep existing positions/size */
1218 
1219   if (!aname) return TCL_ERROR;
1220 
1221   strIType = Tcl_GetVar2(TkGate.tcl,aname,"itype",TCL_GLOBAL_ONLY);
1222   if (strIType && strcmp(strIType,"symbol") == 0) {
1223     igen_generate_symbol(M,aname,which,keep);
1224     return TCL_OK;
1225   }
1226 
1227   /*
1228    * We are including current interface ports
1229    */
1230   if (strcmp(which,"int") == 0 || strcmp(which,"modint") == 0) {
1231     portList = igen_generate_getInstPorts(M,aname,&numPorts);
1232     if (keep)
1233       igen_setBlockPortPositions(M,portList,numPorts);
1234   }
1235 
1236   /*
1237    * Get module ports if necessary
1238    */
1239   if (strcmp(which,"mod") == 0 || strcmp(which,"modint") == 0) {
1240     portList = igen_generate_getModPorts(M,portList,&numPorts);
1241   }
1242 
1243   /*
1244    * Set positions for currently unpositioned ports on each side.
1245    */
1246   for (i = 0;i < PSIDE_MAX;i++)
1247     igen_generate_positionPorts(portList,numPorts,i);
1248 
1249   /*
1250    * Debugging code to print out the new port list.
1251    */
1252 #if 0
1253   printf("Generated port list:\n");
1254   for (i = 0;i < numPorts;i++) {
1255     IGPort *igp = portList[i];
1256 
1257     printf("  %s %s[%d] @ %s",
1258 	   igp_getTypeStr(igp),
1259 	   igp_getName(igp),
1260 	   igp_getSize(igp),
1261 	   igp_getSideStr(igp));
1262 
1263     if (igp->igp_offset >= 0)
1264       printf("+%d\n",igp->igp_offset);
1265     else
1266       printf("\n");
1267   }
1268 #endif
1269 
1270   /*
1271    * Do the actual construction of the new module interface
1272    */
1273   igen_generate_build(M,portList,numPorts,keep);
1274 
1275   SetModified(MF_INTERFACE);
1276 
1277   if (editstate_getInterfaceMode() == INTFMODE_SINGLE) {
1278     modint_syncDisplay(M);
1279     FlagRedraw();
1280   }
1281 
1282   if (portList) igen_freePortList(portList,numPorts);
1283 
1284   return 0;
1285 }
1286 
1287 /*****************************************************************************
1288  *
1289  * Change the type of an interface between "block" and "symbol".
1290  *
1291  *****************************************************************************/
igen_changetype(GModuleDef * M,int argc,const char * argv[])1292 int igen_changetype(GModuleDef *M,int argc,const char *argv[])
1293 {
1294   char *aname = 0;	/* Array with port information */
1295   const char *strIType;
1296   int i;
1297   int doswap = 0;
1298 
1299   if (GModuleDef_isIntfProtected(M)) {
1300     message(1,msgLookup("err.protintf"),M->m_name);
1301     return TCL_ERROR;
1302   }
1303 
1304 
1305   for (i = 0;i < argc;i++) {
1306     if (strcmp(argv[i],"-data") == 0 && i+1 < argc)
1307       aname = (char*) argv[++i];
1308   }
1309   if (!aname) return TCL_ERROR;
1310 
1311   /*
1312    * Check the requested type and take action according to the following rules.
1313    *   1) If the current interface is of the requested type, do nothing.
1314    *   2) If the alternate interface is of the requested type, swap the alternate
1315    *      and current interface objects.
1316    *   3) If there is no alternate, or the alternate is not of the requested type,
1317    *      purge the alternate, move the current interface to the alternate and
1318    *      generate a new interface of the requested type.
1319    */
1320   strIType = Tcl_GetVar2(TkGate.tcl,aname,"itype",TCL_GLOBAL_ONLY);
1321   if (strIType && strcmp(strIType,"symbol") == 0) {
1322     if (M->m_interface && GCElement_getType(M->m_interface) == GC_SYMBLOCK) return TCL_OK;
1323     if (M->m_altInterface && GCElement_getType(M->m_altInterface) == GC_SYMBLOCK)
1324       doswap = 1;
1325   } else {
1326     if (M->m_interface && GCElement_getType(M->m_interface) == GC_BLOCK) return TCL_OK;
1327     if (M->m_altInterface && GCElement_getType(M->m_altInterface) == GC_BLOCK)
1328       doswap = 1;
1329   }
1330 
1331 
1332   /*
1333    * Perform either the required swap or generate action.
1334    */
1335   if (doswap) {
1336     GCElement *g1,*g2,*new_g1,*new_g2;
1337 
1338 #if IGEN_DEBUG
1339     printf("igen_changetype: swap\n");
1340 #endif
1341 
1342     g1 = M->m_altInterface;
1343     g2 = M->m_interface;
1344 
1345 
1346     new_g1 = (*g1->typeinfo->CopyGate)(TkGate.circuit->mid_mod,g1,0,0,0);
1347     new_g2 = (*g2->typeinfo->CopyGate)(TkGate.circuit->mid_altMod,g2,0,0,0);
1348     new_g1->show_name = 0;
1349     new_g2->show_name = 0;
1350 
1351 
1352     gate_delete(g1,TkGate.circuit->mid_altMod,0);
1353     gate_delete(g2,TkGate.circuit->mid_mod,0);
1354 
1355     ob_touch(M);
1356     M->m_altInterface = new_g2;
1357     M->m_interface = new_g1;
1358 
1359     SetModified(MF_INTERFACE);
1360     modint_syncDisplay(M);
1361     FlagRedraw();
1362   } else {
1363     GCElement *g,*new_g;
1364 
1365     g = M->m_interface;
1366 
1367 
1368     new_g = (*g->typeinfo->CopyGate)(TkGate.circuit->mid_altMod,g,0,0,0);
1369     new_g->show_name = 0;
1370 
1371     ob_touch(M);
1372 
1373     gate_delete(M->m_interface,TkGate.circuit->mid_mod,0);
1374     M->m_interface = 0;
1375     modint_setInterface(M,0);
1376     M->m_altInterface = new_g;
1377 
1378 #if IGEN_DEBUG
1379     printf("igen_changetype: backup(%p -> %p) and generate\n",M->m_interface,M->m_altInterface);
1380 #endif
1381 
1382 
1383     igen_generate(M,argc,argv);
1384   }
1385 
1386 
1387   return TCL_OK;
1388 }
1389 
1390 /*****************************************************************************
1391  *
1392  * Main function for manipulating module interfaces.
1393  *
1394  *****************************************************************************/
igen_command(const char * op,const char * mod_name,int argc,const char * argv[])1395 int igen_command(const char *op,const char *mod_name,int argc,const char *argv[])
1396 {
1397   GModuleDef *M;
1398   char *aname = 0;
1399   char *icon = 0;
1400   Tcl_Interp *tcl = TkGate.tcl;
1401 
1402 #if 0
1403  {
1404    int i;
1405    printf("igen %s %s",op,mod_name);
1406    for (i = 0;i < argc;i++)
1407      printf(" %s",argv[i]);
1408    printf("\n");
1409  }
1410 #endif
1411 
1412   aname  = (char*)seekOption("-data",argv,argc);
1413   icon  =  (char*)seekOption("-icon",argv,argc);
1414 
1415   M = env_findModule(mod_name);
1416   if (!M) {
1417     if (aname) Tcl_SetVar2(tcl,aname,"ok","0",TCL_GLOBAL_ONLY);
1418     return 0;
1419   }
1420 
1421   if (icon && strcmp(op,"syncicon") == 0) {
1422     GCElement *g = modint_findDisplay(M->m_name);
1423     EditState *es = TkGate.circuit->es;
1424 
1425     if (es->env != TkGate.circuit->mid_display)
1426       return 0;
1427 
1428     if (strcmp(icon,"select") == 0) {
1429       if (g->selected) return 0;
1430     } else {
1431       if (!g->selected) return 0;
1432     }
1433 
1434     ob_begin_framef("SwitchIcon",0);
1435     if (g->selected) {
1436       sel_clear(es,1);
1437     } else {
1438       sel_appendGate(es,g,1);
1439       sel_finish(es);
1440       ob_touch(TkGate.circuit);
1441       TkGate.circuit->select = g;
1442     }
1443     ob_end_frame();
1444   } else if (strcmp(op,"load") == 0) {
1445     igen_load(M,aname);
1446   } else if (strcmp(op,"changetype") == 0) {
1447     igen_changetype(M,argc,argv);
1448   } else if (strcmp(op,"generate") == 0) {
1449     igen_generate(M,argc,argv);
1450   } else if (strcmp(op,"puticon") == 0) {
1451     igen_putIcon(M,aname,icon);
1452   } else if (strcmp(op,"geticon") == 0) {
1453     igen_getIcon(M,aname);
1454   } else {
1455     return -1;
1456   }
1457 
1458   return 0;
1459 }
1460 
1461