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 Wed Mar 18 05:13:38 2009
19 ****************************************************************************/
20 #include <stdlib.h>
21 #include <string.h>
22 #include "tkgate.h"
23 
24 #define MODINT_DEBUG 0
25 #define MODINT_BLOCKSPACE	50
26 
27 /*****************************************************************************
28  *
29  * Compare two interfaces for sorting purposes.
30  *
31  *****************************************************************************/
blknam_compare(const void * pA,const void * pB)32 static int blknam_compare(const void *pA,const void *pB)
33 {
34   GCElement *A = *(GCElement**) pA;
35   GCElement *B = *(GCElement**) pB;
36 
37   return strcasecmp(A->u.block.moduleName,B->u.block.moduleName);
38 }
39 
40 /*****************************************************************************
41  *
42  * Find the display version of an interface.
43  *
44  *****************************************************************************/
modint_findDisplay(const char * name)45 GCElement *modint_findDisplay(const char *name)
46 {
47   GModuleDef *M = TkGate.circuit->mid_display;
48   HashElem *E;
49 
50 #if MODINT_DEBUG
51   printf("modint_find(%s)\n",name);
52 #endif
53   for (E = Hash_first(M->m_gates);E;E = Hash_next(M->m_gates,E)) {
54     GCElement *g = (GCElement*) HashElem_obj(E);
55 #if MODINT_DEBUG
56     printf("  checking %s\n",g->u.block.moduleName);
57 #endif
58     if (strcmp(g->u.block.moduleName,name) == 0)
59       return g;
60   }
61 #if MODINT_DEBUG
62   printf("  not found\n");
63 #endif
64   return 0;
65 }
66 
67 /*****************************************************************************
68  *
69  * Find the module interface for the named module.
70  *
71  *****************************************************************************/
modint_find(const char * name)72 GCElement *modint_find(const char *name)
73 {
74   GModuleDef *M = TkGate.circuit->mid_mod;
75   HashElem *E;
76 
77   for (E = Hash_first(M->m_gates);E;E = Hash_next(M->m_gates,E)) {
78     GCElement *g = (GCElement*) HashElem_obj(E);
79     if (strcmp(g->u.block.moduleName,name) == 0)
80       return g;
81   }
82   return 0;
83 }
84 
85 /*****************************************************************************
86  *
87  * Find the alternate module interface for the named module.
88  *
89  *****************************************************************************/
modint_findInAlt(const char * name)90 GCElement *modint_findInAlt(const char *name)
91 {
92   GModuleDef *M = TkGate.circuit->mid_altMod;
93   HashElem *E;
94 
95   for (E = Hash_first(M->m_gates);E;E = Hash_next(M->m_gates,E)) {
96     GCElement *g = (GCElement*) HashElem_obj(E);
97     if (strcmp(g->u.block.moduleName,name) == 0)
98       return g;
99   }
100   return 0;
101 }
102 
103 /*****************************************************************************
104  *
105  * Reset the module interface to a plain box.
106  *
107  *****************************************************************************/
modint_reset(EditState * es,GCElement * g)108 void modint_reset(EditState *es, GCElement *g)
109 {
110   int N;
111   int i;
112 
113   if (!g || g->typeinfo->code != GC_BLOCK)
114     return;
115 
116   N = GCElement_numPads(g);
117   for (i = 0;i < N;i++) {
118     GWire *w,*n_w;
119 
120     for (w = g->wires[i];w; w = n_w) {
121       n_w = w->next;
122       block_cutoffwire(w,es);
123     }
124   }
125 
126   gate_draw(g,GD_NOWIRE);
127   ob_touch(g);
128   g->u.block.gwidth = MINSIZE;
129   g->u.block.gheight = MINSIZE;
130   gate_draw(g,GD_NOWIRE);
131 }
132 
133 /*****************************************************************************
134  *
135  * Delete the module interface for a module.
136  *
137  *****************************************************************************/
modint_deleteInterface(GModuleDef * M)138 void modint_deleteInterface(GModuleDef *M)
139 {
140 #if MODINT_DEBUG
141   printf("modint_deleteInterface(%s)\n",M->m_name);
142 #endif
143 
144   if (M->m_interface) {
145     gate_delete(M->m_interface,TkGate.circuit->mid_mod,0);
146     M->m_interface = 0;
147   }
148 
149   if (TkGate.circuit->es && TkGate.circuit->es->isInterface) {
150     modint_arrange(TkGate.circuit->es);
151     FlagRedraw();
152   }
153 }
154 
155 /*****************************************************************************
156  *
157  * Rename the interface of a module to match the module name.  This is generally
158  * called after a module is renamed to synchronize the interface name to the
159  * new module name.
160  *
161  *****************************************************************************/
modint_renameInterface(GModuleDef * M)162 void modint_renameInterface(GModuleDef *M)
163 {
164   GCElement *g;
165 
166   if (M->m_interface) {
167     g = M->m_interface;
168     if (g->u.block.moduleName)
169       ob_free(g->u.block.moduleName);
170     ob_touch(g);
171     g->u.block.moduleName = ob_strdup(M->m_name);
172   }
173   if (M->m_altInterface) {
174     g = M->m_altInterface;
175     if (g->u.block.moduleName)
176       ob_free(g->u.block.moduleName);
177     ob_touch(g);
178     g->u.block.moduleName = ob_strdup(M->m_name);
179   }
180 
181   if (TkGate.circuit->es->isInterface) {
182     modint_arrange(TkGate.circuit->es);
183     FlagRedraw();
184   }
185 }
186 
187 /*****************************************************************************
188  *
189  * Set the interface of a module.
190  *
191  * Parameters:
192  *      M		Module whos interface is to be set.
193  *      g		New interface for module.
194  *
195  * Updates the interface of a module.  The specified gate is copied and that
196  * copy is stored in the module interfaces buffer.
197  *
198  *****************************************************************************/
modint_setInterface(GModuleDef * M,GCElement * g)199 int modint_setInterface(GModuleDef *M,GCElement *g)
200 {
201   GCElement *r = 0;
202 
203 #if 0
204   printf("modint_setInterface(M=%s, g=%p) [d=%p]\n",M->m_name, g, d);
205 #endif
206 
207   if (g && GModuleDef_isIntfProtected(M)) {
208 #if MODINT_DEBUG
209     printf("modint_setInterface failed: %s\n",g->u.block.moduleName);
210 #endif
211     message(0,msgLookup("err.protintf"),g->u.block.moduleName);
212     return -1;
213   }
214 
215   if (M->m_interface) {
216     gate_delete(M->m_interface,TkGate.circuit->mid_mod,0);
217     M->m_interface = 0;
218   }
219 
220   if (g) {
221     r = (*g->typeinfo->CopyGate)(TkGate.circuit->mid_mod,g,0,0,0);
222     ob_touch(r);
223     r->show_name = 0;
224   } else {
225     GGateInfo *bgi = GGateInfo_codeLookup(GC_BLOCK);
226     const char *args[2];
227     args[0] = "-func";
228     args[1] = M->m_name;
229     r = (*bgi->MakeFunction)(0,TkGate.circuit->mid_mod,GC_BLOCK,50,50,0,0,0,args,2);
230   }
231   ob_touch(M);
232   M->m_interface = r;
233   r->isModuleInterface = 1;
234 #if MODINT_DEBUG
235   printf("modint_setInterface(%s) -> %p [n=%d]\n",
236 	 M->m_name,r,Hash_numElems(TkGate.circuit->mid_mod->m_gates));
237 #endif
238 
239   return 0;
240 }
241 
242 /*****************************************************************************
243  *
244  * Nicely arrange modules in the module interface buffer.
245  *
246  * Parameters:
247  *    es		The current edit state.
248  *
249  *****************************************************************************/
modint_arrange(EditState * es)250 void modint_arrange(EditState*es)
251 {
252   GModuleDef *M = TkGate.circuit->mid_mod;
253   HashElem *E;
254   GCElement **blist;
255   int N = Hash_numElems(M->m_gates);
256   int i;
257   int x,y,maxh;
258   int isFirst;
259 
260   if (N < 1) return;					/* No defined blocks */
261 
262   ob_touch(TkGate.circuit);
263   TkGate.circuit->no_set_modify = 1;
264   blist = (GCElement**) calloc(N,sizeof(GCElement*));	/* Temporary allocation */
265 
266   /*
267    * Get the list of modules and sort them alphabetically.
268    */
269   for (i = 0,E = Hash_first(M->m_gates);E;i++, E = Hash_next(M->m_gates,E))
270     blist[i] = (GCElement*) HashElem_obj(E);
271   qsort(blist,N,sizeof(GCElement*),blknam_compare);
272 
273   /*
274    * Initialize the first row
275    */
276   x = MODINT_BLOCKSPACE;
277   y = MODINT_BLOCKSPACE;
278   maxh = 0;
279   isFirst = 1;
280 
281   for (i = 0;i < N;i++) {
282     GCElement *g = blist[i];
283     int minx,miny,maxx,maxy;
284     int width,height,cx,cy;
285 
286     ob_touch(g);
287     g->top = g->bottom = g->right = g->left = 0;
288     (*g->typeinfo->GetExtents)(g,TD_X11,&minx,&miny,&maxx,&maxy,0);
289     width = maxx-minx;
290     height = maxy-miny;
291 
292     if (GCElement_getType(g) == GC_SYMBLOCK) {
293       cx = width/2;
294       cy = height/2;
295     } else
296       cx = cy = 0;
297 
298 
299     if (!isFirst && (x + width + MODINT_BLOCKSPACE) > TkGate.width) {
300       x = MODINT_BLOCKSPACE;
301       y += MODINT_BLOCKSPACE + maxh;
302       maxh = 0;
303     }
304 
305     /*
306      * Place the block/symbol at (x,y)
307      */
308     gate_moveTo(g,x+cx,y+cy);
309 #if MODINT_DEBUG
310     printf("  place %s::%s @ (%d, %d)\n",g->u.block.moduleName,g->ename,g->xpos,g->ypos);
311 #endif
312 
313 
314     x += width + MODINT_BLOCKSPACE;
315     if (height > maxh) maxh = height;
316 
317     isFirst = 0;
318   }
319 
320   ob_touch(TkGate.circuit);
321   TkGate.circuit->no_set_modify = 0;
322 
323   free(blist);
324 }
325 
modint_update(EditState * es)326 void modint_update(EditState *es)
327 {
328 #if MODINT_DEBUG
329   printf("modint_update\n");
330 #endif
331 }
332 
333 /*****************************************************************************
334  *
335  * Center the displayed module interface in the available screen area.
336  *
337  *****************************************************************************/
modint_center()338 void modint_center()
339 {
340   HashElem *he;
341   GCElement *g;
342   int x,y;
343   if (!TkGate.circuit->mid_display) return;
344 
345   he = Hash_first(TkGate.circuit->mid_display->m_gates);
346   if (!he) return;
347   g = (GCElement*) HashElem_obj(he);
348   if (!g) return;
349 
350   SetModified(MF_BEGINSPEC);
351 
352   if (GCElement_getType(g) == GC_SYMBLOCK) {
353     x = TkGate.width/2;
354     y = TkGate.height/2;
355   } else {
356     x = TkGate.width/2 - (g->u.block.gwidth)/2;
357     y = TkGate.height/2 - g->u.block.gheight/2;
358   }
359 
360   if (x != g->xpos || y != g->ypos || TkGate.circuit->org_x != 0 || TkGate.circuit->org_y != 0) {
361     TkGate.circuit->org_x = TkGate.circuit->org_y = 0;
362     ob_begin_framef("-Center",FF_TRANSPARENT);
363     gate_moveTo(g,x,y);
364     ob_end_frame();
365     FlagRedraw();
366   }
367 
368   SetModified(MF_ENDSPEC);
369 }
370 
371 /*****************************************************************************
372  *
373  * Synchronoize the module int the display buffer with the actual module interface
374  *
375  *****************************************************************************/
modint_syncDisplay(GModuleDef * M)376 void modint_syncDisplay(GModuleDef *M)
377 {
378   GCElement *g = M->m_interface;
379   int x,y;
380 
381   if (!g) return;
382 
383   TkGate.circuit->es->isInterface = 0;
384   GModuleDef_flush(TkGate.circuit->mid_display);
385   x = TkGate.width/2;
386   y = TkGate.height/2;
387   TkGate.circuit->org_x = TkGate.circuit->org_y = 0;
388 
389   DoTcl("gat_make MODULE -x %d -y %d -func %s -doinit 1 -dodraw 0",x,y,M->m_name);
390   TkGate.circuit->es->isInterface = 1;
391 
392   DoTcl("NetList::flush");	/* Hack to clear the netlist */
393 }
394 
395 /*****************************************************************************
396  *
397  * Edit a module interface
398  *
399  *****************************************************************************/
modint_edit(EditState ** es,GModuleDef * M)400 void modint_edit(EditState **es,GModuleDef *M)
401 {
402   ob_touch(*es);
403 
404 #if MODINT_DEBUG
405   printf("modint_edit(%s)\n",M ? M->m_name : "0");
406 #endif
407 
408   /*
409    * If we are in interface mode, just pop the current interface editstate before
410    * pushing the new one.
411    */
412   if ((*es)->isInterface) {
413     editstate_pop(es);
414     ob_touch(*es);
415   }
416 
417   ob_touch(*es);
418 
419 
420   /*
421    * Treat root module as list of all modules.
422    */
423   if (M == TkGate.circuit->root_mod) M = 0;
424 
425   /*
426    * If we are given a module, we just display that interface.  If no module, then
427    * we display all interfaces.
428    */
429   if (M) {
430     editstate_push(es,TkGate.circuit->mid_display,0);
431     ob_touch(TkGate.circuit->mid_display);
432     ob_free(TkGate.circuit->mid_display->m_name);
433     TkGate.circuit->mid_display->m_name = ob_strdup(M->m_name);
434 
435     editstate_setCurrent(*es);
436 
437     modint_syncDisplay(M);
438   } else {
439     editstate_push(es,TkGate.circuit->mid_mod,0);
440     (*es)->isInterface = 1;
441     modint_arrange(*es);
442     editstate_setCurrent(*es);
443   }
444 
445   DoTcl("IPanel::loadCurrent");
446 
447   SetModified(MF_MODULE|MF_SYNCONLY);
448   SynchronizeInterface();
449 
450   FlagRedraw();
451 }
452 
453 /*****************************************************************************
454  *
455  * Close the module interface editor.
456  *
457  *****************************************************************************/
modint_close()458 void modint_close()
459 {
460 #if MODINT_DEBUG
461   GModuleDef *m;
462 
463   if (TkGate.circuit->es->env == TkGate.circuit->mid_display)
464     m = env_findModule(TkGate.circuit->mid_display->m_name);	/* Editing an interface */
465   else
466     m = TkGate.circuit->root_mod;				/* Top-level interface editor */
467 
468   printf("modint_close: (%s)=%p\n",TkGate.circuit->mid_display->m_name,m);
469 #endif
470 
471   ob_touch(TkGate.circuit);
472 
473   EditState_unselectGate(TkGate.circuit->es);
474 
475   while (TkGate.circuit->es && TkGate.circuit->es->isInterface)
476     editstate_pop(&TkGate.circuit->es);
477   //  editstate_push(&TkGate.circuit->es, m, 0);
478 
479   editstate_setCurrent(TkGate.circuit->es);
480   SetModified(MF_MODULE|MF_SYNCONLY);
481   SynchronizeInterface();
482   FlagRedraw();
483 }
484 
485 /*****************************************************************************
486  *
487  * Make the interface for this module the default symbol.
488  *
489  *****************************************************************************/
modint_makeSymbolInterface(GModuleDef * M,GModSymbol * ms)490 void modint_makeSymbolInterface(GModuleDef *M,GModSymbol *ms)
491 {
492   GGateInfo *bgi = GGateInfo_codeLookup(GC_BLOCK);
493   const char *args[2];
494   GCElement *g;
495 
496   /*
497    * Create a module and convert it to a symbol block.
498    */
499   args[0] = "-func";
500   args[1] = M->m_name;
501   g = (*bgi->MakeFunction)(0,0,GC_BLOCK,50,50,0,0,0,args,2);
502   g = SymBlock_convert(g,ms,M,0);
503 
504   /*
505    * Make this new symbol block gate the new interface for M.
506    */
507   modint_setInterface(M, g);
508 }
509 
510 /*****************************************************************************
511  *
512  * Flush all module instances
513  *
514  *****************************************************************************/
modint_flush()515 void modint_flush()
516 {
517 #if 0
518   GModuleDef *mm = TkGate.circuit->mid_mod;
519   List dlist;
520 
521   List_init(&dlist);
522 
523   for (E = Hash_first(mm->m_gates);E;E = Hash_next(mm->m_gates,E)) {
524     GCElement *g = (GCElement*) HashElem_obj(E);
525     if (GCElement_getType(g) != GC_BLOCK &&
526 	GCElement_getType(g) != GC_SYMBLOCK)
527       continue;
528 
529     List_addToTail(&dlist,
530   }
531 
532   List_uninit(&dlist);
533     modint_deleteInterface(mi);
534 #endif
535     printf("begin: modint_flush\n");
536     env_clear(TkGate.circuit->mid_mod);
537     printf("end: modint_flush\n");
538 }
539 
540 /*****************************************************************************
541  *
542  * Open the selected module.  If modName is non-null, it is the name of a module
543  * selected from the module list/tree.  If it is null, then we look up the module
544  * from the current selection.
545  *
546  *****************************************************************************/
modint_openSelected(const char * modName)547 void modint_openSelected(const char *modName)
548 {
549 
550   EditState **es = &TkGate.circuit->es;
551   GModuleDef *M;
552   char *p;
553   int listSelection = (modName != 0);
554 
555   /*
556    * Make sure the selected object is a module, and look it up.  If we do not
557    * find it, then return and do nothing.
558    */
559   if (!modName && TkGate.circuit->select && GCElement_isModule(TkGate.circuit->select))
560     modName = TkGate.circuit->select->u.block.moduleName;
561   if (!modName) return;
562   p = strrchr(modName,'/');
563   if (p) modName = p+1;
564   M = env_findModule(modName);
565   if (!M) return;
566 
567   if (editstate_getInterfaceMode() == INTFMODE_ALL || listSelection) {
568     /*
569      * We are in the all interface display mode or we selected the module from
570      * the module list.  Open it for individual editing.
571      */
572     modint_edit(es,M);
573     editstate_setCurrent(*es);
574     SetModified(MF_MODULE|MF_SYNCONLY);
575     SynchronizeInterface();
576     FlagRedraw();
577   }
578 }
579