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