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 Jan 20 14:49:28 2009
19 ****************************************************************************/
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <ctype.h>
23 #include <pwd.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <assert.h>
27 #include <string.h>
28 #include "tkgate.h"
29
30 #define CP_DELTA 3
31
32 /*
33 * Maps a net name to a two-element integer array.
34 */
35 SHash *net_delay_table = 0;
36
37 /*
38 * Maps a cannonical net name to a NetAliasList
39 */
40 SHash *net_alias_table = 0;
41
new_NetAliasList()42 NetAliasList *new_NetAliasList()
43 {
44 NetAliasList *al = (NetAliasList *) ob_malloc(sizeof(NetAliasList),"NetAliasList");
45
46 al->length = 0;
47 al->names = (char**) ob_malloc(sizeof(char*) * NETALIASLIST_STEPSIZE,"char*[]");
48
49 return al;
50 }
51
delete_NetAliasList(NetAliasList * al)52 void delete_NetAliasList(NetAliasList *al)
53 {
54 int i;
55
56 for (i = 0;i < al->length;i++)
57 ob_free(al->names[i]);
58 ob_free(al);
59 }
60
NetAliasList_add(NetAliasList * al,const char * name)61 void NetAliasList_add(NetAliasList *al,const char *name)
62 {
63 if (((al->length+1) % NETALIASLIST_STEPSIZE) == 0) {
64 char **n = (char**)ob_malloc(sizeof(char*)*(al->length+1+NETALIASLIST_STEPSIZE),"char*[]");
65 int i;
66
67 for (i = 0;i < al->length;i++)
68 n[i] = al->names[i];
69 ob_free(al->names);
70 al->names = n;
71 }
72
73 al->names[al->length++] = ob_strdup(name);
74 }
75
76 /*
77 Clear all critical path marks
78 */
cpath_clear()79 void cpath_clear()
80 {
81 HashElem *E;
82 GWireList *wl;
83
84 for (E = Hash_first(TkGate.circuit->moduleTable);E;E = Hash_next(TkGate.circuit->moduleTable,E)) {
85 GModuleDef *M = (GModuleDef*)HashElem_obj(E);
86
87 for (wl = M->m_wires;wl;wl = wl->wl_next) {
88 GWire *w = wl->wl_wire;
89 w->cpath = 0;
90 }
91 }
92 }
93
cpath_flush()94 void cpath_flush()
95 {
96 if (TkGate.cpath_pelems) {
97 int i;
98
99 for (i = 0;i < TkGate.cpath_len;i++)
100 ob_free(TkGate.cpath_pelems[i]);
101 ob_free(TkGate.cpath_pelems);
102 TkGate.cpath_pelems = 0;
103 TkGate.cpath_len = 0;
104 }
105 }
106
107 /*
108 * find the port corresponding to 'name'. The 'name' string is
109 * destroyed in the process.
110 */
cpath_findGatePort(const char * Gname,const char * Pname,int n,GModuleDef * M)111 GWire *cpath_findGatePort(const char *Gname,const char *Pname,int n,GModuleDef *M)
112 {
113 int i,j;
114 GCElement *g;
115
116 #if 0
117 printf(" cpath_findGatePort: %s %s %d\n",Gname,Pname,n);
118 #endif
119
120 g = GModuleDef_findGate(M,Gname);
121
122 if (g) { /* Gname is at this level */
123 int N = GCElement_numPads(g);
124
125 for (i = 0;i < N;i++) {
126 if (strcmp(Pname,GCElement_getPadName(g,i)) == 0) {
127 GWire *w = g->wires[i];
128
129 for (j = 0;w && j < n;j++)
130 w = w->next;
131 return w;
132 }
133 }
134 return 0;
135 } else { /* Gname is at a different level */
136 GWire *w;
137 char *x;
138
139 x = strchr(Gname,'.');
140 if (!x) return 0;
141 *x = 0;
142 g = GModuleDef_findGate(M,Gname);
143 if (!g) return 0;
144
145 /*
146 * Special case for regular (not symbol) modules.
147 */
148 if (g->typeinfo->code == GC_BLOCK) {
149 int N = GCElement_numPads(g);
150
151 Gname = x+1;
152
153 w = cpath_findGatePort(Gname,Pname,n,env_findModule(g->u.block.moduleName));
154 if (!w) return 0;
155
156 for (i = 0;i < N;i++) {
157 GWire *mw;
158
159 for (mw = g->wires[i];mw;mw = mw->next) {
160 if (strcmp(w->net->n_signame,mw->name) == 0)
161 return mw;
162 }
163 }
164 }
165
166 return 0;
167 }
168 }
169
cpath_findPort(const char * name,GModuleDef * M)170 GWire *cpath_findPort(const char *name,GModuleDef *M)
171 {
172 char buf[STRMAX];
173 char *Gname,*Pname,*x;
174 int n;
175
176 if (!name) return 0;
177
178 strcpy(buf,name);
179
180 Gname = buf;
181 Pname = strchr(Gname,'[');
182 if (!Pname) return 0;
183
184 *Pname++ = 0;
185 x = strchr(Pname,']');
186 if (x) *x = 0;
187
188 for (x = Pname;*x && !isdigit(*x);x++);
189 if (sscanf(x,"%d",&n) == 1)
190 *x = 0;
191 else
192 n = 0;
193
194 return cpath_findGatePort(Gname,Pname,n,M);
195
196 }
197
198 /*
199 * Highlight the path from w1 to w2
200 */
cpath_highlightPath(GWire * w1,GWire * w2)201 int cpath_highlightPath(GWire *w1,GWire *w2)
202 {
203 GCElement *g;
204 GGateInfo *gi;
205
206 if (!w1 || w1->cpath)
207 return 0;
208
209 w1->cpath = 1;
210 w1 = wire_other(w1);
211 w1->cpath = 1;
212
213 if (w1 == w2 || wire_other(w1) == w2) return 1;
214
215 g = w1->gate;
216 if (g) {
217 int i;
218
219 gi = g->typeinfo;
220 switch (gi->code) {
221 case GC_JOINT :
222 for (i = 0;i < 4;i++)
223 if (cpath_highlightPath(g->wires[i],w2))
224 return 1;
225 break;
226 case GC_TAP :
227 if (w1 == g->wires[TAP_IN]) {
228 if (cpath_highlightPath(g->wires[TAP_OUT],w2))
229 return 1;
230 } else if (w1 == g->wires[TAP_OUT]) {
231 if (cpath_highlightPath(g->wires[TAP_IN],w2))
232 return 1;
233 }
234 break;
235 }
236 }
237
238 w1->cpath = 0;
239 w1 = wire_other(w1);
240 w1->cpath = 0;
241 return 0;
242 }
243
244 /*
245 * A starting port has not been explicitly specified. Try to
246 * guess the initial port.
247 */
cpath_guessPort(GWire * w,GModuleDef * M,int isOut)248 GWire *cpath_guessPort(GWire *w,GModuleDef *M,int isOut)
249 {
250 GNet *n = w->net;
251 HashElem *E;
252
253 if (!M) return 0;
254
255 for (E = Hash_first(M->m_gates);E;E = Hash_next(M->m_gates,E)) {
256 GCElement *g = (GCElement*) HashElem_obj(E);
257
258 switch (g->typeinfo->code) {
259 case GC_LOGICIN :
260 case GC_LOGICOUT :
261 case GC_LOGICTRI :
262 if (g->wires[0]->net == n)
263 return g->wires[0];
264 break;
265 case GC_SWITCH :
266 case GC_DIP :
267 if (isOut) {
268 if (g->wires[0]->net == n)
269 return g->wires[0];
270 }
271 break;
272 case GC_LED :
273 if (!isOut) {
274 if (g->wires[0]->net == n)
275 return g->wires[0];
276 }
277 break;
278 case GC_REGISTER :
279 case GC_FLIPFLOP :
280 {
281 int N = GCElement_numPads(g);
282 int i;
283
284 for (i = 0;i < N;i++) {
285 if (isOut && GCElement_getPadDir(g,i) == OUT && g->wires[i]->net == n)
286 return g->wires[i];
287 if (!isOut && GCElement_getPadDir(g,i) == IN && g->wires[i]->net == n)
288 return g->wires[i];
289 }
290 }
291 break;
292 }
293 }
294
295 return 0;
296 }
297
298 /*
299 Display an n-element path. Each element of the path is a string of
300 the form <port1>:net:<port2>
301 */
cpath_show_aux(int n,char * pelems[])302 void cpath_show_aux(int n,char *pelems[])
303 {
304 GModuleDef *M;
305 GWireList *wl;
306 char modPath[STRMAX];
307 int i,j,l;
308 NetAliasList *al;
309
310 M = TkGate.circuit->es->env;
311
312 editstate_getPath(TkGate.circuit->es,modPath);
313 l = strlen(modPath);
314 if (l > 0) {
315 strcat(modPath,".");
316 l++;
317 }
318 for (i = 0;i < n;i++) {
319 char port1[STRMAX],netName[STRMAX],port2[STRMAX];
320 GNet *net = 0;
321 GWire *w1 = 0,*w2 = 0;
322
323 if (sscanf(pelems[i],"<%[^>]>:%[^:]:<%[^>]>",port1,netName,port2) == 3) {
324 } else if (sscanf(pelems[i],"<>:%[^:]:<%[^>]>",netName,port2) == 2) {
325 *port1 = 0;
326 } else if (sscanf(pelems[i],"<%[^>]>:%[^:]:<>",port1,netName) == 2) {
327 *port2 = 0;
328 } else if (sscanf(pelems[i],"<>:%[^:]:<>",netName) == 1) {
329 *port1 = 0;
330 *port2 = 0;
331 }
332
333 /*printf("cpath [%s]: <%s %s>\n",netName,port1,port2);*/
334
335 net = 0;
336 al = (NetAliasList*) SHash_find(net_alias_table,netName);
337 if (al) {
338 for (j = 0;!net && j < al->length;j++) {
339 if (l != 0 && strncmp(modPath,al->names[j],l) != 0) {
340 continue;
341 }
342 net = GModuleDef_findNet(M,al->names[j]+l);
343 }
344 }
345
346 if (!net) continue; /* Net is not in this module */
347
348 if (l == 0 || (*port1 && strncmp(port1,modPath,l) == 0))
349 w1 = cpath_findPort(port1+l,TkGate.circuit->es->env);
350
351 if (l == 0 || (*port2 && strncmp(port2,modPath,l) == 0))
352 w2 = cpath_findPort(port2+l,TkGate.circuit->es->env);
353
354 if (w1 == w2) continue;
355
356 if (w1 && !w2) w2 = cpath_guessPort(w1,M,0);
357 if (w2 && !w1) w1 = cpath_guessPort(w2,M,1);
358
359 #if 0
360 printf("cpath_show: |%s| w1=%x w2=%x modPath=%s l=%d net=%x\n",pelems[i],w1,w2,modPath,l,net);
361 #endif
362
363 if (!w1 && !w2) { /* No port info, highligh full net */
364 for (wl = M->m_wires;wl;wl = wl->wl_next) {
365 GWire *w = wl->wl_wire;
366 if (w->net != net) continue;
367 w->cpath = 1;
368 }
369 } else if (!w1) { /* highlight w2 only */
370 w1 = wire_driver(w2);
371 w2 = wire_drivee(w1);
372 w1->cpath = w2->cpath = 1;
373 } else if (!w2) { /* highlight w1 only */
374 w1 = wire_driver(w1);
375 w2 = wire_drivee(w1);
376 w1->cpath = w2->cpath = 1;
377 } else { /* highlight path */
378 cpath_highlightPath(w1,w2);
379 }
380 }
381 }
382
cpath_close()383 void cpath_close()
384 {
385 cpath_flushNetDelayTable();
386 DoTcl("catch { set analyOn 0 }");
387 DoTcl("catch { close $simId }");
388 DoTcl("catch { destroy .cpbox }");
389 ClearErrorMark();
390 }
391
392 /*
393 * Execute a command from the analyzer
394 */
cpath_command(const char * C)395 int cpath_command(const char *C)
396 {
397 char buf[STRMAX],buf2[STRMAX];
398 int t,a1,a2;
399 extern int debugSimInterface;
400 int area,staticPower;
401
402 if (debugSimInterface) {
403 printf("Analyze: %s\n",C);
404 fflush(stdout);
405 }
406
407 while (*C == ' ')C++;
408 if (strncmp(C,"comment",7) == 0) { /* Ignore comments from simulator */
409 return 0;
410 } else if (strncmp(C,"echo",4) == 0) {
411 printf("gsim: %s\n",C);
412 return 0;
413 } else if (strncmp(C,"ok",2) == 0) { /* Simulator loaded file and is ready to go */
414 DoTcl("tkg_cpathStart");
415 } else if (strncmp(C,"error_exit",10) == 0) { /* The simulator exited on an error */
416 Error_close();
417 tkgate_setMajorMode(MM_EDIT);
418 } else if (sscanf(C," netalias %s %s",buf,buf2) == 2) { /* Net alias definition */
419 cpath_registerNetAlias(buf,buf2);
420 } else if (sscanf(C," netdelay %s %d %d",buf,&a1,&a2) == 3) { /* Net delay values */
421 cpath_registerNetDelay(buf,a1,a2);
422 } else if (sscanf(C," cpath_loop %s",buf) == 1) { /* Combinational loop */
423 DoTcl("tkg_cpathAddLoop %s",buf);
424 } else if (sscanf(C," cpath %d %[^\n]",&t,buf) == 2) { /* Critical path */
425 DoTcl("tkg_cpathAdd %d {%s}",t,buf);
426 } else if (strncmp(C,"cdone",5) == 0) { /* End of critical path data */
427 DoTcl("tkg_cpathEnd");
428 } else if (sscanf(C," stats area=%d static_power=%d",&area,&staticPower) == 2) {/* Circuit statistics */
429 message(0,"Estimated area=%d.",area,staticPower);
430 } else if (sscanf(C," warning file %[^\n]",buf) == 1) { /* An error in a simulator input file. */
431 Error_report(C);
432 } else if (sscanf(C," error file %[^\n]",buf) == 1) { /* An error in a simulator input file. */
433 Error_report(C);
434 } else if (sscanf(C," simerror %[^\n]",buf) == 1) { /* A run-time error */
435 message(1,buf);
436 }
437 return 0;
438
439 }
440
cpath_open()441 void cpath_open()
442 {
443 /** @TODO to remove */
444 /*
445 EditState *es;
446 */
447 char tempName[STRMAX];
448
449 editstate_makeRootAtTop(&TkGate.circuit->es);
450 /** @TODO to remove */
451 /* es = TkGate.circuit->es;*/
452
453 getSimTempFile(tempName);
454
455 if (VerilogWriteModules(tempName,VSO_ALLMODS|VSO_NOHDLCHECK) != 0) { /* Save circuit to send to simulator/analyzer */
456 /* Could not save temporary file '%s' for simulator (disc full?) */
457 message(1,msgLookup("err.sim.badtmp"),tempName);
458 return;
459 }
460
461 DoTcl("tkg_startAnalyzer %s",tempName);
462 }
463
cpath_show(int n,const char * pelems[])464 void cpath_show(int n,const char *pelems[])
465 {
466 int i;
467
468 cpath_clear();
469 cpath_flush();
470 ClearErrorMark();
471
472 if (n <= 0) return;
473
474 #if 0
475 printf("cpath_show:");
476 for (i = 0;i < n;i++)
477 printf(" %s",pelems[i]);
478 printf("\n");
479 #endif
480
481 TkGate.cpath_len = n;
482 TkGate.cpath_pelems = (char**) ob_malloc(sizeof(char*)*n,"char*[]");
483 for (i = 0;i < n;i++) {
484 TkGate.cpath_pelems[i] = ob_strdup(pelems[i]);
485 }
486 cpath_show_aux(TkGate.cpath_len,TkGate.cpath_pelems);
487 FlagRedraw();
488 }
489
490 /*
491 * Redisplay the current critical path if one is visible
492 */
cpath_reshow()493 void cpath_reshow()
494 {
495 if (tkgate_currentMode() != MM_ANALYZE) return;
496
497 cpath_clear();
498 cpath_show_aux(TkGate.cpath_len,TkGate.cpath_pelems);
499 FlagRedraw();
500 }
501
cpath_draw(int x1,int y1,int x2,int y2)502 void cpath_draw(int x1,int y1,int x2,int y2)
503 {
504 int n,i;
505 int dx = x2-x1;
506 int dy = y2-y1;
507 int x,y;
508 int x_off = 0,y_off = 0;
509
510 n = (dx+dy)/CP_DELTA;
511 if (n < 0) n = -n;
512
513 /*
514 Only one of dx or dy should be non-zero
515 */
516 if (dx > 0)
517 dx = CP_DELTA;
518 else if (dx < 0)
519 dx = -CP_DELTA;
520
521 if (dy > 0)
522 dy = CP_DELTA;
523 else if (dy < 0)
524 dy = -CP_DELTA;
525
526 /*
527 * Correct for variations in X servers.
528 */
529 if (dx == 0) {
530 x_off = TKGATE_BUSW_VERT-1;
531 } else {
532 y_off = TKGATE_BUSW_HORZ-1;
533 }
534
535 x = x1;
536 y = y1;
537 for (i = 0;i < n;i++) {
538 x += dx;
539 y += dy;
540 Icon_draw(TkGate.D,TkGate.W,TkGate.cpathGC,x+x_off,y+y_off,SIZEHASH);
541 }
542 }
543
cpath_drawSegments()544 void cpath_drawSegments()
545 {
546 GModuleDef *M = TkGate.circuit->es->env;
547 GWireList *wl;
548
549 for (wl = M->m_wires;wl;wl = wl->wl_next) {
550 GWire *w = wl->wl_wire;
551
552 if (w->cpath && w->nodes->out)
553 GWire_draw(w);
554 }
555 }
556
557 /*
558 Called at regular intervals while cpath is displayed to
559 flash the cpath state.
560 */
cpath_flash()561 void cpath_flash()
562 {
563 if (!TkGate.circuit->es) return;
564
565 if (TkGate.flashCPath) {
566 cpath_drawSegments();
567 TkGate.cpath_flashState = !TkGate.cpath_flashState;
568 cpath_drawSegments();
569 } else if (!TkGate.cpath_flashState) {
570 cpath_drawSegments();
571 TkGate.cpath_flashState = 1;
572 cpath_drawSegments();
573 }
574 }
575
init_cpathNetDelayTable(void)576 void init_cpathNetDelayTable(void)
577 {
578 net_delay_table = new_SHash();
579 net_alias_table = new_SHash();
580 }
581
cpath_flushNetDelayTable()582 void cpath_flushNetDelayTable()
583 {
584 HashElem *E;
585
586 for (E = Hash_first(net_delay_table);E;E = Hash_next(net_delay_table,E)) {
587 int *d = (int*)HashElem_obj(E);
588 ob_free(d);
589 }
590 SHash_flush(net_delay_table);
591
592 for (E = Hash_first(net_delay_table);E;E = Hash_next(net_delay_table,E)) {
593 NetAliasList *d = (NetAliasList*)HashElem_obj(E);
594 delete_NetAliasList(d);
595 }
596 SHash_flush(net_alias_table);
597 }
598
cpath_registerNetAlias(const char * alias_name,const char * canon_name)599 void cpath_registerNetAlias(const char *alias_name,const char *canon_name)
600 {
601 NetAliasList *al = (NetAliasList*)SHash_find(net_alias_table,canon_name);
602
603 #if 0
604 printf("cpath_registerNetAlias: %s %s\n",alias_name,canon_name);
605 #endif
606
607 if (!al) {
608 al = new_NetAliasList();
609 SHash_insert(net_alias_table,canon_name,al);
610 }
611
612 NetAliasList_add(al,alias_name);
613 }
614
cpath_registerNetDelay(const char * name,int fd,int bd)615 void cpath_registerNetDelay(const char *name,int fd,int bd)
616 {
617 int *d;
618
619 cpath_registerNetAlias(name,name);
620 #if 0
621 printf("cpath_registerNetDelay: %s fd=%d bd=%d\n",name,fd,bd);
622 #endif
623
624 d = SHash_find(net_delay_table,name);
625 if (!d) {
626 d = (int*)ob_malloc(2*sizeof(int),"int[2]");
627 SHash_insert(net_delay_table,name,d);
628 }
629
630 d[0] = fd;
631 d[1] = bd;
632 }
633
cpath_getNetDelay(const char * name,int * fd,int * bd)634 int cpath_getNetDelay(const char *name,int *fd,int *bd)
635 {
636 int *d;
637
638 d = SHash_find(net_delay_table,name);
639 if (d) {
640 if (fd) *fd = d[0];
641 if (bd) *bd = d[1];
642 return 1;
643 }
644
645 return 0;
646 }
647
cpath_showNetDelay(GNet * n)648 void cpath_showNetDelay(GNet *n)
649 {
650 char buf[STRMAX];
651 int fd,bd;
652
653 editstate_getPath(TkGate.circuit->es,buf);
654 if (*buf) {
655 char *p = buf+strlen(buf);
656 sprintf(p,".%s",n->n_signame);
657 } else
658 strcpy(buf,n->n_signame);
659
660 if (cpath_getNetDelay(buf,&fd,&bd))
661 DoTcl("tkg_postNetDelay %s %d %d",buf,fd,bd);
662 }
663
664 /*
665 Mouse button press while in cpath mode.
666 */
cpath_mouseDown(EditState * es)667 void cpath_mouseDown(EditState *es)
668 {
669 GCElement *g = gate_hit(es->env,TkGate.ed->tx,TkGate.ed->ty);
670 GWireNode *wn = wire_iohit(TkGate.ed->tx,TkGate.ed->ty,es->env->m_wires);
671
672 if (wn) {
673 GWire *w = wirenode_driver(wn);
674
675 EditState_unselectGate(es);
676 cpath_showNetDelay(w->net);
677 net_select(w->net,1);
678 } else if (g) {
679 net_unselect(1);
680 EditState_selectGate(es,TkGate.ed->tx,TkGate.ed->ty);
681 } else {
682 EditState_unselectGate(es);
683 net_unselect(1);
684 }
685 }
686
cpath_mouseUp(EditState * es)687 void cpath_mouseUp(EditState *es)
688 {
689 DoTcl("tkg_unpostNetDelay");
690 }
691