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 Tue May  5 20:45:31 2009
19 ****************************************************************************/
20 
21 #include <stdlib.h>
22 
23 #include "tkgate.h"
24 
25 #define DEBUG_REDISPLAY 0
26 
27 #define MAX_STACKDEPTH 256
28 
29 extern int baderp;
30 
31 extern int GlobalElementCount;
32 extern int RedrawRequested;
33 extern int baderp,startrekp;
34 
35 void SetErrorPosition(int x,int y);
36 
TkGate_setOrigin(int x,int y)37 void TkGate_setOrigin(int x,int y)
38 {
39 #if 0
40   printf("ORIGIN SET (%d, %d)\n",x,y);
41 #endif
42   if (TkGate.circuit->org_x != x || TkGate.circuit->org_y != y) {
43     ob_touch(TkGate.circuit);
44     TkGate.circuit->org_x = x;
45     TkGate.circuit->org_y = y;
46   }
47   TkGate.idle_ev.scroll_new_x = TkGate.circuit->org_x;
48   TkGate.idle_ev.scroll_new_y = TkGate.circuit->org_y;
49   editstate_saveOrig(TkGate.circuit->es);
50 }
51 
env_findModule(const char * name)52 GModuleDef *env_findModule(const char *name)
53 {
54   return (GModuleDef*) SHash_find(TkGate.circuit->moduleTable,name);
55 }
56 
57 /*
58  * Dump the names of child blocks of M to the hierarchical block list tree
59  */
env_updateMTChildren(GModuleDef * M)60 static void env_updateMTChildren(GModuleDef *M)
61 {
62   HashElem *gl;
63 
64   DoTcl("BlockTree::disownChildren %s",M->m_name);
65   for (gl = Hash_first(M->m_gates);gl;gl = Hash_next(M->m_gates,gl)) {
66     GCElement *g = (GCElement*) HashElem_obj(gl);
67 
68     /*
69      * Mark all modules found in M as children of M.  We first make to sure that the
70      * block actually has a module name.  In the case of a block that is currently in
71      * the process of being defined, it is possible that there may temporarily be some
72      * modules with no defined name.
73      */
74     if (GCElement_isModule(g) && g->u.block.moduleName && *g->u.block.moduleName) {
75       const char *prefix = TkGate.circuit->c_gatePrefix;
76       if (strncmp(g->u.block.moduleName,prefix,strlen(prefix)) != 0)
77 	DoTcl("BlockTree::makeChild %s %s",g->u.block.moduleName,M->m_name);
78     }
79   }
80 }
81 
env_updateMT_simulate(GModuleDef * M,GCElement * g)82 static void env_updateMT_simulate(GModuleDef *M,GCElement *g)
83 {
84   HashElem *he;
85   char *T = (M->m_type == MT_TEXTHDL) ? "hdl" : "netlist";
86 
87   if (M->m_isLib) T = "part";
88 
89   if (g) {
90     DoTcl("BlockTree::add %s<%s> -type %s",g->ename,M->m_name,T);
91     DoTcl("BlockTree::disownChildren %s<%s>",g->ename,M->m_name);
92   } else {
93     DoTcl("BlockTree::add <%s> -type %s",M->m_name,T);
94     DoTcl("BlockTree::disownChildren <%s>",M->m_name);
95     DoTcl("BlockTree::setRoot <%s>",M->m_name);
96 
97   }
98 
99   for (he = Hash_first(M->m_gates);he;he = Hash_next(M->m_gates,he)) {
100     GCElement *cg = (GCElement*) HashElem_obj(he);
101     GModuleDef *cm = 0;
102 
103     if (GCElement_isModule(cg) && cg->u.block.moduleName && *cg->u.block.moduleName) {
104       const char *prefix = TkGate.circuit->c_gatePrefix;
105 
106       cm = env_findModule(cg->u.block.moduleName);
107 
108       /*
109        * Ignore any built-in gates.
110        */
111       if (strncmp(cg->u.block.moduleName,prefix,strlen(prefix)) == 0)
112 	continue;
113     }
114 
115     if (cm) {
116       if (g)
117 	DoTcl("BlockTree::makeChild %s<%s> %s<%s>",cg->ename,cm->m_name,g->ename,M->m_name);
118       else
119 	DoTcl("BlockTree::makeChild %s<%s> <%s>",cg->ename,cm->m_name,M->m_name);
120       env_updateMT_simulate(cm,cg);
121     }
122   }
123 }
124 
125 /*****************************************************************************
126  *
127  * Update the module tree while in edit (or related) mode
128  *
129  *****************************************************************************/
env_updateMT_edit(void)130 static void env_updateMT_edit(void)
131 {
132   HashElem *he;
133 
134   for (he = Hash_first(TkGate.libraries);he;he = Hash_next(TkGate.libraries,he)) {
135     DoTclL("BlockTree::addLibrary",SHashElem_key(he),NULL);
136   }
137 
138   for (he = Hash_first(TkGate.circuit->moduleTable);he;he = Hash_next(TkGate.circuit->moduleTable,he)) {
139     GModuleDef *M = (GModuleDef*) HashElem_obj(he);
140 
141     if (M->m_isLib) {
142       DoTclL("BlockTree::addPart",M->m_name,M->m_libName,NULL);
143     } else {
144       char *T = (M->m_type == MT_TEXTHDL) ? "hdl" : "netlist";
145       char ID[8];
146 
147       sprintf(ID,"%s%s" , (M->m_protIntf ? "I" : ""), (M->m_protData ? "D" : ""));
148       DoTclL("BlockTree::add",M->m_name,"-locks",ID,"-type",T,NULL);
149     }
150 
151     env_updateMTChildren(M);
152   }
153 
154   if (TkGate.circuit->root_mod) {
155     DoTclL("BlockTree::setRoot",TkGate.circuit->root_mod->m_name,NULL);
156   }
157 }
158 
159 
160 /*****************************************************************************
161  *
162  * Flush and reconstruct the module lists for edit mode
163  *
164  *****************************************************************************/
env_updateModuleList(void)165 static void env_updateModuleList(void)
166 {
167   HashElem *E;
168 
169   for (E = Hash_first(TkGate.circuit->moduleTable);E;E = Hash_next(TkGate.circuit->moduleTable,E)) {
170     GModuleDef *M = (GModuleDef*) HashElem_obj(E);
171 
172     if (M->m_isLib) {
173       DoTcl("BlockList::addPart %s",M->m_name);
174     } else {
175       char *I = M->m_protIntf ? "I" : "";
176       char *D = M->m_protData ? "D" : "";
177       char *T = (M->m_type == MT_TEXTHDL) ? "hdl" : "netlist";
178       DoTcl("BlockList::add %s -locks \"%s%s\" -type %s",M->m_name,I,D,T);
179     }
180   }
181 
182   if (TkGate.circuit->root_mod) {
183     DoTcl("BlockList::setRoot %s",TkGate.circuit->root_mod->m_name);
184   }
185 }
186 
187 /*****************************************************************************
188  *
189  * Flush and reconstruct the module lists.
190  *
191  *****************************************************************************/
env_updateMTCircuit()192 void env_updateMTCircuit()
193 {
194   int is_simulate = (TkGate.ed->major_mode == MM_SIMULATE || TkGate.ed->major_mode == MM_ANALYZE);
195 
196   DoTcl("BlockTree::flush\n");
197   DoTcl("BlockList::flush\n");
198 
199   env_updateModuleList();
200 
201   if (is_simulate) {
202     env_updateMT_simulate(TkGate.circuit->root_mod,0);
203   } else
204     env_updateMT_edit();
205 
206   DoTcl("BlockTree::rebuild");
207 }
208 
209 /*****************************************************************************
210  *
211  * Insert a module into the current circuit environment and create a module
212  * interface for it if it is not the top level.
213  *
214  *****************************************************************************/
env_insertModule(GModuleDef * M)215 void env_insertModule(GModuleDef *M)
216 {
217   /** @TODO to check the necessity */
218   /*
219   char *mflags = "";
220 
221   if (GModuleDef_isTop(M))
222     mflags = "+";
223   */
224 
225   SHash_insert(TkGate.circuit->moduleTable,M->m_name,M);
226 }
227 
228 /*****************************************************************************
229  *
230  * Define a new module.
231  *
232  * Parameters:
233  *     name		Name of new module
234  *     isMain		Flag to indicate if this is the top-level module
235  *
236  *****************************************************************************/
env_defineModule(const char * name,int isMain)237 GModuleDef *env_defineModule(const char *name,int isMain)
238 {
239   GModuleDef *M;
240 
241   M = new_GModuleDef(name);
242   if (isMain)
243     TkGate.circuit->root_mod = M;
244 
245   env_insertModule(M);
246   if (!GModuleDef_isTop(M)) {
247     modint_setInterface(M,0);
248   }
249 
250   SetModified(MF_MODULE);
251 
252   return M;
253 }
254 
env_findAdd(const char * name,int isMain)255 GModuleDef *env_findAdd(const char *name,int isMain)
256 {
257   GModuleDef *M;
258 
259   if (!(M = env_findModule(name))) {
260     M = env_defineModule(name,isMain);
261   }
262   return M;
263 }
264 
env_getInterface(GCElement * g)265 GCElement *env_getInterface(GCElement *g)
266 {
267   GModuleDef *M;
268 
269   if (GCElement_getType(g) != GC_BLOCK &&
270       GCElement_getType(g) != GC_SYMBLOCK)
271     return 0;
272 
273   M = env_findModule(g->u.block.moduleName);
274   if (M)
275     return M->m_interface;
276   else
277     return 0;
278 }
279 
env_checkname(GCElement * g)280 void env_checkname(GCElement *g)
281 {
282   if (!GCElement_isModule(g)) {
283     printf("Huh?  checkname gets non-block\n");
284     exit(1);
285   }
286 
287   env_findAdd(g->u.block.moduleName,0);
288 }
289 
290 /*
291  * Free memory from all gates in a module (used to delete a module).
292  */
freegatelist(GModuleDef * M)293 void freegatelist(GModuleDef *M)
294 {
295   HashElem *gl;
296   GCElement **gates;
297   int i,N;
298 
299   /*  printf("freegatelist: %s\n",GModuleDef_getName(M));*/
300   if (Hash_numElems(M->m_gates) > 0) {
301     N = 0;
302     gates = (GCElement**)ob_calloc(Hash_numElems(M->m_gates),sizeof(GCElement*),"GCElement*[]");
303     for (gl = Hash_first(M->m_gates);gl;gl = Hash_next(M->m_gates,gl)) {
304       GCElement *g = (GCElement*) HashElem_obj(gl);
305       if (g->typeinfo->code != GC_JOINT)
306 	gates[N++] = g;
307     }
308 
309     for (i = 0;i < N;i++) {
310       gate_delete(gates[i],M,0);
311     }
312     ob_free(gates);
313   }
314 
315   SHash_flush(M->m_gates);
316 }
317 
freewirelist(GModuleDef * M)318 void freewirelist(GModuleDef *M)
319 {
320   GWireList *l = M->m_wires;
321 
322   while (l) {
323     GWireList *n = l->wl_next;
324     if (l->wl_wire->driver == l->wl_wire)
325       GWireNode_freenodelist(l->wl_wire->nodes);
326     ob_free(l->wl_wire);
327     ob_free(l);
328     l = n;
329   }
330 }
331 
332 /*
333    Remove all gates, wires and nets from a module.
334 */
env_clear(GModuleDef * M)335 void env_clear(GModuleDef *M)
336 {
337   HashElem *E;
338 
339   if (!M) return;
340 
341   freegatelist(M);
342   freewirelist(M);
343 
344   /*
345    * Nets in netlist modules will have already been deleted by the freewirelist()
346    * call above.  This additional deletion scan deletes nets used by the HDL module
347    * scanner.
348    */
349   while ((E = Hash_first(M->m_nets))) {
350     GNet *n = (GNet*) HashElem_obj(E);
351     delete_GNet(n);
352   }
353 }
354 
env_clearmark()355 void env_clearmark()
356 {
357   HashElem *E;
358 
359   for (E = Hash_first(TkGate.circuit->moduleTable);E;E = Hash_next(TkGate.circuit->moduleTable,E)) {
360     GModuleDef *M = (GModuleDef*) HashElem_obj(E);
361     ob_touch(M);
362     M->m_used = 0;
363   }
364 }
365 
366 /*
367    Mark this module and all children of it.
368 */
env_markenv(GModuleDef * M)369 void env_markenv(GModuleDef *M)
370 {
371   HashElem *gl;
372 
373   if (!M->m_used) {
374     ob_touch(M);
375     M->m_used = 1;
376     for (gl = Hash_first(M->m_gates);gl;gl = Hash_next(M->m_gates,gl)) {
377       GCElement *g = HashElem_obj(gl);
378 
379       if (GCElement_isModule(g)) {
380 	GModuleDef *M = env_findAdd(g->u.block.moduleName,0);
381 	env_markenv(M);
382       }
383     }
384   }
385 }
386 
editstate_saveOrig(EditState * es)387 void editstate_saveOrig(EditState *es)
388 {
389   if (es->save_x != TkGate.circuit->org_x || es->save_y != TkGate.circuit->org_y) {
390     ob_touch(es);
391     es->save_x = TkGate.circuit->org_x;
392     es->save_y = TkGate.circuit->org_y;
393   }
394 }
395 
env_removeModule(const char * name,int force)396 GModuleDef *env_removeModule(const char *name,int force)
397 {
398   GModuleDef *M;
399 
400   M = (GModuleDef*) SHash_find(TkGate.circuit->moduleTable,name);
401   if (!M) return 0;
402 
403   if (!force && (GModuleDef_isTop(M) || GModuleDef_isDataProtected(M))) {
404     return 0;
405   }
406 
407   SHash_remove(TkGate.circuit->moduleTable,name);
408   modint_deleteInterface(M);
409 
410   return M;
411 }
412 
413 /*
414    Delete the specified block
415 */
env_delete(EditState * es,const char * name)416 int env_delete(EditState *es,const char *name)
417 {
418   GModuleDef *M;
419 
420   while (es) {
421     if (strcmp(es->env->m_name,name) == 0) {
422       message(1,msgLookup("err.badopendel"));			/* "Can't delete open module." */
423       return -1;
424     }
425     es = es->parent;
426   }
427 
428   /*****************************************************************************
429    *
430    * Do error checking
431    *
432    *****************************************************************************/
433   M = (GModuleDef*) SHash_find(TkGate.circuit->moduleTable,name);
434   if (!M) {
435     message(1,msgLookup("err.nomod"),name);
436     return -1;
437   }
438   if (GModuleDef_isTop(M)) {
439     message(1,msgLookup("err.deltop"),name);
440     return -1;
441   }
442   if (GModuleDef_isDataProtected(M)) {
443     message(1,msgLookup("err.delprot"),name);
444     return -1;
445   }
446 
447 
448   /*****************************************************************************
449    *
450    * Do the actual delete here.
451    *
452    *****************************************************************************/
453   if (!env_removeModule(name,0))
454     return -1;
455 
456   SetModified(MF_MODULE);
457   FlagRedraw();
458   return 0;
459 }
460 
461 
462 /*****************************************************************************
463  *
464  * Renames a module definition.
465  *
466  * Parameters:
467  *     oldName		Old module name.
468  *     newName		New module name.
469  *
470  *****************************************************************************/
env_rename(const char * oldName,const char * newName)471 int env_rename(const char *oldName,const char *newName)
472 {
473   GModuleDef *M;
474 
475   M = env_findModule(oldName);
476   if (!M) return ENOENT;
477 
478   if (SHash_find(TkGate.circuit->moduleTable,newName)) return EEXIST;
479   SHash_remove(TkGate.circuit->moduleTable,oldName);
480   SHash_insert(TkGate.circuit->moduleTable,newName,M);
481   ob_touch(M);
482   ob_free(M->m_name);
483   M->m_name = ob_strdup(newName);
484   M->m_needScan = 1;
485 
486   modint_renameInterface(M);
487 
488   if (GModuleDef_getType(M) == MT_TEXTHDL) {
489     hdl_replaceName(M,M->m_name);
490   }
491 
492   FlagRedraw();
493 
494   return 0;
495 }
496 
497 /*****************************************************************************
498  *
499  * Copy the contents of on module definition to another.
500  *
501  * Parameters:
502  *      src		Name of the source module for copy
503  *      dst		Name of the destination module for copy
504  *****************************************************************************/
env_copy(EditState * es,const char * src,const char * dst)505 void env_copy(EditState *es,const char *src,const char *dst)
506 {
507   GModuleDef *S,*D;
508 
509   S = env_findModule(src);
510   D = env_findModule(dst);
511 
512   if (!S) {
513     message(1,msgLookup("err.nosrcmod"),src);		/* "Source module '%s' not found" */
514     return;
515   }
516 
517   if (D) {
518     char buf[1024];
519 
520     sprintf(buf,msgLookup("msg.modoverwt"),dst);	/* Destination module '%s' already exists.  Overwrite? */
521     DoTcl("confirmMsg \"%s\" ",buf);
522     if (Tcl_GetStringResult(TkGate.tcl)[0] != '1')
523       return;
524 
525     env_removeModule(dst,0);
526     if (env_findModule(dst))
527       return;
528   }
529 #if 0
530   printf("defining block |%s|\n",dst);
531 #endif
532   D = env_defineModule(dst,0);
533 
534   GModuleDef_copy(D,S);
535 }
536 
editstate_Init(EditState * es)537 void editstate_Init(EditState *es)
538 {
539   ob_touch(es);
540   es->isInterface = 0;
541   es->save_x = es->save_y = 0;
542   es->parent = 0;
543   es->env = 0;
544   es->smod = 0;
545   es->inst = 0;
546 }
547 
new_EditState()548 EditState *new_EditState()
549 {
550   EditState *es;
551 
552   es = (EditState*) ob_malloc(sizeof(EditState),"EditState");
553 
554   editstate_Init(es);
555 
556   return es;
557 }
558 
delete_editstate(EditState * es)559 void delete_editstate(EditState *es)
560 {
561   ob_free(es);
562 }
563 
editstate_update(EditState * es)564 void editstate_update(EditState *es)
565 {
566 #if 0
567   ob_touch(TkGate.circuit);
568 #endif
569 
570 #if 1
571   /* TkGate.ed not subject to undo */
572   TkGate.ed->min_x = 0x7fffffff;
573   TkGate.ed->min_y = 0x7fffffff;
574   TkGate.ed->max_x = -0x7fffffff;
575   TkGate.ed->max_y = -0x7fffffff;
576 #endif
577 
578   mark_redraw();
579 
580   if (es->clip.isActive) {
581     XRectangle cr;
582     cr.x = es->clip.xmin;
583     cr.y = es->clip.ymin;
584     cr.width = es->clip.xmax - es->clip.xmin;
585     cr.height = es->clip.ymax - es->clip.ymin;
586     XSetClipRectangles(TkGate.D,TkGate.instGC,0,0,&cr,1,YXSorted);
587     XSetClipRectangles(TkGate.D,TkGate.moduleGC,0,0,&cr,1,YXSorted);
588     XSetClipRectangles(TkGate.D,TkGate.modportGC,0,0,&cr,1,YXSorted);
589     XSetClipRectangles(TkGate.D,TkGate.frameGC,0,0,&cr,1,YXSorted);
590     XSetClipRectangles(TkGate.D,GatePainterContext_gc(TkGate.commentContext),
591 	0,0,&cr,1,YXSorted);
592     XSetClipRectangles(TkGate.D,TkGate.hyperlinkGC,0,0,&cr,1,YXSorted);
593     XSetClipRectangles(TkGate.D,TkGate.wireGC,0,0,&cr,1,YXSorted);
594     XSetClipRectangles(TkGate.D,TkGate.busGC,0,0,&cr,1,YXSorted);
595     XSetClipRectangles(TkGate.D,TkGate.selWireGC,0,0,&cr,1,YXSorted);
596     XSetClipRectangles(TkGate.D,TkGate.selBusGC,0,0,&cr,1,YXSorted);
597     XSetClipRectangles(TkGate.D,TkGate.toolGC,0,0,&cr,1,YXSorted);
598     XSetClipRectangles(TkGate.D,TkGate.cpathGC,0,0,&cr,1,YXSorted);
599     if (TkGate.japaneseMode) {
600       XSetClipRectangles(TkGate.D,TkGate.kanjiGC,0,0,&cr,1,YXSorted);
601     }
602   }
603 
604   gate_displayall(es->env);
605 
606   /*
607    * Happens only if the module is empty.
608    */
609   if (TkGate.ed->min_x > TkGate.ed->max_x)
610     TkGate.ed->min_x = TkGate.ed->max_x = TkGate.ed->min_y = TkGate.ed->max_y = 0;
611 
612 
613   scrollbar_update();
614 
615   /*
616    * Draw special mode-specific items
617    */
618   switch (tkgate_currentMode()) {
619   case MM_SIMULATE :
620     SimInterface_drawProbes(&TkGate.circuit->simulator);
621     break;
622   default :
623     break;
624   }
625 
626 
627   if (TkGate.ErrorMarkTimeout) {
628     DrawErrorPositionMark();
629     TkGate.ErrorMarkTimeout = 1;
630   }
631 
632   if (es->clip.isActive) {
633     XSetClipMask(TkGate.D,TkGate.instGC,None);
634     XSetClipMask(TkGate.D,TkGate.moduleGC,None);
635     XSetClipMask(TkGate.D,TkGate.modportGC,None);
636     XSetClipMask(TkGate.D,TkGate.frameGC,None);
637     XSetClipMask(TkGate.D,GatePainterContext_gc(TkGate.commentContext),None);
638     XSetClipMask(TkGate.D,TkGate.hyperlinkGC,None);
639     XSetClipMask(TkGate.D,TkGate.wireGC,None);
640     XSetClipMask(TkGate.D,TkGate.busGC,None);
641     XSetClipMask(TkGate.D,TkGate.selWireGC,None);
642     XSetClipMask(TkGate.D,TkGate.selBusGC,None);
643     XSetClipMask(TkGate.D,TkGate.toolGC,None);
644     XSetClipMask(TkGate.D,TkGate.cpathGC,None);
645     if (TkGate.japaneseMode) {
646       XSetClipMask(TkGate.D,TkGate.kanjiGC,None);
647     }
648   }
649 }
650 
editstate_fullUpdate(EditState * es)651 void editstate_fullUpdate(EditState *es)
652 {
653 #if DEBUG_REDISPLAY
654   printf("editstate_fullUpdate(*)\n");
655 #endif
656   wm_GetDimensions(&TkGate.width,&TkGate.height);
657   XClearWindow(TkGate.D,TkGate.W);
658   mark_flush();
659 
660   if (!es) return;
661 
662   if (es->env == TkGate.circuit->mid_display) {
663     modint_center();
664   }
665 
666 #if 0
667   /* Not needed */
668   ob_touch(es);
669 #endif
670 
671   ob_begin_framef("-SaveOrig",FF_TRANSPARENT|FF_BACKGROUND);
672   editstate_saveOrig(es);
673   ob_touch(es);
674   es->clip.isActive = 0;
675   es->clip.xmin = 0;
676   es->clip.ymin = 0;
677   es->clip.xmax = TkGate.width;
678   es->clip.ymax = TkGate.height;
679   ob_end_frame();
680   editstate_update(es);
681 }
682 
683 /*
684    Do a partial screen update.
685 */
editstate_regionUpdate(EditState * es,int xmin,int ymin,int xmax,int ymax)686 void editstate_regionUpdate(EditState *es,int xmin,int ymin,int xmax,int ymax)
687 {
688 #if DEBUG_REDISPLAY
689   printf("editstate_regionUpdate(*,%d,%d,%d,%d)\n",xmin,ymin,xmax,ymax);
690 #endif
691 
692   wm_GetDimensions(&TkGate.width,&TkGate.height);
693   mark_hide();
694   XClearArea(TkGate.D,TkGate.W,xmin,ymin,xmax-xmin,ymax-ymin,False);
695 
696   if (!es) return;
697 
698 #if 0
699   /* Not needed */
700   ob_touch(es);
701 #endif
702   editstate_saveOrig(es);
703   es->clip.isActive = 1;
704   es->clip.xmin = xmin;
705   es->clip.ymin = ymin;
706   es->clip.xmax = xmax;
707   es->clip.ymax = ymax;
708 
709   editstate_update(es);
710 }
711 
712 /*
713  * Set the tkg_currentPath and tkg_currentModule variables
714  */
editstate_displayPathString(EditState * cur_es)715 void editstate_displayPathString(EditState *cur_es)
716 {
717   EditState *estack[MAX_STACKDEPTH];
718   EditState *es;
719   char path[STRMAX],*p;
720   int esp,i;
721 
722   es = cur_es;
723   for (esp = 0;esp < MAX_STACKDEPTH && es;es = es->parent)
724     estack[esp++] = es;
725 
726   p = path;
727   sprintf(p,"/");
728   p = p + strlen(p);
729 
730   DoTcl("catch { unset tkg_pathInstance }");
731   for (i = esp-1;i >= 0;i--) {
732     if (i != esp-1) *p++ = '/';
733     if (estack[i]->inst) {
734       DoTcl("set ::tkg_pathInstance(%s) \" (%s)\"",estack[i]->env->m_name,estack[i]->inst->ename);
735     } else {
736       DoTcl("set ::tkg_pathInstance(%s) \"\"",estack[i]->env->m_name);
737     }
738     strcpy(p,estack[i]->env->m_name);
739     p = p + strlen(p);
740   }
741 
742   if (TkGate.tcl) {
743     Tcl_SetVar(TkGate.tcl,"tkg_currentPath",path,TCL_GLOBAL_ONLY);
744     Tcl_SetVar(TkGate.tcl,"tkg_currentModule",cur_es->env->m_name,TCL_GLOBAL_ONLY);
745   }
746 }
747 
748 /*****************************************************************************
749  *
750  * Do any special processing when an editstate becomes active
751  *
752  *****************************************************************************/
editstate_setCurrent(EditState * es)753 void editstate_setCurrent(EditState *es)
754 {
755   GModuleDef_listNets(es->env);
756   GModuleDef_listPorts(es->env);
757   editstate_displayPathString(es);
758 
759   if (tkgate_currentMode() == MM_SIMULATE && es && es->smod)
760     SimInterface_updateNetlistProbes(es->smod);
761 }
762 
763 /*****************************************************************************
764  *  Check for a module along the specified path.  Returns
765  *  '1' on success, '0' on failure.
766  *
767  *  Two types of paths are recognized:
768  *
769  *     mod:inst			A module name and an instance in the module
770  *     inst1.inst2.inst3	A path of instances from the root module all
771  *				but the last instance must be a module instance.
772  *****************************************************************************/
editstate_checkPath(EditState ** es,const char * path)773 int editstate_checkPath(EditState **es,const char *path)
774 {
775   GModuleDef *M = TkGate.circuit->root_mod;
776   GCElement *g;
777   char buf[STRMAX],*p,*q;
778 
779   strcpy(buf,path);
780   p = buf;
781 
782   if ((q = strchr(p,':'))) {
783     *q++ = 0;
784     M = env_findModule(p);
785     if (!M) return 0;
786     p = q;
787   } else {
788     for (;;) {
789       q = strchr(p,'.');
790       if (q) {					/* Looking for a module instance */
791 	*q++ = 0;
792 	g = GModuleDef_findGate(M,p);
793 	if (!g) return 0;
794 	if (!GCElement_isModule(g)) return 0;
795 
796 	M = env_findModule(g->u.block.moduleName);
797 	if (!M) return 0;
798 	p = q;
799       } else
800 	break;
801     }
802   }
803 
804   g = GModuleDef_findGate(M,p);
805   if (!g && !GModuleDef_findNet(M,p))
806     return 0;
807 
808   return 1;
809 }
810 
811 /*
812   Set the current module along the specified path.  Returns
813   '1' on success, '0' on failure.
814  */
editstate_setPath(EditState ** es,const char * path)815 int editstate_setPath(EditState **es,const char *path)
816 {
817   GModuleDef *M = TkGate.circuit->root_mod;
818   GCElement *g;
819   GNet *n;
820   char buf[STRMAX],*p,*q;
821 
822   strcpy(buf,path);
823   p = buf;
824 
825   if ((q = strchr(p,':'))) {
826     *q++ = 0;
827     M = env_findModule(p);
828     if (!M) return 0;
829     editstate_navigateToModule(es,M);
830     p = q;
831   } else {
832     while ((*es)->parent) editstate_pop(es);
833 
834     for (;;) {
835       q = strchr(p,'.');
836       if (q) {					/* Looking for a module instance */
837 	*q++ = 0;
838 	g = GModuleDef_findGate(M,p);
839 	if (!g) return 0;
840 	if (!GCElement_isModule(g)) return 0;
841 
842 	M = env_findModule(g->u.block.moduleName);
843 	if (!M) return 0;
844 	p = q;
845 	editstate_push(es,M,g);
846       } else
847 	break;
848     }
849   }
850 
851   g = GModuleDef_findGate(M,p);
852   n = GModuleDef_findNet(M,p);
853   if (g) {
854     editstate_setCurrent(TkGate.circuit->es);
855     GSearchContext_setPosition(M,g,0);
856   } else if (n) {
857     editstate_setCurrent(TkGate.circuit->es);
858     GSearchContext_setPosition(M,0,n);
859   } else
860     return 0;
861 
862   return 1;
863 }
864 
editstate_getPath(EditState * es,char * buf)865 char *editstate_getPath(EditState *es,char *buf)
866 {
867   if (!es->parent) {
868     *buf = 0;
869     return buf;
870   } else {
871     buf = editstate_getPath(es->parent,buf);
872     if (es->parent->parent)
873       *buf++ = '.';
874     if (es->inst)
875       strcpy(buf,es->inst->ename);
876     else
877       strcpy(buf,"-");
878     return buf + strlen(buf);
879   }
880 }
881 
882 /*****************************************************************************
883  *
884  * Push module M via instance g onto the module editing stack.
885  *
886  * Parameters
887  *     *es		The current editstate (updated with new editstate).
888  *     M		The module to open for editing
889  *     g		Optional instance of M
890  *
891  *****************************************************************************/
editstate_push(EditState ** es,GModuleDef * M,GCElement * g)892 void editstate_push(EditState **es,GModuleDef *M,GCElement *g)
893 {
894   EditState *newes;
895   GSimModule *old_sm = (es && *es) ? (*es)->smod : 0;
896 
897   mark_flush();
898 
899   newes = new_EditState();
900   ob_touch(newes);
901 
902   newes->env = M;
903   if (*es && ((*es)->inst || !(*es)->parent))
904     newes->inst = g;
905 
906   if (g && tkgate_currentMode() == MM_SIMULATE) {
907     GSimModule *sM = (GSimModule*) SHash_find((*es)->smod->children,g->ename);
908     newes->smod = sM;
909   }
910 
911   if (*es) {
912     ob_touch(*es);
913     editstate_saveOrig(*es);
914   }
915 
916   newes->parent = (*es);
917   *es = newes;
918 
919   sel_clear(*es,1);
920   TkGate_clearSelection();
921 
922   if (tkgate_currentMode() == MM_SIMULATE && es && *es)
923     SimInterface_changeCurrentModule((*es)->smod,old_sm);
924 
925   TkGate_setOrigin(0,0);
926 }
927 
editstate_pop(EditState ** es)928 void editstate_pop(EditState **es)
929 {
930   EditState *newes;
931   GSimModule *old_sm = (es && *es) ? (*es)->smod : 0;
932 
933 #if 0
934   if (tkgate_currentMode() == MM_SIMULATE && !(*es)->parent) return;
935 #endif
936 
937   if ((*es)->isInterface) {
938     modint_update(*es);
939   }
940 
941   if (!(newes = (*es)->parent)) {
942     *es = 0;
943     return;
944   }
945 
946   sel_clear(*es,1);
947   TkGate_clearSelection();
948   TkGate_setOrigin(newes->save_x,newes->save_y);
949   mark_flush();
950   delete_editstate(*es);
951   *es = newes;
952 
953   if (tkgate_currentMode() == MM_SIMULATE && es && *es)
954     SimInterface_changeCurrentModule((*es)->smod,old_sm);
955 }
956 
editstate_navigateToModule(EditState ** es,GModuleDef * M)957 void editstate_navigateToModule(EditState **es,GModuleDef *M)
958 {
959   EditState *xes;
960 
961   for (xes = *es;xes && xes->env != M;xes = xes->parent);
962 
963   if (xes) {
964     /* Move up to block */
965     while ((*es)->env != M)
966       editstate_pop(es);
967   } else {
968     /* Push down to block */
969     if (!(*es)->inst)
970       editstate_pop(es);
971     editstate_push(es,M,0);
972   }
973 }
974 
editstate_makeRootAtTop(EditState ** es)975 void editstate_makeRootAtTop(EditState **es)
976 {
977   EditState *pes;
978   int need_reroot = 0;
979 
980   EditState_unselectAll(*es);
981 
982   pes = *es;
983   while (pes->parent) {
984     if (!pes->inst) {
985       need_reroot = 1;
986       break;
987     }
988     pes = pes->parent;
989   }
990 
991   if (pes->env != TkGate.circuit->root_mod)
992     need_reroot = 1;
993 
994   if (need_reroot) {
995     while (*es)
996       editstate_pop(es);
997     editstate_push(es,TkGate.circuit->root_mod,0);
998     editstate_setCurrent(*es);
999     ClearErrorMark();
1000     net_unselect(0);
1001     FlagRedraw();
1002   }
1003 
1004 }
1005 
1006 /*****************************************************************************
1007  *
1008  * Delete all modules in the current circuit except library modules.
1009  *
1010  *****************************************************************************/
editstate_flushModules(EditState ** es)1011 void editstate_flushModules(EditState **es)
1012 {
1013   HashElem *E;
1014   PHash *lmhash;
1015 
1016   sel_clear(*es,1);
1017 
1018   while (*es)
1019     editstate_pop(es);
1020 
1021   TkGate.circuit->root_mod = 0;
1022 
1023   /*  printf("**begin flushModules xes=%x\n",TkGate.circuit->es);*/
1024   lmhash = new_PHash();
1025   for (E = Hash_first(TkGate.circuit->moduleTable);E; E = Hash_next(TkGate.circuit->moduleTable,E)) {
1026     GModuleDef *M = (GModuleDef*) HashElem_obj(E);
1027     /*printf("  deleting module: %s\n",GModuleDef_getName(M));*/
1028     if (M->m_isLib) {
1029       PHash_insert(lmhash,M,M);
1030     } else {
1031       /*printf("  deleting interface: %s %p\n",GModuleDef_getName(M),M->m_interface);*/
1032       modint_deleteInterface(M);
1033       delete_GModuleDef(M);
1034     }
1035   }
1036   SHash_flush(TkGate.circuit->moduleTable);
1037 
1038 #if 0
1039   DoTcl("tkg_blockListClear\n");
1040 #endif
1041   DoTcl("gat_setCircProp -clear");
1042 
1043   for (E = Hash_first(lmhash);E;E = Hash_next(lmhash,E)) {
1044     GModuleDef *M = (GModuleDef*) HashElem_obj(E);
1045     SHash_insert(TkGate.circuit->moduleTable,M->m_name,M);
1046   }
1047 
1048   delete_PHash(lmhash);
1049 
1050   /* i don't think we need this.  It cause trouble by deleting interfaces for
1051    * library modules we are retaining.
1052    *
1053    *  modint_flush();
1054    *  printf("**end flushModules\n");
1055    */
1056 }
1057 
1058 /*****************************************************************************
1059  *
1060  * Called before and after an undo or redo to synchronize the tcl/tk interface
1061  * elements with the new internal state.
1062  *
1063  *****************************************************************************/
undo_sync(int is_after)1064 void undo_sync(int is_after)
1065 {
1066   char buf[STRMAX];
1067   static int old_mode;
1068 
1069   if (!is_after) {
1070     /* BEFORE UNDO/REDO */
1071     old_mode = EditState_getMode();
1072   } else {
1073     /* AFTER UNDO/REDO */
1074 
1075     /*
1076      * Update list of nets/ports
1077      */
1078     editstate_setCurrent(TkGate.circuit->es);
1079 
1080     /*
1081      * Update tcl-side "mode" variable
1082      */
1083     sprintf(buf,"%d",EditState_getMode());
1084     Tcl_SetVar(TkGate.tcl,"mode",buf,TCL_GLOBAL_ONLY);
1085 
1086     /*
1087      * Update tcl-side "rot" variable
1088      */
1089     sprintf(buf,"%d",EditState_getRotation());
1090     Tcl_SetVar(TkGate.tcl,"rot",buf,TCL_GLOBAL_ONLY);
1091 
1092     /*
1093      * Reset correct cursor for mode.
1094      */
1095     if (old_mode != EditState_getMode())
1096       setEditCursor(EditState_getMode());
1097 
1098     if (editstate_isInterfaceMode()) {
1099       DoTcl("IPanel::undoSync");
1100     }
1101 
1102     DoTcl("HdlEditor::undoSync");
1103     DoTcl("Breakpoint::undoSync");
1104 
1105     SetModified(MF_MODULE|MF_SYNCONLY);
1106   }
1107 
1108   UpdateModifiedIndicator();
1109 }
1110 
1111 /*****************************************************************************
1112  *
1113  * Returns non-zero if we are in interface editing mode.
1114  *
1115  *****************************************************************************/
editstate_isInterfaceMode()1116 int editstate_isInterfaceMode()
1117 {
1118   return TkGate.circuit->es && TkGate.circuit->es->isInterface;
1119 }
1120 
1121 /*****************************************************************************
1122  *
1123  * Returns a INTFMODE_ value to indicate which interface sub-mode we are in.
1124  *
1125  *****************************************************************************/
editstate_getInterfaceMode()1126 int editstate_getInterfaceMode()
1127 {
1128   if (!TkGate.circuit->es) return INTFMODE_NONE;
1129   if (!TkGate.circuit->es->isInterface) return INTFMODE_NONE;
1130 
1131   if (TkGate.circuit->es->env == TkGate.circuit->mid_display)
1132     return INTFMODE_SINGLE;
1133   else
1134     return INTFMODE_ALL;
1135 }
1136 
1137 /*****************************************************************************
1138  *
1139  * Move the edit window the the nth error in the error list.
1140  *
1141  * Parameter:
1142  *      n		Index of error to move to
1143  *      es		Current edit state
1144  *
1145  * Returns:		New edit state
1146  *
1147  *****************************************************************************/
EditState_moveToError(int n,EditState * es)1148 EditState *EditState_moveToError(int n,EditState *es)
1149 {
1150   GateError *E;
1151 
1152   if (!TkGate.errl->errors) {
1153     message(0,msgLookup("err.misserr"));
1154     return es;
1155   }
1156 
1157   E = TkGate.errl->errors[n];
1158   return Error_open(E,es);
1159 }
1160 
EditState_setMode(int mode)1161 void EditState_setMode(int mode)
1162 {
1163   ob_touch(TkGate.circuit);
1164   TkGate.circuit->mode = mode;
1165 }
1166 
1167 
EditState_setRotation(int rot)1168 void EditState_setRotation(int rot)
1169 {
1170   ob_touch(TkGate.circuit);
1171   TkGate.circuit->rot = rot;
1172 }
1173 
1174