/************************************************* lxt_init - Open lxt file and enable collection ************************************************/ static void lxt_init() { char* filename; if( lxt.inited ) { tf_error( "recording has alreay begun" ); tf_dofinish(); return; } if( lxt.filename ) { filename = lxt.filename; } else if( lxt.design ) { filename = (char*)malloc( strlen(lxt.design)+4+1 ); if( !filename ) { tf_error( "could not allocate memory" ); tf_dofinish(); return; } sprintf( filename, "%s.lxt", lxt.design ); lxt.filename = filename; } else { char* top = acc_fetch_name( acc_next_topmod(null) ); filename = (char*)malloc( strlen(top)+3+1 ); sprintf( filename, "%s.lxt", top ); lxt.filename = filename; } lxt.t = lt_init( filename ); #if DEBUG io_printf( "lxt_init: %p\n", lxt.t ); #endif if( !lxt.t ) { tf_error( "could not create file '%s'", filename ); tf_dofinish(); return; } lt_set_clock_compress( lxt.t ); if( lxt.compress ) { // lt_set_chg_compress( lxt.t ); } lxt.inited = 1; lxt.enabled = 1; lxt.updateList = 0; lxt.eventList = 0; lxt.hunk = 0; lt_set_initial_value( lxt.t, 'x' ); lt_symbol_bracket_stripping( lxt.t, 1 ); lt_set_timescale( lxt.t, acc_fetch_precision() ); lxt_timemarker(); }
void lxt_restart(void) { if (trace == NULL) return; lt_set_timescale(trace, -15); lt_symbol_bracket_stripping(trace, 0); lt_set_clock_compress(trace); const int ndecls = tree_decls(lxt_top); for (int i = 0; i < ndecls; i++) { tree_t d = tree_decl(lxt_top, i); if (tree_kind(d) != T_SIGNAL_DECL) continue; else if (!wave_should_dump(d)) continue; type_t type = tree_type(d); int rows, msb, lsb; if (type_is_array(type)) { rows = type_dims(type) - 1; if ((rows > 0) || type_is_array(type_elem(type))) { warn_at(tree_loc(d), "cannot emit arrays of greater than one " "dimension or arrays of arrays in LXT yet"); continue; } range_t r = type_dim(type, 0); msb = assume_int(r.left); lsb = assume_int(r.right); } else { rows = 0; msb = lsb = -1; } lxt_data_t *data = xmalloc(sizeof(lxt_data_t)); memset(data, '\0', sizeof(lxt_data_t)); int flags = 0; if (type_is_array(type)) { // Only arrays of CHARACTER, BIT, STD_ULOGIC are supported type_t elem = type_base_recur(type_elem(type)); if ((type_kind(elem) != T_ENUM) || !lxt_can_fmt_enum_chars(elem, data, &flags)) { warn_at(tree_loc(d), "cannot represent arrays of type %s " "in LXT format", type_pp(elem)); free(data); continue; } data->dir = type_dim(type, 0).kind; } else { type_t base = type_base_recur(type); switch (type_kind(base)) { case T_INTEGER: data->fmt = lxt_fmt_int; flags = LT_SYM_F_INTEGER; break; case T_ENUM: if (!lxt_can_fmt_enum_chars(base, data, &flags)) { data->fmt = lxt_fmt_enum; flags = LT_SYM_F_STRING; } break; default: warn_at(tree_loc(d), "cannot represent type %s in LXT format", type_pp(type)); free(data); continue; } } char *name = lxt_fmt_name(d); data->sym = lt_symbol_add(trace, name, rows, msb, lsb, flags); free(name); tree_add_attr_ptr(d, lxt_data_i, data); watch_t *w = rt_set_event_cb(d, lxt_event_cb, data, true); (*data->fmt)(d, w, data); } last_time = (lxttime_t)-1; }
/* * mainline */ int save_nodes_to_export_generic(FILE *trans_file, Trptr trans_head, const char *fname, int export_typ) { Trptr t = trans_head ? trans_head : GLOBALS->traces.first; int nodecnt = 0; vcdsav_Tree *vt = NULL; vcdsav_Tree **hp_clone = GLOBALS->hp_vcd_saver_c_1; nptr n; /* ExtNode *e; */ /* int msi, lsi; */ int i; TimeType prevtime = LLDescriptor(-1); time_t walltime; struct strace *st = NULL; int strace_append = 0; int max_len = 1; char *row_data = NULL; struct lt_trace *lt = NULL; int lxt = (export_typ == WAVE_EXPORT_LXT); int is_trans = (export_typ == WAVE_EXPORT_TRANS); if(export_typ == WAVE_EXPORT_TIM) { return(do_timfile_save(fname)); } errno = 0; if(lxt) { lt = lt_init(fname); if(!lt) { return(VCDSAV_FILE_ERROR); } } else { if(export_typ != WAVE_EXPORT_TRANS) { GLOBALS->f_vcd_saver_c_1 = fopen(fname, "wb"); } else { if(!trans_head) /* scan-build : is programming error to get here */ { return(VCDSAV_FILE_ERROR); } GLOBALS->f_vcd_saver_c_1 = trans_file; } if(!GLOBALS->f_vcd_saver_c_1) { return(VCDSAV_FILE_ERROR); } } while(t) { if(!t->vector) { if(t->n.nd) { n = t->n.nd; if(n->expansion) n = n->expansion->parent; vt = vcdsav_splay(n, vt); if(!vt || vt->item != n) { unsigned char flags = 0; if(n->head.next) if(n->head.next->next) { flags = n->head.next->next->flags; } vt = vcdsav_insert(n, vt, ++nodecnt, flags, &n->head); } } } else { bvptr b = t->n.vec; if(b) { bptr bt = b->bits; if(bt) { for(i=0;i<bt->nnbits;i++) { if(bt->nodes[i]) { n = bt->nodes[i]; if(n->expansion) n = n->expansion->parent; vt = vcdsav_splay(n, vt); if(!vt || vt->item != n) { unsigned char flags = 0; if(n->head.next) if(n->head.next->next) { flags = n->head.next->next->flags; } vt = vcdsav_insert(n, vt, ++nodecnt, flags, &n->head); } } } } } } if(export_typ == WAVE_EXPORT_TRANS) { break; } if(!strace_append) { t=t->t_next; if(t) continue; } else { st = st->next; t = st ? st->trace : NULL; if(t) { continue; } else { swap_strace_contexts(); } } strace_concat: GLOBALS->strace_ctx = &GLOBALS->strace_windows[GLOBALS->strace_current_window = strace_append]; strace_append++; if(strace_append == WAVE_NUM_STRACE_WINDOWS) break; if(!GLOBALS->strace_ctx->shadow_straces) { goto strace_concat; } swap_strace_contexts(); st = GLOBALS->strace_ctx->straces; t = st ? st->trace : NULL; if(!t) {swap_strace_contexts(); goto strace_concat; } } if(!nodecnt) return(VCDSAV_EMPTY); /* header */ if(lxt) { int dim; lt_set_chg_compress(lt); lt_set_clock_compress(lt); lt_set_initial_value(lt, 'x'); lt_set_time64(lt, 0); lt_symbol_bracket_stripping(lt, 1); switch(GLOBALS->time_dimension) { case 'm': dim = -3; break; case 'u': dim = -6; break; case 'n': dim = -9; break; case 'p': dim = -12; break; case 'f': dim = -15; break; default: dim = 0; break; } lt_set_timescale(lt, dim); } else { if(export_typ != WAVE_EXPORT_TRANS) { time(&walltime); w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$date\n"); w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "\t%s",asctime(localtime(&walltime))); w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$end\n"); w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$version\n\t"WAVE_VERSION_INFO"\n$end\n"); w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$timescale\n\t%d%c%s\n$end\n", (int)GLOBALS->time_scale, GLOBALS->time_dimension, (GLOBALS->time_dimension=='s') ? "" : "s"); if(GLOBALS->global_time_offset) { w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$timezero\n\t"TTFormat"\n$end\n",GLOBALS->global_time_offset); } } else { w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$comment data_start %p $end\n", (void *)trans_head); /* arbitrary hex identifier */ w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$comment name %s $end\n", trans_head->name ? trans_head->name : "UNKNOWN"); w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$timescale %d%c%s $end\n", (int)GLOBALS->time_scale, GLOBALS->time_dimension, (GLOBALS->time_dimension=='s') ? "" : "s"); if(GLOBALS->global_time_offset) { w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$timezero "TTFormat" $end\n",GLOBALS->global_time_offset); } w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$comment min_time "TTFormat" $end\n", GLOBALS->min_time / GLOBALS->time_scale); w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$comment max_time "TTFormat" $end\n", GLOBALS->max_time / GLOBALS->time_scale); } } if(export_typ == WAVE_EXPORT_TRANS) { w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$comment max_seqn %d $end\n", nodecnt); if(t && t->transaction_args) { w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$comment args \"%s\" $end\n", t->transaction_args); } } /* write out netnames here ... */ hp_clone = GLOBALS->hp_vcd_saver_c_1 = calloc_2(nodecnt, sizeof(vcdsav_Tree *)); recurse_build(vt, &hp_clone); for(i=0;i<nodecnt;i++) { int was_packed = HIER_DEPACK_STATIC; char *hname = hier_decompress_flagged(GLOBALS->hp_vcd_saver_c_1[i]->item->nname, &was_packed); char *netname = lxt ? hname : output_hier(is_trans, hname); if(export_typ == WAVE_EXPORT_TRANS) { w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$comment seqn %d %s $end\n", GLOBALS->hp_vcd_saver_c_1[i]->val, hname); } if(GLOBALS->hp_vcd_saver_c_1[i]->flags & (HIST_REAL|HIST_STRING)) { if(lxt) { GLOBALS->hp_vcd_saver_c_1[i]->handle.p = lt_symbol_add(lt, netname, 0, 0, 0, GLOBALS->hp_vcd_saver_c_1[i]->flags & HIST_STRING ? LT_SYM_F_STRING : LT_SYM_F_DOUBLE); } else { const char *typ = (GLOBALS->hp_vcd_saver_c_1[i]->flags & HIST_STRING) ? "string" : "real"; int tlen = (GLOBALS->hp_vcd_saver_c_1[i]->flags & HIST_STRING) ? 0 : 1; w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$var %s %d %s %s $end\n", typ, tlen, vcdid(GLOBALS->hp_vcd_saver_c_1[i]->val, export_typ), netname); } } else { int msi = -1, lsi = -1; if(GLOBALS->hp_vcd_saver_c_1[i]->item->extvals) { msi = GLOBALS->hp_vcd_saver_c_1[i]->item->msi; lsi = GLOBALS->hp_vcd_saver_c_1[i]->item->lsi; } if(msi==lsi) { if(lxt) { int strand_idx = strand_pnt(netname); if(strand_idx >= 0) { msi = lsi = atoi(netname + strand_idx + 1); } GLOBALS->hp_vcd_saver_c_1[i]->handle.p = lt_symbol_add(lt, netname, 0, msi, lsi, LT_SYM_F_BITS); } else { w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$var wire 1 %s %s $end\n", vcdid(GLOBALS->hp_vcd_saver_c_1[i]->val, export_typ), netname); } } else { int len = (msi < lsi) ? (lsi - msi + 1) : (msi - lsi + 1); if(lxt) { GLOBALS->hp_vcd_saver_c_1[i]->handle.p = lt_symbol_add(lt, netname, 0, msi, lsi, LT_SYM_F_BITS); } else { w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$var wire %d %s %s $end\n", len, vcdid(GLOBALS->hp_vcd_saver_c_1[i]->val, export_typ), netname); } GLOBALS->hp_vcd_saver_c_1[i]->len = len; if(len > max_len) max_len = len; } } /* if(was_packed) { free_2(hname); } ...not needed for HIER_DEPACK_STATIC */ } row_data = malloc_2(max_len + 1); if(!lxt) { output_hier(is_trans, ""); free_hier(); w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$enddefinitions $end\n"); w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$dumpvars\n"); } /* value changes */ for(i=(nodecnt/2-1);i>0;i--) /* build nodes into having heap property */ { heapify(i,nodecnt); } for(;;) { heapify(0, nodecnt); if(!GLOBALS->hp_vcd_saver_c_1[0]->hist) break; if(GLOBALS->hp_vcd_saver_c_1[0]->hist->time > GLOBALS->max_time) break; if((GLOBALS->hp_vcd_saver_c_1[0]->hist->time != prevtime) && (GLOBALS->hp_vcd_saver_c_1[0]->hist->time >= LLDescriptor(0))) { TimeType tnorm = GLOBALS->hp_vcd_saver_c_1[0]->hist->time; if(GLOBALS->time_scale != 1) { tnorm /= GLOBALS->time_scale; } if(lxt) { lt_set_time64(lt, tnorm); } else { w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "#"TTFormat"\n", tnorm); } prevtime = GLOBALS->hp_vcd_saver_c_1[0]->hist->time; } if(GLOBALS->hp_vcd_saver_c_1[0]->hist->time >= LLDescriptor(0)) { if(GLOBALS->hp_vcd_saver_c_1[0]->flags & (HIST_REAL|HIST_STRING)) { if(GLOBALS->hp_vcd_saver_c_1[0]->flags & HIST_STRING) { char *vec = GLOBALS->hp_vcd_saver_c_1[0]->hist->v.h_vector ? GLOBALS->hp_vcd_saver_c_1[0]->hist->v.h_vector : "UNDEF"; if(lxt) { lt_emit_value_string(lt, GLOBALS->hp_vcd_saver_c_1[0]->handle.p, 0, vec); } else { int vec_slen = strlen(vec); char *vec_escaped = malloc_2(vec_slen*4 + 1); /* worst case */ int vlen = fstUtilityBinToEsc((unsigned char *)vec_escaped, (unsigned char *)vec, vec_slen); vec_escaped[vlen] = 0; if(vlen) { w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "s%s %s\n", vec_escaped, vcdid(GLOBALS->hp_vcd_saver_c_1[0]->val, export_typ)); } else { w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "s\\000 %s\n", vcdid(GLOBALS->hp_vcd_saver_c_1[0]->val, export_typ)); } free_2(vec_escaped); } } else { #ifdef WAVE_HAS_H_DOUBLE double *d = &GLOBALS->hp_vcd_saver_c_1[0]->hist->v.h_double; #else double *d = (double *)GLOBALS->hp_vcd_saver_c_1[0]->hist->v.h_vector; #endif double value; if(!d) { sscanf("NaN", "%lg", &value); } else { value = *d; } if(lxt) { lt_emit_value_double(lt, GLOBALS->hp_vcd_saver_c_1[0]->handle.p, 0, value); } else { w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "r%.16g %s\n", value, vcdid(GLOBALS->hp_vcd_saver_c_1[0]->val, export_typ)); } } } else if(GLOBALS->hp_vcd_saver_c_1[0]->len) { if(GLOBALS->hp_vcd_saver_c_1[0]->hist->v.h_vector) { for(i=0;i<GLOBALS->hp_vcd_saver_c_1[0]->len;i++) { row_data[i] = analyzer_demang(lxt, GLOBALS->hp_vcd_saver_c_1[0]->hist->v.h_vector[i]); } } else { for(i=0;i<GLOBALS->hp_vcd_saver_c_1[0]->len;i++) { row_data[i] = 'x'; } } row_data[i] = 0; if(lxt) { lt_emit_value_bit_string(lt, GLOBALS->hp_vcd_saver_c_1[0]->handle.p, 0, row_data); } else { w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "b%s %s\n", vcd_truncate_bitvec(row_data), vcdid(GLOBALS->hp_vcd_saver_c_1[0]->val, export_typ)); } } else { if(lxt) { row_data[0] = analyzer_demang(lxt, GLOBALS->hp_vcd_saver_c_1[0]->hist->v.h_val); row_data[1] = 0; lt_emit_value_bit_string(lt, GLOBALS->hp_vcd_saver_c_1[0]->handle.p, 0, row_data); } else { w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "%c%s\n", analyzer_demang(lxt, GLOBALS->hp_vcd_saver_c_1[0]->hist->v.h_val), vcdid(GLOBALS->hp_vcd_saver_c_1[0]->val, export_typ)); } } } GLOBALS->hp_vcd_saver_c_1[0]->hist = GLOBALS->hp_vcd_saver_c_1[0]->hist->next; } if(prevtime < GLOBALS->max_time) { if(lxt) { lt_set_time64(lt, GLOBALS->max_time / GLOBALS->time_scale); } else { w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "#"TTFormat"\n", GLOBALS->max_time / GLOBALS->time_scale); } } for(i=0;i<nodecnt;i++) { free_2(GLOBALS->hp_vcd_saver_c_1[i]); } free_2(GLOBALS->hp_vcd_saver_c_1); GLOBALS->hp_vcd_saver_c_1 = NULL; free_2(row_data); row_data = NULL; if(lxt) { lt_close(lt); lt = NULL; } else { if(export_typ != WAVE_EXPORT_TRANS) { fclose(GLOBALS->f_vcd_saver_c_1); } else { w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$comment data_end %p $end\n", (void *)trans_head); /* arbitrary hex identifier */ #if !defined _MSC_VER && !defined __MINGW32__ fflush(GLOBALS->f_vcd_saver_c_1); #endif } GLOBALS->f_vcd_saver_c_1 = NULL; } return(VCDSAV_OK); }
/************************************************* lxt_incinit - close current file and open a new one maintaining the same trace info ************************************************/ static void lxt_incinit() { char* filename; char* dot; info_p info; #if DEBUG io_printf( "lxt_incinit: %p\n", lxt.t ); #endif /* * pinch off old file */ lxt_timemarker(); lt_close( lxt.t ); /* * create new filename */ lxt.hunk++; filename = (char*)malloc( strlen(lxt.filename)+10+1 ); dot = rindex( lxt.filename, '.' ); *dot = 0; if( lxt.hunk > 1 ) { dot = rindex( lxt.filename, '-' ); *dot = 0; } sprintf( filename, "%s-%d.lxt", lxt.filename, lxt.hunk ); free( lxt.filename ); lxt.filename = filename; /* * open new wave file */ lxt.t = lt_init( filename ); if( !lxt.t ) { tf_error( "could not create file '%s'", filename ); tf_dofinish(); return; } lt_set_clock_compress( lxt.t ); if( lxt.compress ) { // lt_set_chg_compress( lxt.t ); } lxt.updateList = 0; lxt.eventList = 0; lt_set_initial_value( lxt.t, 'x' ); lt_symbol_bracket_stripping( lxt.t, 1 ); lt_set_timescale( lxt.t, acc_fetch_precision() ); lxt_timemarker(); /* * add existing objects to new file */ info = lxt.objectList; while( info ) { int flags; int msb; int lsb; if( info->real ) { flags = LT_SYM_F_DOUBLE; } else { flags = LT_SYM_F_BITS; } if( info->real ) { info->symbol = lt_symbol_add( lxt.t, info->name, 0, 0, 0, flags ); } else if( info->event ) { info->symbol = lt_symbol_add( lxt.t, info->name, 0, 0, 0, flags ); } else { acc_fetch_range( info->object, &msb, &lsb ); info->symbol = lt_symbol_add( lxt.t, info->name, 0, msb, lsb, flags ); } info = info->next; } if( lxt.compress ) { lt_set_no_interlace( lxt.t ); } lxt_dump( lxt.objectList, 1 ); }