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