1 /*
2 * Copyright (c) Yiftach Tzori 2009-2012.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 */
9 #include <config.h>
10 #include "globals.h"
11 #include <gtk/gtk.h>
12 #include <gdk/gdkkeysyms.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include "gtk12compat.h"
16 #include "analyzer.h"
17 #include "tree.h"
18 #include "symbol.h"
19 #include "vcd.h"
20 #include "lx2.h"
21 #include "busy.h"
22 #include "debug.h"
23 #include "hierpack.h"
24 #include "tcl_helper.h"
25 #include "tcl_support_commands.h"
26
27 /* **
28 * Search for a tree node that is associated with the hierarchical path
29 * return pointer to this node or NULL
30 */
SST_find_node_by_path(GtkCTreeRow * root,char * path)31 GtkCTreeNode *SST_find_node_by_path(GtkCTreeRow *root, char *path) {
32 char *s = strdup_2(path) ;
33 char *p = s ;
34 char *p1 ;
35 GtkCTreeRow *gctr = root ;
36 GtkCTreeNode *node = gctr->parent ;
37 struct tree *t ;
38 int i ;
39 /* in the cases of path that where generated inside a `generate-for' block
40 * path name will contain '[]'. This will prompt TCL to soround PATH with
41 * '{' and '}'
42 */
43 if (*p == '{' && (p1 = strrchr(p, '}'))) {
44 p++ ;
45 *p1 = '\0' ;
46 }
47 while (gctr) {
48 if ((p1 = strchr(p, '.')))
49 *p1 = '\0' ;
50 t = (struct tree *)(gctr->row.data) ;
51 i = 0 ;
52 while (strcmp(t->name, p)) { /* name mis-match */
53 if (!(node = gctr->sibling)) { /* no more siblings */
54 gctr = NULL ;
55 break ;
56 } else {
57 gctr = GTK_CTREE_ROW(node);
58 t = (struct tree *)(gctr->row.data) ;
59 }
60 i++ ;
61 }
62 if (gctr) { /* normal exit from the above */
63 if(!p1) {/* first/last in chain */
64 if(i == 0) /* first */
65 if(gctr->children)
66 node = GTK_CTREE_ROW(gctr->children)->parent ;
67 break ;
68 } else { /* keep going down the hierarchy */
69 if (!(node = gctr->children))
70 break ;
71 else {
72 gctr = GTK_CTREE_ROW(gctr->children) ;
73 p = p1 + 1 ;
74 }
75 }
76 }
77 }
78 free_2(s) ;
79 return node ;
80 }
81
82 /* **
83 * Open the hierarchy tree, starting from 'node' up to the root
84 */
SST_open_path(GtkCTree * ctree,GtkCTreeNode * node)85 int SST_open_path(GtkCTree *ctree, GtkCTreeNode *node) {
86 GtkCTreeRow *row ;
87 for(row = GTK_CTREE_ROW(node) ; row->parent; row = GTK_CTREE_ROW(row->parent)) {
88 if(row->parent)
89 gtk_ctree_expand(ctree, row->parent);
90 else
91 break ;
92 }
93 return 0 ;
94 }
95
96 /* **
97 * Main function called by gtkwavetcl_forceOpenTreeNode
98 * Inputs:
99 * char *name :: hierachical path to open
100 * Output:
101 * One of:
102 * SST_NODE_FOUND - if path is in the dump file
103 * SST_NODE_NOT_EXIST - is path is not in the dump
104 * SST_TREE_NOT_EXIST - is Tree widget does not exist
105 * Side effects:
106 * If path is in the dump then its tree is opened and scrolled
107 * to be it to display. Node is selected and associated signals
108 * are displayed.
109 * No change in any other case
110 */
111
SST_open_node(char * name)112 int SST_open_node(char *name) {
113 int rv ;
114 #ifdef WAVE_USE_GTK2
115 GtkCTree *ctree = GLOBALS->ctree_main;
116 if (ctree) {
117 GtkCTreeRow *gctr;
118 GtkCTreeNode *target_node ;
119 for(gctr = GTK_CTREE_ROW(GLOBALS->any_tree_node); gctr->parent;
120 gctr = GTK_CTREE_ROW(gctr->parent)) ;
121 if ((target_node = SST_find_node_by_path(gctr, name))) {
122 struct tree *t ;
123 rv = SST_NODE_FOUND ;
124 gtk_ctree_collapse_recursive(ctree, gctr->parent) ;
125 SST_open_path(ctree, target_node) ;
126 gtk_ctree_node_moveto(ctree, target_node, 0, 0.5, 0.5);
127 gtk_ctree_select(ctree, target_node);
128 gctr = GTK_CTREE_ROW(target_node) ;
129 t = (struct tree *)(gctr->row.data) ;
130 GLOBALS->sig_root_treesearch_gtk2_c_1 = t->child;
131 fill_sig_store ();
132 } else {
133 rv = SST_NODE_NOT_EXIST ;
134 }
135 } else {
136 rv = SST_TREE_NOT_EXIST ;
137 }
138 #else
139 (void)name;
140 rv = SST_TREE_NOT_EXIST ;
141 #endif
142
143 return rv ;
144 }
145 /* ===== Double link lists */
llist_new(llist_u v,ll_elem_type type,int arg)146 llist_p *llist_new(llist_u v, ll_elem_type type, int arg) {
147 llist_p *p = (llist_p *)malloc_2(sizeof(llist_p)) ;
148 p->next = p->prev = NULL ;
149 switch(type) {
150 case LL_INT: p->u.i = v.i ; break ;
151 case LL_UINT: p->u.u = v.u ; break ;
152 case LL_TIMETYPE: p->u.tt = v.tt ; break ;
153 case LL_CHAR: p->u.c = v.c ; break ;
154 case LL_SHORT: p->u.s = v.s ; break ;
155 case LL_STR:
156 if(arg == -1)
157 p->u.str = strdup_2(v.str) ;
158 else {
159 p->u.str = (char *)malloc_2(arg) ;
160 strncpy(p->u.str, v.str, arg) ;
161 p->u.str[arg] = '\0' ;
162 }
163 break ;
164 case LL_VOID_P: p->u.p = v.p ; break ;
165 default:
166 fprintf(stderr, "Internal error in llist_new(), type: %d\n", type);
167 exit(255);
168 }
169 return p ;
170 }
171
172 /*
173 * append llist_p element ELEM to the of the list whose first member is HEAD amd
174 * last is TAIL. and return the head of the list.
175 * if HEAD is NULL ELEM is returned.
176 * if TAIL is defined then ELEM is chained to it and TAIL is set to point to
177 * ELEM
178 */
179
llist_append(llist_p * head,llist_p * elem,llist_p ** tail)180 llist_p *llist_append(llist_p *head, llist_p *elem, llist_p **tail) {
181 llist_p *p ;
182 if (*tail) {
183 p = tail[0] ;
184 p->next = elem ;
185 elem->prev = p ;
186 tail[0] = elem ;
187 } else {
188 if (head) {
189 for(p = head ; p->next; p = p->next) ;
190 p->next = elem ;
191 elem ->prev = p ;
192 } else {
193 head = elem ;
194 }
195 }
196 return head ;
197 }
198 /*
199 * Remove the last element from list whose first member is HEAD
200 * if TYPE is LL_STR the memory allocated for this string is freed.
201 * if the TYPE is LL_VOID_P that the caller supplied function pointer F() is
202 * is executed (if not NULL)
203 * HEAD and TAIL are updated.
204 */
205
llist_remove_last(llist_p * head,llist_p ** tail,ll_elem_type type,void * f (void *))206 llist_p *llist_remove_last(llist_p *head, llist_p **tail, ll_elem_type type, void *f(void *) ) {
207 if (head) {
208 llist_p *p = tail[0] ;
209 switch(type) {
210 case LL_STR: free_2(p->u.str) ; break ;
211 case LL_VOID_P:
212 if (f)
213 f(p->u.p) ;
214 break ;
215 default:
216 fprintf(stderr, "Internal error in llist_remove_last(), type: %d\n", type);
217 exit(255);
218 }
219 if (p->prev) {
220 tail[0] = p->prev ;
221 } else {
222 head = tail[0] = NULL ;
223 }
224 free_2(p) ;
225 }
226 return head ;
227 }
228
229 /* Destroy the list whose first member is HEAD
230 * function pointer F() is called in type is LL_VOID_P
231 * if TYPE is LL_STR then string is freed
232 */
llist_free(llist_p * head,ll_elem_type type,void * f (void *))233 void llist_free(llist_p *head, ll_elem_type type, void *f(void *)) {
234 llist_p *p = head, *p1 ;
235 while(p) {
236 p1 = p->next ;
237 switch(type) {
238 case LL_STR: free_2(p->u.str) ; break ;
239 case LL_VOID_P:
240 if (f)
241 f(p->u.p) ;
242 break ;
243 default:
244 fprintf(stderr, "Internal error in llist_free(), type: %d\n", type);
245 exit(255);
246 }
247 free_2(p) ;
248 p = p1 ;
249 }
250 }
251 /* ===================================================== */
252 /* Create a Trptr structure that contains the bit-vector VEC
253 * This is based on the function AddVector()
254 */
BitVector_to_Trptr(bvptr vec)255 Trptr BitVector_to_Trptr(bvptr vec) {
256 Trptr t;
257 int n;
258
259 GLOBALS->signalwindow_width_dirty=1;
260
261 n = vec->nbits;
262 t = (Trptr) calloc_2(1, sizeof( TraceEnt ) );
263 if( t == NULL ) {
264 fprintf( stderr, "Out of memory, can't add %s to analyzer\n",
265 vec->bvname );
266 return( 0 );
267 }
268
269 t->name = vec->bvname;
270
271 if(GLOBALS->hier_max_level)
272 t->name = hier_extract(t->name, GLOBALS->hier_max_level);
273
274 t->flags = ( n > 3 ) ? TR_HEX|TR_RJUSTIFY : TR_BIN|TR_RJUSTIFY;
275 t->vector = TRUE;
276 t->n.vec = vec;
277 /* AddTrace( t ); */
278 return( t );
279 }
280
find_first_highlighted_trace(void)281 Trptr find_first_highlighted_trace(void) {
282 Trptr t=GLOBALS->traces.first;
283 while(t) {
284 if(t->flags&TR_HIGHLIGHT) {
285 if(!(t->flags&(TR_BLANK|TR_ANALOG_BLANK_STRETCH))) {
286 break;
287 }
288 }
289 t=t->t_next;
290 }
291 return(t);
292 }
293
294 /* Find is signal named NAME is on display and return is Trptr value
295 * or NULL
296 * NAME is a full hierarchical name, but may not in include range '[..:..]'
297 * information.
298 */
is_signal_displayed(char * name)299 Trptr is_signal_displayed(char *name) {
300 Trptr t=GLOBALS->traces.first ;
301 char *p = strchr(name, '['), *p1 ;
302 unsigned int len, len1 ;
303 if(p)
304 *p = '\0' ;
305 len = strlen(name) ;
306 while(t) {
307 int was_packed = HIER_DEPACK_ALLOC;
308 int cc;
309 if(t->vector)
310 {
311 p = t->n.vec->bvname;
312 }
313 else
314 {
315 if(t->n.vec)
316 {
317 p = hier_decompress_flagged(t->n.nd->nname, &was_packed);
318 }
319 else
320 {
321 p = NULL;
322 }
323 }
324
325 if(p) {
326 p1 = strchr(p,'[') ;
327 len1 = (p1) ? (unsigned int)(p1 - p) : strlen(p) ;
328 cc = ((len == len1) && !strncmp(name, p, len));
329 if(was_packed) free_2(p);
330 if(cc)
331 break ;
332 }
333 t = t->t_next ;
334 }
335 return t ;
336 }
337
338 /* Create a Trptr structure for ND and return its value
339 * This is based on the function AddNodeTraceReturn()
340 */
Node_to_Trptr(nptr nd)341 Trptr Node_to_Trptr(nptr nd)
342 {
343 Trptr t = NULL;
344 hptr histpnt;
345 hptr *harray;
346 int histcount;
347 int i;
348
349 if(nd->mv.mvlfac) import_trace(nd);
350
351 GLOBALS->signalwindow_width_dirty=1;
352
353 if( (t = (Trptr) calloc_2( 1, sizeof( TraceEnt ))) == NULL ) {
354 fprintf( stderr, "Out of memory, can't add to analyzer\n" );
355 return( 0 );
356 }
357
358 if(!nd->harray) { /* make quick array lookup for aet display */
359 histpnt=&(nd->head);
360 histcount=0;
361
362 while(histpnt) {
363 histcount++;
364 histpnt=histpnt->next;
365 }
366
367 nd->numhist=histcount;
368
369 if(!(nd->harray=harray=(hptr *)malloc_2(histcount*sizeof(hptr)))) {
370 fprintf( stderr, "Out of memory, can't add to analyzer\n" );
371 free_2(t);
372 return(0);
373 }
374
375 histpnt=&(nd->head);
376 for(i=0;i<histcount;i++) {
377 *harray=histpnt;
378 harray++;
379 histpnt=histpnt->next;
380 }
381 }
382
383 if(!GLOBALS->hier_max_level) {
384 int flagged = HIER_DEPACK_ALLOC;
385
386 t->name = hier_decompress_flagged(nd->nname, &flagged);
387 t->is_depacked = (flagged != 0);
388 }
389 else {
390 int flagged = HIER_DEPACK_ALLOC;
391 char *tbuff = hier_decompress_flagged(nd->nname, &flagged);
392 if(!flagged) {
393 t->name = hier_extract(nd->nname, GLOBALS->hier_max_level);
394 }
395 else {
396 t->name = strdup_2(hier_extract(tbuff, GLOBALS->hier_max_level));
397 free_2(tbuff);
398 t->is_depacked = 1;
399 }
400 }
401
402 if(nd->extvals) { /* expansion vectors */
403 int n;
404
405 n = nd->msi - nd->lsi;
406 if(n<0)n=-n;
407 n++;
408
409 t->flags = (( n > 3 )||( n < -3 )) ? TR_HEX|TR_RJUSTIFY :
410 TR_BIN|TR_RJUSTIFY;
411 }
412 else {
413 t->flags |= TR_BIN; /* binary */
414 }
415 t->vector = FALSE;
416 t->n.nd = nd;
417 /* if(tret) *tret = t; ... for expand */
418 return t ;
419 }
420 /*
421 * Search for the signal named (full path) NAME in the signal data base and
422 * create a Trptr structure for it
423 * NAME is a full hierarchy name, but may not include range information.
424 * Return the structure created or NULL
425 */
sig_name_to_Trptr(char * name)426 Trptr sig_name_to_Trptr(char *name) {
427 Trptr t = NULL ;
428 int was_packed = HIER_DEPACK_ALLOC;
429 int i, name_len;
430 char *hfacname = NULL;
431 struct symbol *s = NULL, *s2 ;
432 int len = 0 ;
433 bvptr v = NULL;
434 bptr b = NULL;
435 int pre_import = 0;
436
437 if(name)
438 {
439 name_len = strlen(name);
440 for(i=0;i<GLOBALS->numfacs;i++)
441 {
442 hfacname = hier_decompress_flagged(GLOBALS->facs[i]->name, &was_packed);
443 if(!strcmp(name, hfacname) || ((!strncmp(name, hfacname, name_len) && hfacname[name_len] == '[')))
444 {
445 s = GLOBALS->facs[i];
446 if((s2 = s->vec_root))
447 {
448 s = s2;
449 }
450 else
451 {
452 s2 = s;
453 }
454
455 if(GLOBALS->is_lx2)
456 {
457 while(s2)
458 {
459 if(s2->n->mv.mvlfac) /* the node doesn't exist yet! */
460 {
461 lx2_set_fac_process_mask(s2->n);
462 pre_import++;
463 }
464
465 s2 = s2->vec_chain;
466 len++;
467 }
468 }
469 else
470 {
471 while(s2)
472 {
473 s2 = s2->vec_chain;
474 len++;
475 }
476 }
477
478 if(was_packed) { free_2(hfacname); }
479 break;
480 }
481 if(was_packed) { free_2(hfacname); }
482 s = NULL;
483 }
484
485 if(s)
486 {
487 if(pre_import)
488 {
489 lx2_import_masked(); /* import any missing nodes */
490 }
491
492 if(len > 1)
493 {
494 if ((b = makevec_chain(NULL, s, len)))
495 {
496 if((v=bits2vector(b)))
497 {
498 t = BitVector_to_Trptr(v) ;
499 }
500 else
501 {
502 free_2(b->name);
503 if(b->attribs) free_2(b->attribs);
504 free_2(b);
505 }
506 }
507 }
508 else
509 {
510 nptr node = s->n ;
511 t = Node_to_Trptr(node) ;
512 }
513 }
514
515 }
516
517 return t ;
518 }
519
520 /* Return the base prefix for the signal value */
signal_value_prefix(TraceFlagsType flags)521 char *signal_value_prefix(TraceFlagsType flags) {
522 if(flags & TR_BIN) return "0b" ;
523 if(flags & TR_HEX) return "0x" ;
524 if(flags & TR_OCT) return "0" ;
525 return "" ;
526 }
527
528 /* ===================================================== */
529
signal_change_list(char * sig_name,int dir,TimeType start_time,TimeType end_time,int max_elements)530 llist_p *signal_change_list(char *sig_name, int dir, TimeType start_time,
531 TimeType end_time, int max_elements) {
532 llist_p *l0_head = NULL, *l0_tail = NULL, *l1_head = NULL,*l_elem, *lp ;
533 llist_p *l1_tail = NULL ;
534 char *s, s1[1024] ;
535 hptr h_ptr ;
536 Trptr t = NULL ;
537 Trptr t_created = NULL;
538 if(!sig_name) {
539 t = (Trptr)find_first_highlighted_trace();
540 } else {
541 /* case of sig name, find the representing Trptr structure */
542 if (!(t = is_signal_displayed(sig_name)))
543 t = t_created = sig_name_to_Trptr(sig_name) ;
544 }
545 if (t) { /* we have a signal */
546 /* create a list of value change structs (hptrs or vptrs */
547 int nelem = 0 /* , bw = -1 */ ; /* scan-build */
548 TimeType tstart = (dir == STRACE_FORWARD) ? start_time : end_time ;
549 TimeType tend = (dir == STRACE_FORWARD) ? end_time : start_time ;
550 if ((dir == STRACE_BACKWARD) && (max_elements == 1))
551 {
552 max_elements++;
553 }
554 if (!t->vector) {
555 hptr h, h1;
556 int len = 0 ;
557 /* scan-build :
558 if(t->n.nd->extvals) {
559 bw = abs(t->n.nd->msi - t->n.nd->lsi) + 1 ;
560 }
561 */
562 h = bsearch_node(t->n.nd, tstart - t->shift) ;
563 for(h1 = h; h1; h1 = h1->next) {
564 if (h1->time <= tend) {
565 if (len++ < max_elements) {
566 llist_u llp; llp.p = h1;
567 l_elem = llist_new(llp, LL_VOID_P, -1) ;
568 l0_head = llist_append(l0_head, l_elem, &l0_tail) ;
569 if(!l0_tail) l0_tail = l0_head ;
570 } else {
571 if(dir == STRACE_FORWARD)
572 break ;
573 else {
574 if(!l0_head) /* null pointer deref found by scan-build */
575 {
576 llist_u llp; llp.p = h1;
577 l_elem = llist_new(llp, LL_VOID_P, -1) ;
578 l0_head = llist_append(l0_head, l_elem, &l0_tail) ;
579 if(!l0_tail) l0_tail = l0_head ;
580 }
581 l_elem = l0_head ;
582 l0_head = l0_head->next ; /* what scan-build flagged as null */
583 l0_head->prev = NULL ;
584 l_elem->u.p = (void *)h1 ;
585 l_elem->next = NULL ;
586 l_elem->prev = l0_tail ;
587 l0_tail->next = l_elem ;
588 l0_tail = l_elem ;
589 }
590 }
591 }
592 }
593 } else {
594 vptr v, v1;
595 v = bsearch_vector(t->n.vec, tstart - t->shift) ;
596 for(v1 = v; v1; v1 = v1->next) {
597 if (v1->time <= tend) {
598 llist_u llp; llp.p = v1;
599 l_elem = llist_new(llp, LL_VOID_P, -1) ;
600 l0_head = llist_append(l0_head, l_elem, &l0_tail) ;
601 if(!l0_tail) l0_tail = l0_head ;
602 }
603 }
604 }
605 lp = (start_time < end_time) ? l0_head : l0_tail ;
606 /* now create a linked list of time,value.. */
607 while (lp && (nelem++ < max_elements)) {
608 llist_u llp; llp.tt = ((t->vector) ? ((vptr)lp->u.p)->time: ((hptr)lp->u.p)->time);
609 l_elem = llist_new(llp, LL_TIMETYPE, -1) ;
610 l1_head = llist_append(l1_head, l_elem, &l1_tail) ;
611 if(!l1_tail) l1_tail = l1_head ;
612 if(t->vector == 0) {
613 if(!t->n.nd->extvals) { /* really single bit */
614 switch(((hptr)lp->u.p)->v.h_val) {
615 case '0':
616 case AN_0: llp.str = "0"; l_elem = llist_new(llp, LL_STR, -1) ; break ;
617
618 case '1':
619 case AN_1: llp.str = "1"; l_elem = llist_new(llp, LL_STR, -1) ; break ;
620
621 case 'x':
622 case 'X':
623 case AN_X: llp.str = "x"; l_elem = llist_new(llp, LL_STR, -1) ; break ;
624
625 case 'z':
626 case 'Z':
627 case AN_Z: llp.str = "z"; l_elem = llist_new(llp, LL_STR, -1) ; break ;
628
629 case 'h':
630 case 'H':
631 case AN_H: llp.str = "h"; l_elem = llist_new(llp, LL_STR, -1) ; break ; /* added for GHW... */
632
633 case 'u':
634 case 'U':
635 case AN_U: llp.str = "u"; l_elem = llist_new(llp, LL_STR, -1) ; break ;
636
637 case 'w':
638 case 'W':
639 case AN_W: llp.str = "w"; l_elem = llist_new(llp, LL_STR, -1) ; break ;
640
641 case 'l':
642 case 'L':
643 case AN_L: llp.str = "l"; l_elem = llist_new(llp, LL_STR, -1) ; break ;
644
645 case '-':
646 case AN_DASH: llp.str = "-"; l_elem = llist_new(llp, LL_STR, -1) ; break ;
647
648 default: llp.str = "?"; l_elem = llist_new(llp, LL_STR, -1) ; break ; /* ...added for GHW */
649 }
650 } else { /* this is still an array */
651 h_ptr = (hptr)lp->u.p ;
652 if(h_ptr->flags&HIST_REAL) {
653 if(!(h_ptr->flags&HIST_STRING)) {
654 #ifdef WAVE_HAS_H_DOUBLE
655 s=convert_ascii_real(t, &h_ptr->v.h_double);
656 #else
657 s=convert_ascii_real(t, (double *)h_ptr->v.h_vector);
658 #endif
659 } else {
660 s=convert_ascii_string((char *)h_ptr->v.h_vector);
661 }
662 } else {
663 s=convert_ascii_vec(t,h_ptr->v.h_vector);
664 }
665 if(s) {
666 sprintf(s1,"%s%s", signal_value_prefix(t->flags), s) ;
667 llp.str = s1;
668 l_elem = llist_new(llp, LL_STR, -1) ;
669 } else {
670 l1_head = llist_remove_last(l1_head, &l1_tail, LL_INT, NULL) ;
671 }
672 }
673 } else {
674 sprintf(s1, "%s%s", signal_value_prefix(t->flags),
675 convert_ascii(t, (vptr)lp->u.p)) ;
676 llp.str = s1 ;
677 l_elem = llist_new(llp, LL_STR, -1) ;
678 }
679 l1_head = llist_append(l1_head, l_elem, &l1_tail) ;
680 lp = (start_time < end_time) ? lp->next : lp->prev ;
681 }
682 llist_free(l0_head, LL_VOID_P, NULL) ;
683 }
684
685 if(t_created)
686 {
687 FreeTrace(t_created);
688 }
689
690 return l1_head ;
691 }
692