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