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