📄 sc_vcd_trace.cpp
字号:
{ std::string file_name = name ; file_name += ".vcd"; fp = fopen(file_name.c_str(), "w"); if (!fp) { std::string msg = std::string("Cannot write trace file '") + file_name + "'"; ::std::cerr << "FATAL: " << msg << "\n"; exit(1); } trace_delta_cycles = false; // Make this the default initialized = false; vcd_name_index = 0; // default time step is the time resolution timescale_unit = sc_get_time_resolution().to_seconds(); timescale_set_by_user = false;}void vcd_trace_file::initialize(){ char buf[2000]; //date: time_t long_time; time(&long_time); struct tm* p_tm; p_tm = localtime(&long_time); strftime(buf, 199, "%b %d, %Y %H:%M:%S", p_tm); std::fprintf(fp, "$date\n %s\n$end\n\n", buf); //version: std::fprintf(fp, "$version\n %s\n$end\n\n", sc_version()); //timescale: static struct SC_TIMESCALE_TO_TEXT { double unit; const char* text; } timescale_to_text [] = { { sc_time(1, SC_FS).to_seconds(), "1 fs" }, { sc_time(10, SC_FS).to_seconds(), "10 fs" }, { sc_time(100, SC_FS).to_seconds(),"100 fs" }, { sc_time(1, SC_PS).to_seconds(), "1 ps" }, { sc_time(10, SC_PS).to_seconds(), "10 ps" }, { sc_time(100, SC_PS).to_seconds(),"100 ps" }, { sc_time(1, SC_NS).to_seconds(), "1 ns" }, { sc_time(10, SC_NS).to_seconds(), "10 ns" }, { sc_time(100, SC_NS).to_seconds(),"100 ns" }, { sc_time(1, SC_US).to_seconds(), "1 us" }, { sc_time(10, SC_US).to_seconds(), "10 us" }, { sc_time(100, SC_US).to_seconds(),"100 us" }, { sc_time(1, SC_MS).to_seconds(), "1 ms" }, { sc_time(10, SC_MS).to_seconds(), "10 ms" }, { sc_time(100, SC_MS).to_seconds(),"100 ms" }, { sc_time(1, SC_SEC).to_seconds(), "1 sec" }, { sc_time(10, SC_SEC).to_seconds(), "10 sec" }, { sc_time(100, SC_SEC).to_seconds(),"100 sec" } }; static int timescale_to_text_n = sizeof(timescale_to_text)/sizeof(SC_TIMESCALE_TO_TEXT); for ( int time_i = 0; time_i < timescale_to_text_n; time_i++ ) { if (timescale_unit == timescale_to_text[time_i].unit) { std::fprintf(fp,"$timescale\n %s\n$end\n\n", timescale_to_text[time_i].text); break; } } running_regression = ( getenv( "SYSTEMC_REGRESSION" ) != NULL ); // Don't print message if running regression if( ! timescale_set_by_user && ! running_regression ) { ::std::cout << "WARNING: Default time step is used for VCD tracing." << ::std::endl; } // Create a dummy scope std::fputs("$scope module SystemC $end\n", fp); //variable definitions: int i; for (i = 0; i < (int)traces.size(); i++) { vcd_trace* t = traces[i]; t->set_width(); // needed for all vectors t->print_variable_declaration_line(fp); } std::fputs("$upscope $end\n", fp); std::fputs("$enddefinitions $end\n\n", fp); // double inittime = sc_simulation_time(); double inittime = sc_time_stamp().to_seconds(); std::sprintf(buf, "All initial values are dumped below at time " "%g sec = %g timescale units.", inittime, inittime/timescale_unit ); write_comment(buf); double_to_special_int64(inittime/timescale_unit, &previous_time_units_high, &previous_time_units_low ); std::fputs("$dumpvars\n",fp); for (i = 0; i < (int)traces.size(); i++) { vcd_trace* t = traces[i]; t->write(fp); std::fputc('\n', fp); } std::fputs("$end\n\n", fp);}// ----------------------------------------------------------------------------#define DEFN_TRACE_METHOD(tp) \void \vcd_trace_file::trace(const tp& object_, const std::string& name_) \{ \ if( initialized ) { \ put_error_message( \ "No traces can be added once simulation has started.\n" \ "To add traces, create a new vcd trace file.", false ); \ } \ std::string temp_vcd_name; \ create_vcd_name( &temp_vcd_name ); \ traces.push_back( new vcd_ ## tp ## _trace( object_, \ name_, \ temp_vcd_name ) ); \}DEFN_TRACE_METHOD(bool)DEFN_TRACE_METHOD(float)DEFN_TRACE_METHOD(double)#undef DEFN_TRACE_METHOD#define DEFN_TRACE_METHOD(tp) \void \vcd_trace_file::trace(const sc_dt::tp& object_, const std::string& name_)\{ \ if( initialized ) { \ put_error_message( \ "No traces can be added once simulation has started.\n" \ "To add traces, create a new vcd trace file.", false ); \ } \ std::string temp_vcd_name; \ create_vcd_name( &temp_vcd_name ); \ traces.push_back( new vcd_ ## tp ## _trace( object_, \ name_, \ temp_vcd_name ) ); \}DEFN_TRACE_METHOD(sc_bit)DEFN_TRACE_METHOD(sc_logic)DEFN_TRACE_METHOD(sc_signed)DEFN_TRACE_METHOD(sc_unsigned)DEFN_TRACE_METHOD(sc_int_base)DEFN_TRACE_METHOD(sc_uint_base)DEFN_TRACE_METHOD(sc_fxval)DEFN_TRACE_METHOD(sc_fxval_fast)DEFN_TRACE_METHOD(sc_fxnum)DEFN_TRACE_METHOD(sc_fxnum_fast)#undef DEFN_TRACE_METHOD#define DEFN_TRACE_METHOD_SIGNED(tp) \void \vcd_trace_file::trace( const tp& object_, \ const std::string& name_, \ int width_ ) \{ \ if( initialized ) { \ put_error_message( \ "No traces can be added once simulation has started.\n" \ "To add traces, create a new vcd trace file.", false ); \ } \ std::string temp_vcd_name; \ create_vcd_name( &temp_vcd_name ); \ traces.push_back( new vcd_signed_ ## tp ## _trace( object_, \ name_, \ temp_vcd_name, \ width_ ) ); \}#define DEFN_TRACE_METHOD_UNSIGNED(tp) \void \vcd_trace_file::trace( const unsigned tp& object_, \ const std::string& name_, \ int width_ ) \{ \ if( initialized ) { \ put_error_message( \ "No traces can be added once simulation has started.\n" \ "To add traces, create a new vcd trace file.", false ); \ } \ std::string temp_vcd_name; \ create_vcd_name( &temp_vcd_name ); \ traces.push_back( new vcd_unsigned_ ## tp ## _trace( object_, \ name_, \ temp_vcd_name, \ width_ ) ); \}DEFN_TRACE_METHOD_SIGNED(char)DEFN_TRACE_METHOD_SIGNED(short)DEFN_TRACE_METHOD_SIGNED(int)DEFN_TRACE_METHOD_SIGNED(long)DEFN_TRACE_METHOD_UNSIGNED(char)DEFN_TRACE_METHOD_UNSIGNED(short)DEFN_TRACE_METHOD_UNSIGNED(int)DEFN_TRACE_METHOD_UNSIGNED(long)#undef DEFN_TRACE_METHOD_SIGNED#undef DEFN_TRACE_METHOD_UNSIGNED#define DEFN_TRACE_METHOD_LONG_LONG(tp) \void \vcd_trace_file::trace( const sc_dt::tp& object_, \ const std::string& name_, \ int width_ ) \{ \ if( initialized ) { \ put_error_message( \ "No traces can be added once simulation has started.\n" \ "To add traces, create a new vcd trace file.", false ); \ } \ std::string temp_vcd_name; \ create_vcd_name( &temp_vcd_name ); \ traces.push_back( new vcd_ ## tp ## _trace( object_, \ name_, \ temp_vcd_name, \ width_ ) ); \}DEFN_TRACE_METHOD_LONG_LONG(int64)DEFN_TRACE_METHOD_LONG_LONG(uint64)#undef DEFN_TRACE_METHOD_LONG_LONGvoidvcd_trace_file::trace( const unsigned& object_, const std::string& name_, const char** enum_literals_ ){ if( initialized ) { put_error_message( "No traces can be added once simulation has started.\n" "To add traces, create a new vcd trace file.", false ); } std::string temp_vcd_name; create_vcd_name( &temp_vcd_name ); traces.push_back( new vcd_enum_trace( object_, name_, temp_vcd_name, enum_literals_ ) );}voidvcd_trace_file::write_comment(const std::string& comment){ //no newline in comments allowed, as some viewers may crash std::fputs("$comment\n", fp); std::fputs(comment.c_str(), fp); std::fputs("\n$end\n\n", fp);}voidvcd_trace_file::delta_cycles(bool flag){ trace_delta_cycles = flag;}voidvcd_trace_file::cycle(bool this_is_a_delta_cycle){ char message[4000]; unsigned this_time_units_high, this_time_units_low; // Just to make g++ shut up in the optimized mode this_time_units_high = this_time_units_low = 0; // Trace delta cycles only when enabled if (!trace_delta_cycles && this_is_a_delta_cycle) return; // Check for initialization if (!initialized) { initialize(); initialized = true; return; }; double now_units = sc_time_stamp().to_seconds() / timescale_unit; unsigned now_units_high, now_units_low; double_to_special_int64(now_units, &now_units_high, &now_units_low ); bool now_later_than_previous_time = false; if( now_units_low > previous_time_units_low && now_units_high == previous_time_units_high || now_units_high > previous_time_units_high){ now_later_than_previous_time = true; } bool now_equals_previous_time = false; if(now_later_than_previous_time){ this_time_units_high = now_units_high; this_time_units_low = now_units_low; } else { if( now_units_low == previous_time_units_low && now_units_high == previous_time_units_high){ now_equals_previous_time = true; this_time_units_high = now_units_high; this_time_units_low = now_units_low; } } // Since VCD does not understand 0 time progression, we have to fake // delta cycles with progressing time by one unit if(this_is_a_delta_cycle){ this_time_units_high = previous_time_units_high; this_time_units_low = previous_time_units_low + 1; if(this_time_units_low == 1000000000){ this_time_units_high++; this_time_units_low=0; } static bool warned = false; if(!warned){ ::std::cout << "Note: VCD delta cycling with pseudo timesteps (1 unit) " "is performed.\n" << ::std::endl; warned = true; } } // Not a delta cycle and time has not progressed if( ! this_is_a_delta_cycle && now_equals_previous_time && ( now_units_high != 0 || now_units_low != 0 ) ) { // Don't print the message at time zero static bool warned = false; if( ! warned && ! running_regression ) { std::sprintf(message, "Multiple cycles found with same (%u) time units count.\n" "Waveform viewers will only show the states of the last one.\n" "Use ((vcd_trace_file*)vcdfile)->sc_set_vcd_time_unit(int exponent10_seconds)\n" "to increase time resolution.", now_units_low ); put_error_message(message, true); warned = true; } } // Not a delta cycle and time has gone backward // This will happen with large number of delta cycles between two real // advances of time if(!this_is_a_delta_cycle && !now_equals_previous_time && !now_later_than_previous_time){ static bool warned = false; if(!warned){ std::sprintf(message, "Cycle found with falling (%u -> %u) time units count.\n" "This can occur when delta cycling is activated.\n" "Cycles with falling time are not shown.\n" "Use ((vcd_trace_file*)vcdfile)->sc_set_vcd_time_unit(int exponent10_seconds)\n" "to increase time resolution.", previous_time_units_low, now_units_low); put_error_message(message, true); warned = true; } // Note that we don't set this_time_units_high/low to any value only // in this case because we are not going to do any tracing. In the // optimized mode, the compiler complains because of this. Therefore, // we include the lines at the very beginning of this function to make // the compiler shut up. return; } // Now do the actual printing bool time_printed = false; vcd_trace* const* const l_traces = &traces[0]; for (int i = 0; i < (int)traces.size(); i++) { vcd_trace* t = l_traces[i]; if(t->changed()){ if(time_printed == false){ char buf[200]; if(this_time_units_high){ std::sprintf(buf, "#%u%09u", this_time_units_high, this_time_units_low); } else{ std::sprintf(buf, "#%u", this_time_units_low); } std::fputs(buf, fp); std::fputc('\n', fp); time_printed = true; } // Write the variable t->write(fp); std::fputc('\n', fp); } } // Put another newline after all values are printed if(time_printed) std::fputc('\n', fp); if(time_printed){ // We update previous_time_units only when we print time because // this field stores the previous time that was printed, not the // previous time this function was called previous_time_units_high = this_time_units_high; previous_time_units_low = this_time_units_low; }}voidvcd_trace_file::create_vcd_name(std::string* p_destination){ const char first_type_used = 'a'; const int used_types_count = 'z' - 'a' + 1; int result; char char4 = (char)(vcd_name_index % used_types_count); result = vcd_name_index / used_types_count; char char3 = (char)(result % used_types_count); result = result / used_types_count; char char2 = (char)(result % used_types_count); char buf[20]; std::sprintf(buf, "%c%c%c", char2 + first_type_used, char3 + first_type_used, char4 + first_type_used); *p_destination = buf; vcd_name_index++;}// same as abovestd::stringvcd_trace_file::obtain_name(){ const char first_type_used = 'a'; const int used_types_count = 'z' - 'a' + 1; int result; char char4 = (char)(vcd_name_index % used_types_count); result = vcd_name_index / used_types_count; char char3 = (char)(result % used_types_count); result = result / used_types_count; char char2 = (char)(result % used_types_count); char buf[20]; std::sprintf(buf, "%c%c%c", char2 + first_type_used, char3 + first_type_used, char4 + first_type_used); vcd_name_index++; return std::string(buf);}vcd_trace_file::~vcd_trace_file(){ int i; for (i = 0; i < (int)traces.size(); i++) { vcd_trace* t = traces[i]; delete t; } fclose(fp);}// Functions specific to VCD tracingstatic charmap_sc_logic_state_to_vcd_state(char in_char){ char out_char; switch(in_char){ case 'U': case 'X': case 'W': case 'D': out_char = 'x'; break; case '0': case 'L': out_char = '0'; break; case '1': case 'H': out_char = '1'; break; case 'Z': out_char = 'z'; break; default: out_char = '?'; } return out_char;}staticvoidremove_vcd_name_problems(std::string& name){ char message[4000]; static bool warned = false; bool braces_removed = false; for (unsigned int i = 0; i< name.length(); i++) { if (name[i] == '[') { name[i] = '('; braces_removed = true; } else if (name[i] == ']') { name[i] = ')'; braces_removed = true; } } if(braces_removed && !warned){ std::sprintf(message, "Traced objects found with name containing [], which may be\n" "interpreted by the waveform viewer in unexpected ways.\n" "So the [] is automatically replaced by ()."); put_error_message(message, true); warned = true; }}sc_trace_file*sc_create_vcd_trace_file(const char * name){ sc_trace_file *tf; tf = new vcd_trace_file(name); sc_get_curr_simcontext()->add_trace_file(tf); return tf;}voidsc_close_vcd_trace_file( sc_trace_file* tf ){ vcd_trace_file* vcd_tf = (vcd_trace_file*)tf; delete vcd_tf; }} // namespace sc_core
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -