diff --git a/include/verilated.cpp b/include/verilated.cpp index eba94136c..f8f034fb1 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -244,8 +244,8 @@ Verilated::Serialized::Serialized() { s_errorLimit = 1; s_randReset = 0; s_randSeed = 0; - s_timeunit = -VL_TIME_UNIT; // Initial value until overriden by _Vconfigure - s_timeprecision = -VL_TIME_PRECISION; // Initial value until overriden by _Vconfigure + s_timeunit = VL_TIME_UNIT; // Initial value until overriden by _Vconfigure + s_timeprecision = VL_TIME_PRECISION; // Initial value until overriden by _Vconfigure } Verilated::NonSerialized::NonSerialized() { @@ -2007,14 +2007,13 @@ int VL_TIME_STR_CONVERT(const char* strp) { } static const char* vl_time_str(int scale) { static const char* const names[] - = {"1s", "100ms", "10ms", "1ms", "100us", "10us", "1us", "100ns", - "10ns", "1ns", "100ps", "10ps", "1ps", "100fs", "10fs", "1fs"}; - if (scale < 0) scale = -scale; - if (VL_UNLIKELY(scale > 15)) scale = 0; - return names[scale]; + = {"100s", "10s", "1s", "100ms", "10ms", "1ms", "100us", "10us", "1us", + "100ns", "10ns", "1ns", "100ps", "10ps", "1ps", "100fs", "10fs", "1fs"}; + if (VL_UNLIKELY(scale > 2 || scale < -15)) scale = 0; + return names[2 - scale]; } double vl_time_multiplier(int scale) { - // Return timescale multipler -15 to +15 + // Return timescale multipler -18 to +18 // For speed, this does not check for illegal values static double pow10[] = {1.0, 10.0, @@ -2031,7 +2030,10 @@ double vl_time_multiplier(int scale) { 1000000000000.0, 10000000000000.0, 100000000000000.0, - 1000000000000000.0}; + 1000000000000000.0, + 10000000000000000.0, + 100000000000000000.0, + 1000000000000000000.0}; static double neg10[] = {1.0, 0.1, 0.01, @@ -2047,7 +2049,10 @@ double vl_time_multiplier(int scale) { 0.000000000001, 0.0000000000001, 0.00000000000001, - 0.000000000000001}; + 0.000000000000001, + 0.0000000000000001, + 0.00000000000000001, + 0.000000000000000001}; if (scale < 0) { return neg10[-scale]; } else { diff --git a/include/verilated.h b/include/verilated.h index e06a2e275..9eb804125 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -386,8 +386,8 @@ class Verilated { bool s_assertOn; ///< Assertions are enabled bool s_fatalOnVpiError; ///< Stop on vpi error/unsupported // Slow path - unsigned s_timeunit : 4; ///< Time unit as 0..15 - unsigned s_timeprecision : 4; ///< Time precision as 0..15 + vlsint8_t s_timeunit; ///< Time unit as 0..15 + vlsint8_t s_timeprecision; ///< Time precision as 0..15 int s_errorCount; ///< Number of errors int s_errorLimit; ///< Stop on error number int s_randReset; ///< Random reset: 0=all 0s, 1=all 1s, 2=random diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 011fe47d0..2f5ba6546 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -2308,12 +2308,12 @@ void EmitCImp::emitConfigureImp(AstNodeModule* modp) { puts("if (false && this->__VlSymsp) {} // Prevent unused\n"); if (v3Global.opt.coverage()) { puts(protect("_configure_coverage") + "(vlSymsp, first);\n"); } if (modp->isTop() && !v3Global.rootp()->timeunit().isNone()) { - puts("Verilated::timeunit(" + cvtToStr(v3Global.rootp()->timeunit().negativeInt()) + puts("Verilated::timeunit(" + cvtToStr(v3Global.rootp()->timeunit().powerOfTen()) + ");\n"); } if (modp->isTop() && !v3Global.rootp()->timeprecision().isNone()) { puts("Verilated::timeprecision(" - + cvtToStr(v3Global.rootp()->timeprecision().negativeInt()) + ");\n"); + + cvtToStr(v3Global.rootp()->timeprecision().powerOfTen()) + ");\n"); } puts("}\n"); splitSizeInc(10); diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 807886536..e633a2c1f 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -292,7 +292,7 @@ class EmitCSyms : EmitCBaseVisitor { string type = (nodep->origModName() == "__BEGIN__") ? "SCOPE_OTHER" : "SCOPE_MODULE"; string name = nodep->scopep()->name() + "__DOT__" + nodep->name(); string name_dedot = AstNode::dedotName(name); - int timeunit = m_modp->timeunit().negativeInt(); + int timeunit = m_modp->timeunit().powerOfTen(); m_vpiScopeCandidates.insert( make_pair(name, ScopeData(scopeSymString(name), name_dedot, timeunit, type))); } @@ -305,7 +305,7 @@ class EmitCSyms : EmitCBaseVisitor { if (v3Global.opt.vpi() && !nodep->isTop()) { string name_dedot = AstNode::dedotName(nodep->shortName()); - int timeunit = m_modp->timeunit().negativeInt(); + int timeunit = m_modp->timeunit().powerOfTen(); m_vpiScopeCandidates.insert( make_pair(nodep->name(), ScopeData(scopeSymString(nodep->name()), name_dedot, timeunit, "SCOPE_MODULE"))); @@ -315,7 +315,7 @@ class EmitCSyms : EmitCBaseVisitor { string name = nodep->scopeSymName(); // UINFO(9,"scnameins sp "<name()<<" sp "<scopePrettySymName() // <<" ss"<timeunit().negativeInt() : 0; + int timeunit = m_modp ? m_modp->timeunit().powerOfTen() : 0; if (m_scopeNames.find(name) == m_scopeNames.end()) { m_scopeNames.insert(make_pair( name, ScopeData(name, nodep->scopePrettySymName(), timeunit, "SCOPE_OTHER"))); diff --git a/src/V3Options.cpp b/src/V3Options.cpp index d8de81a1f..f22789acd 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -125,7 +125,7 @@ VTimescale::VTimescale(const string& value, bool& badr) : m_e(VTimescale::NONE) { badr = true; string spaceless = VString::removeWhitespace(value); - for (int i = TS_1S; i < _ENUM_END; ++i) { + for (int i = TS_100S; i < _ENUM_END; ++i) { VTimescale ts(i); if (spaceless == ts.ascii()) { badr = false; diff --git a/src/V3Options.h b/src/V3Options.h index 28082d8a9..7813f236d 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -72,15 +72,15 @@ inline std::ostream& operator<<(std::ostream& os, const VOptionBool& rhs) { class VTimescale { public: enum en { - TS_1S = 0, // clang-format off - TS_100MS = 1, TS_10MS = 2, TS_1MS = 3, - TS_100US = 4, TS_10US = 5, TS_1US = 6, - TS_100NS = 7, TS_10NS = 8, TS_1NS = 9, - TS_100PS = 10, TS_10PS = 11, TS_1PS = 12, - TS_100FS = 13, TS_10FS = 14, TS_1FS = 15, + TS_100S = 0, TS_10S = 1, TS_1S = 2, + TS_100MS = 3, TS_10MS = 4, TS_1MS = 5, + TS_100US = 6, TS_10US = 7, TS_1US = 8, + TS_100NS = 9, TS_10NS = 10, TS_1NS = 11, + TS_100PS = 12, TS_10PS = 13, TS_1PS = 14, + TS_100FS = 15, TS_10FS = 16, TS_1FS = 17, // clang-format on - NONE = 16, + NONE = 18, _ENUM_END }; enum { TS_DEFAULT = TS_1PS }; @@ -93,13 +93,14 @@ public: : m_e(_e) {} explicit inline VTimescale(int _e) : m_e(static_cast(_e)) {} - int negativeInt() { return -static_cast(m_e); } // Construct from string VTimescale(const string& value, bool& badr); VTimescale(double value, bool& badr) { badr = false; // clang-format off - if (value == 1e0) m_e = TS_1S; + if (value == 10e2) m_e = TS_100S; + else if (value == 1e1) m_e = TS_10S; + else if (value == 1e0) m_e = TS_1S; else if (value == 1e-1) m_e = TS_100MS; else if (value == 1e-2) m_e = TS_10MS; else if (value == 1e-3) m_e = TS_1MS; @@ -127,13 +128,14 @@ public: bool allowEmpty = false); const char* ascii() const { static const char* const names[] - = {"1s", "100ms", "10ms", "1ms", "100us", "10us", "1us", "100ns", "10ns", - "1ns", "100ps", "10ps", "1ps", "100fs", "10fs", "1fs", "NONE"}; + = {"100s", "10s", "1s", "100ms", "10ms", "1ms", "100us", "10us", "1us", "100ns", + "10ns", "1ns", "100ps", "10ps", "1ps", "100fs", "10fs", "1fs", "NONE"}; return names[m_e]; } + int powerOfTen() { return 2 - static_cast(m_e); } double multiplier() const { - static double values[] = {1, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, 1e-8, - 1e-9, 1e-10, 1e-11, 1e-12, 1e-13, 1e-14, 1e-15, 0}; + static double values[] = {100, 10, 1, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, + 1e-8, 1e-9, 1e-10, 1e-11, 1e-12, 1e-13, 1e-14, 1e-15, 0}; return values[m_e]; } }; diff --git a/test_regress/t/t_time_sc_bad.out b/test_regress/t/t_time_sc_bad.out index fb65dcdf0..86603162d 100644 --- a/test_regress/t/t_time_sc_bad.out +++ b/test_regress/t/t_time_sc_bad.out @@ -1,2 +1,2 @@ -%Error: SystemC's sc_set_time_resolution is 10^-9, which does not match Verilog timeprecision 10^-12. Suggest use 'sc_set_time_resolution(1ps)', or Verilator '--timescale-override 1ns/1ns' +%Error: SystemC's sc_set_time_resolution is 10^-9, which does not match Verilog timeprecision 10^-12. Suggest use 'sc_set_time_resolution(1s)', or Verilator '--timescale-override 1s/1s' Aborting... diff --git a/test_regress/t/t_time_vpi_100s10ms.out b/test_regress/t/t_time_vpi_100s10ms.out new file mode 100644 index 000000000..73db352ca --- /dev/null +++ b/test_regress/t/t_time_vpi_100s10ms.out @@ -0,0 +1,15 @@ +:: In top.t +Time scale of t is 100s / 10ms +[100000000] time%0d=10000 123%0t=1230000 + dig%0t=0 dig%0d=0 + rdig%0t=543 rdig%0f=0.054321 +[0.000000ns] time%0d=10000 123%0t=12300000000000.000000ns + dig%0t=0.000000ns dig%0d=0 + rdig%0t=5432109876.543210ns rdig%0f=0.054321 +[0.000000ns] stime%0t=0.000000ns stime%0d=10000 stime%0f=10000.000000 +[0.000000ns] rtime%0t=0.000000ns rtime%0d=10000 rtime%0f=10000.000000 +global vpiSimTime = 0,100000000 vpiScaledRealTime = 1e+08 +global vpiTimeUnit = -2 vpiTimePrecision = -2 +top.t vpiSimTime = 0,100000000 vpiScaledRealTime = 10000 +top.t vpiTimeUnit = 2 vpiTimePrecision = -2 +*-* All Finished *-* diff --git a/test_regress/t/t_time_vpi_100s10ms.pl b/test_regress/t/t_time_vpi_100s10ms.pl new file mode 100755 index 000000000..34e5ba90e --- /dev/null +++ b/test_regress/t/t_time_vpi_100s10ms.pl @@ -0,0 +1,30 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator_st => 1); + +top_filename("t/t_time_vpi.v"); + +$Self->{main_time_multiplier} = 100e0 / 10e-6; + +compile( + v_flags2 => ['+define+time_scale_units=100s +define+time_scale_prec=10ms', + 't/t_time_vpi_c.cpp'], + verilator_flags2 => ['--vpi'], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_timescale_parse.v b/test_regress/t/t_timescale_parse.v index 63e5fbb1e..e58bb0741 100644 --- a/test_regress/t/t_timescale_parse.v +++ b/test_regress/t/t_timescale_parse.v @@ -12,38 +12,42 @@ module modname; \ task check; t = 1ns; $write("%m %0t\n", t); endtask \ endmodule +`timescale 100s/1fs +`testmod(sp2) +`timescale 10s/1fs +`testmod(sp1) `timescale 1s/1fs -`testmod(s0) +`testmod(sp0) `timescale 100ms/1fs -`testmod(s1) +`testmod(sm1) `timescale 10ms/1fs -`testmod(s2) +`testmod(sm2) `timescale 1ms/1fs -`testmod(s3) +`testmod(sm3) `timescale 100us/1fs -`testmod(s4) +`testmod(sm4) `timescale 10us/1fs -`testmod(s5) +`testmod(sm5) `timescale 1us/1fs -`testmod(s6) +`testmod(sm6) `timescale 100ns/1fs -`testmod(s7) +`testmod(sm7) `timescale 10ns/1fs -`testmod(s8) +`testmod(sm8) `timescale 1ns/1fs -`testmod(s9) +`testmod(sm9) `timescale 100ps/1fs -`testmod(s10) +`testmod(sm10) `timescale 10ps/1fs -`testmod(s11) +`testmod(sm11) `timescale 1ps/1fs -`testmod(s12) +`testmod(sm12) `timescale 100 fs/1fs -`testmod(s13) +`testmod(sm13) `timescale 10fs/1 fs -`testmod(s14) +`testmod(sm14) `timescale 1 fs / 1 fs // Comment -`testmod(s15) +`testmod(sm15) module r0; @@ -58,43 +62,47 @@ module r1; endmodule module t; - s0 s0(); - s1 s1(); - s2 s2(); - s3 s3(); - s4 s4(); - s5 s5(); - s6 s6(); - s7 s7(); - s8 s8(); - s9 s9(); - s10 s10(); - s11 s11(); - s12 s12(); - s13 s13(); - s14 s14(); - s15 s15(); + sp2 sp2(); + sp1 sp1(); + sp0 sp0(); + sm1 sm1(); + sm2 sm2(); + sm3 sm3(); + sm4 sm4(); + sm5 sm5(); + sm6 sm6(); + sm7 sm7(); + sm8 sm8(); + sm9 sm9(); + sm10 sm10(); + sm11 sm11(); + sm12 sm12(); + sm13 sm13(); + sm14 sm14(); + sm15 sm15(); r0 r0(); r1 r1(); final begin - s0.check(); - s1.check(); - s2.check(); - s3.check(); - s4.check(); - s5.check(); - s6.check(); - s7.check(); - s8.check(); - s9.check(); - s10.check(); - s11.check(); - s12.check(); - s13.check(); - s14.check(); - s15.check(); + sp2.check(); + sp1.check(); + sp0.check(); + sm1.check(); + sm2.check(); + sm3.check(); + sm4.check(); + sm5.check(); + sm6.check(); + sm7.check(); + sm8.check(); + sm9.check(); + sm10.check(); + sm11.check(); + sm12.check(); + sm13.check(); + sm14.check(); + sm15.check(); r0.check(); r1.check(); $write("*-* All Finished *-*\n");