From 31779b8b8bb5764247d6fd892b91228a10294395 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Sun, 16 May 2021 19:01:03 +0900 Subject: [PATCH] Format time string using integer (#2940) Co-authored-by: Wilson Snyder --- include/verilated.cpp | 116 +++++++++++++++++++++---- include/verilated.h | 2 + src/V3EmitC.cpp | 13 +++ src/V3Width.cpp | 21 ----- test_regress/t/t_time_vpi_100s10ms.out | 4 +- test_regress/t/t_time_vpi_10ms10ns.out | 4 +- test_regress/t/t_time_vpi_1fs1fs.out | 4 +- test_regress/t/t_time_vpi_1ms10ns.out | 4 +- test_regress/t/t_time_vpi_1ns1ns.out | 4 +- test_regress/t/t_time_vpi_1ps1fs.out | 8 +- test_regress/t/t_time_vpi_1s10ns.out | 4 +- test_regress/t/t_time_vpi_1us1ns.out | 6 +- 12 files changed, 132 insertions(+), 58 deletions(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index a1c070cad..f8b460439 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -637,26 +637,80 @@ std::string VL_DECIMAL_NW(int width, WDataInP lwp) VL_MT_SAFE { return output; } -std::string _vl_vsformat_time(char* tmp, double ld, bool left, size_t width) { - // Double may lose precision, but sc_time_stamp has similar limit - std::string suffix = Verilated::threadContextp()->impp()->timeFormatSuffix(); - int userUnits = Verilated::threadContextp()->impp()->timeFormatUnits(); // 0..-15 - int fracDigits = Verilated::threadContextp()->impp()->timeFormatPrecision(); // 0..N - int prec = Verilated::threadContextp()->timeprecision(); // 0..-15 - int shift = prec - userUnits + fracDigits; // 0..-15 - double shiftd = vl_time_multiplier(shift); - double scaled = ld * shiftd; - const double fracDiv = vl_time_multiplier(fracDigits); - const double whole = scaled / fracDiv; +template +std::string _vl_vsformat_time(char* tmp, T ld, int timeunit, bool left, size_t width) { + const VerilatedContextImp* const ctxImpp = Verilated::threadContextp()->impp(); + const std::string suffix = ctxImpp->timeFormatSuffix(); + const int userUnits = ctxImpp->timeFormatUnits(); // 0..-15 + const int fracDigits = ctxImpp->timeFormatPrecision(); // 0..N + const int shift = -userUnits + fracDigits + timeunit; // 0..-15 int digits = 0; - if (!fracDigits) { - digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%.0f%s", whole, suffix.c_str()); + if (std::numeric_limits::is_integer) { + constexpr int b = 128; + constexpr int w = VL_WORDS_I(b); + WData tmp0[w], tmp1[w], tmp2[w], tmp3[w]; + + WDataInP shifted = VL_EXTEND_WQ(b, 0, tmp0, ld); + if (shift < 0) { + WDataInP pow10 = VL_EXTEND_WQ(b, 0, tmp1, vl_time_pow10(-shift)); + shifted = VL_DIV_WWW(b, tmp2, shifted, pow10); + } else { + WDataInP pow10 = VL_EXTEND_WQ(b, 0, tmp1, vl_time_pow10(shift)); + shifted = VL_MUL_W(w, tmp2, shifted, pow10); + } + + WDataInP fracDigitsPow10 = VL_EXTEND_WQ(b, 0, tmp3, vl_time_pow10(fracDigits)); + WDataInP integer = VL_DIV_WWW(b, tmp0, shifted, fracDigitsPow10); + WDataInP frac = VL_MODDIV_WWW(b, tmp1, shifted, fracDigitsPow10); + WDataInP max64Bit + = VL_EXTEND_WQ(b, 0, tmp2, std::numeric_limits::max()); // breaks shifted + if (VL_GT_W(w, integer, max64Bit)) { + WDataOutP v = VL_ASSIGN_W(b, tmp3, integer); // breaks fracDigitsPow10 + WData zero[w], ten[w]; + VL_ZERO_W(b, zero); + VL_EXTEND_WI(b, 0, ten, 10); + char buf[128]; // 128B is obviously long enough to represent 128bit integer in decimal + char* ptr = buf + sizeof(buf) - 1; + *ptr = '\0'; + while (VL_GT_W(w, v, zero)) { + --ptr; + WDataInP mod = VL_MODDIV_WWW(b, tmp2, v, ten); // breaks max64Bit + *ptr = "0123456789"[VL_SET_QW(mod)]; + WData divided[w]; + VL_DIV_WWW(b, divided, v, ten); + VL_ASSIGN_W(b, v, divided); + } + if (!fracDigits) { + digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%s%s", ptr, suffix.c_str()); + } else { + digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%s.%0*" VL_PRI64 "u%s", ptr, + fracDigits, VL_SET_QW(frac), suffix.c_str()); + } + } else { + const vluint64_t integer64 = VL_SET_QW(integer); + if (!fracDigits) { + digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%" VL_PRI64 "u%s", integer64, + suffix.c_str()); + } else { + digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, + "%" VL_PRI64 "u.%0*" VL_PRI64 "u%s", integer64, fracDigits, + VL_SET_QW(frac), suffix.c_str()); + } + } } else { - digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%.*f%s", fracDigits, whole, - suffix.c_str()); + double shiftd = vl_time_multiplier(shift); + double scaled = ld * shiftd; + const double fracDiv = vl_time_multiplier(fracDigits); + const double whole = scaled / fracDiv; + if (!fracDigits) { + digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%.0f%s", whole, suffix.c_str()); + } else { + digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%.*f%s", fracDigits, whole, + suffix.c_str()); + } } - int needmore = width - digits; + const int needmore = width - digits; std::string padding; if (needmore > 0) padding.append(needmore, ' '); // Pad with spaces return left ? (tmp + padding) : (padding + tmp); @@ -751,7 +805,8 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA if (lbits) {} // UNUSED - always 64 if (fmt == '^') { // Realtime if (!widthSet) width = Verilated::threadContextp()->impp()->timeFormatWidth(); - output += _vl_vsformat_time(t_tmp, d, left, width); + const int timeunit = va_arg(ap, int); + output += _vl_vsformat_time(t_tmp, d, timeunit, left, width); } else { std::string fmts(pctp, pos - pctp + 1); VL_SNPRINTF(t_tmp, VL_VALUE_STRING_MAX_WIDTH, fmts.c_str(), d); @@ -850,7 +905,8 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA } case 't': { // Time if (!widthSet) width = Verilated::threadContextp()->impp()->timeFormatWidth(); - output += _vl_vsformat_time(t_tmp, static_cast(ld), left, width); + const int timeunit = va_arg(ap, int); + output += _vl_vsformat_time(t_tmp, ld, timeunit, left, width); break; } case 'b': @@ -2153,6 +2209,30 @@ double vl_time_multiplier(int scale) VL_PURE { return pow10[scale]; } } +vluint64_t vl_time_pow10(int n) { + static const vluint64_t pow10[20] = { + 1ULL, + 10ULL, + 100ULL, + 1000ULL, + 10000ULL, + 100000ULL, + 1000000ULL, + 10000000ULL, + 100000000ULL, + 1000000000ULL, + 10000000000ULL, + 100000000000ULL, + 1000000000000ULL, + 10000000000000ULL, + 100000000000000ULL, + 1000000000000000ULL, + 10000000000000000ULL, + 100000000000000000ULL, + 1000000000000000000ULL, + }; + return pow10[n]; +} void VL_PRINTTIMESCALE(const char* namep, const char* timeunitp, const VerilatedContext* contextp) VL_MT_SAFE { diff --git a/include/verilated.h b/include/verilated.h index 7df6e08de..123ea92c5 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -1187,6 +1187,8 @@ inline vluint64_t VerilatedContext::time() const VL_MT_SAFE { // Return time precision as multiplier of time units double vl_time_multiplier(int scale) VL_PURE; +// Return power of 10. e.g. returns 100 if n==2 +vluint64_t vl_time_pow10(int n) VL_PURE; #ifdef VL_DEBUG /// Evaluate statement if Verilated::debug() enabled diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 0ad110a5d..08f186b3e 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -2282,6 +2282,19 @@ void EmitCStmts::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const emitDispState.pushArg(' ', nullptr, cvtToStr(argp->widthMin())); } emitDispState.pushArg(fmtLetter, argp, ""); + if (fmtLetter == 't' || fmtLetter == '^') { + AstSFormatF* fmtp = nullptr; + if (AstDisplay* nodep = VN_CAST(dispp, Display)) + fmtp = nodep->fmtp(); + else if (AstSFormat* nodep = VN_CAST(dispp, SFormat)) + fmtp = nodep->fmtp(); + else + fmtp = VN_CAST(dispp, SFormatF); + UASSERT_OBJ(fmtp, dispp, + "Use of %t must be under AstDisplay, AstSFormat, or AstSFormatF"); + UASSERT_OBJ(!fmtp->timeunit().isNone(), fmtp, "timenunit must be set"); + emitDispState.pushArg(' ', nullptr, cvtToStr((int)fmtp->timeunit().powerOfTen())); + } } else { emitDispState.pushArg(fmtLetter, nullptr, ""); } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index dc556aa00..22e15d1c7 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -3864,27 +3864,6 @@ private: if (nodep->timeunit().isNone()) { nodep->v3fatalSrc("display %t has no time units"); } - double scale = nodep->timeunit().multiplier() - / v3Global.rootp()->timeprecision().multiplier(); - if (scale != 1.0) { - AstNode* newp; - AstNRelinker relinkHandle; - argp->unlinkFrBack(&relinkHandle); - if (argp->isDouble()) { // Convert it - ch = '^'; - newp = new AstMulD( - argp->fileline(), - new AstConst(argp->fileline(), AstConst::RealDouble(), scale), - argp); - } else { - newp = new AstMul(argp->fileline(), - new AstConst(argp->fileline(), - AstConst::Unsized64(), - std::llround(scale)), - argp); - } - relinkHandle.relink(newp); - } argp = nextp; } break; diff --git a/test_regress/t/t_time_vpi_100s10ms.out b/test_regress/t/t_time_vpi_100s10ms.out index c581dbf6c..8a0428fea 100644 --- a/test_regress/t/t_time_vpi_100s10ms.out +++ b/test_regress/t/t_time_vpi_100s10ms.out @@ -3,11 +3,11 @@ 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 - acc%0t=11177671081359484928 acc%0d=12345678901234567890 + acc%0t=123456789012345678900000 acc%0d=12345678901234567890 [1000000000000000.000000ns] time%0d=10000 123%0t=12300000000000.000000ns dig%0t=0.000000ns dig%0d=0 rdig%0t=5432109876.543210ns rdig%0f=0.054321 - acc%0t=111776710813594856498135040.000000ns acc%0d=12345678901234567890 + acc%0t=1234567890123456789000000000000.000000ns acc%0d=12345678901234567890 [1000000000000000.000000ns] stime%0t=1000000000000000.000000ns stime%0d=10000 stime%0f=10000.000000 [1000000000000000.000000ns] rtime%0t=1000000000000000.000000ns rtime%0d=10000 rtime%0f=10000.000000 global vpiSimTime = 0,100000000 vpiScaledRealTime = 1e+08 diff --git a/test_regress/t/t_time_vpi_10ms10ns.out b/test_regress/t/t_time_vpi_10ms10ns.out index 4b7180883..b09a31d11 100644 --- a/test_regress/t/t_time_vpi_10ms10ns.out +++ b/test_regress/t/t_time_vpi_10ms10ns.out @@ -3,11 +3,11 @@ Time scale of t is 10ms / 10ns [60000000] time%0d=60 123%0t=123000000 dig%0t=543000000 dig%0d=543 rdig%0t=543210988 rdig%0f=543.210988 - acc%0t=10962463713375475712 acc%0d=12345678901234567890 + acc%0t=12345678901234567890000000 acc%0d=12345678901234567890 [600000000.000000ns] time%0d=60 123%0t=1230000000.000000ns dig%0t=5430000000.000000ns dig%0d=543 rdig%0t=5432109876.543210ns rdig%0f=543.210988 - acc%0t=109624637133754744832.000000ns acc%0d=12345678901234567890 + acc%0t=123456789012345678900000000.000000ns acc%0d=12345678901234567890 [600000000.000000ns] stime%0t=600000000.000000ns stime%0d=60 stime%0f=60.000000 [600000000.000000ns] rtime%0t=600000000.000000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,60000000 vpiScaledRealTime = 6e+07 diff --git a/test_regress/t/t_time_vpi_1fs1fs.out b/test_regress/t/t_time_vpi_1fs1fs.out index 612a7023b..a353d9cea 100644 --- a/test_regress/t/t_time_vpi_1fs1fs.out +++ b/test_regress/t/t_time_vpi_1fs1fs.out @@ -3,11 +3,11 @@ Time scale of t is 1fs / 1fs [60] time%0d=60 123%0t=123 dig%0t=5432109876543210 dig%0d=5432109876543210 rdig%0t=5432109876543210 rdig%0f=5432109876543210.000000 - acc%0t=12345678901234567168 acc%0d=12345678901234567890 + acc%0t=12345678901234567890 acc%0d=12345678901234567890 [0.000060ns] time%0d=60 123%0t=0.000123ns dig%0t=5432109876.543210ns dig%0d=5432109876543210 rdig%0t=5432109876.543210ns rdig%0f=5432109876543210.000000 - acc%0t=12345678901234.566406ns acc%0d=12345678901234567890 + acc%0t=12345678901234.567890ns acc%0d=12345678901234567890 [0.000060ns] stime%0t=0.000060ns stime%0d=60 stime%0f=60.000000 [0.000060ns] rtime%0t=0.000060ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,60 vpiScaledRealTime = 60 diff --git a/test_regress/t/t_time_vpi_1ms10ns.out b/test_regress/t/t_time_vpi_1ms10ns.out index a6e35ad26..1276f8d4c 100644 --- a/test_regress/t/t_time_vpi_1ms10ns.out +++ b/test_regress/t/t_time_vpi_1ms10ns.out @@ -3,11 +3,11 @@ Time scale of t is 1ms / 10ns [6000000] time%0d=60 123%0t=12300000 dig%0t=543200000 dig%0d=5432 rdig%0t=543210988 rdig%0f=5432.109877 - acc%0t=1096246371337547520 acc%0d=12345678901234567890 + acc%0t=1234567890123456789000000 acc%0d=12345678901234567890 [60000000.000000ns] time%0d=60 123%0t=123000000.000000ns dig%0t=5432000000.000000ns dig%0d=5432 rdig%0t=5432109876.543210ns rdig%0f=5432.109877 - acc%0t=10962463713375473664.000000ns acc%0d=12345678901234567890 + acc%0t=12345678901234567890000000.000000ns acc%0d=12345678901234567890 [60000000.000000ns] stime%0t=60000000.000000ns stime%0d=60 stime%0f=60.000000 [60000000.000000ns] rtime%0t=60000000.000000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,6000000 vpiScaledRealTime = 6e+06 diff --git a/test_regress/t/t_time_vpi_1ns1ns.out b/test_regress/t/t_time_vpi_1ns1ns.out index 05e68341c..b9e6d3ed1 100644 --- a/test_regress/t/t_time_vpi_1ns1ns.out +++ b/test_regress/t/t_time_vpi_1ns1ns.out @@ -3,11 +3,11 @@ Time scale of t is 1ns / 1ns [60] time%0d=60 123%0t=123 dig%0t=5432109877 dig%0d=5432109877 rdig%0t=5432109877 rdig%0f=5432109876.543210 - acc%0t=12345678901234567168 acc%0d=12345678901234567890 + acc%0t=12345678901234567890 acc%0d=12345678901234567890 [60.000000ns] time%0d=60 123%0t=123.000000ns dig%0t=5432109877.000000ns dig%0d=5432109877 rdig%0t=5432109876.543210ns rdig%0f=5432109876.543210 - acc%0t=12345678901234565120.000000ns acc%0d=12345678901234567890 + acc%0t=12345678901234567890.000000ns acc%0d=12345678901234567890 [60.000000ns] stime%0t=60.000000ns stime%0d=60 stime%0f=60.000000 [60.000000ns] rtime%0t=60.000000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,60 vpiScaledRealTime = 60 diff --git a/test_regress/t/t_time_vpi_1ps1fs.out b/test_regress/t/t_time_vpi_1ps1fs.out index 35ab855e0..3a391485d 100644 --- a/test_regress/t/t_time_vpi_1ps1fs.out +++ b/test_regress/t/t_time_vpi_1ps1fs.out @@ -2,12 +2,12 @@ Time scale of t is 1ps / 1fs [60000] time%0d=60 123%0t=123000 dig%0t=5432109876543000 dig%0d=5432109876543 - rdig%0t=5432109876543209 rdig%0f=5432109876543.209961 - acc%0t=4807115922877858816 acc%0d=12345678901234567890 + rdig%0t=5432109876543210 rdig%0f=5432109876543.209961 + acc%0t=12345678901234567890000 acc%0d=12345678901234567890 [0.060000ns] time%0d=60 123%0t=0.123000ns dig%0t=5432109876.543000ns dig%0d=5432109876543 - rdig%0t=5432109876.543209ns rdig%0f=5432109876543.209961 - acc%0t=4807115922877.858398ns acc%0d=12345678901234567890 + rdig%0t=5432109876.543210ns rdig%0f=5432109876543.209961 + acc%0t=12345678901234567.890000ns acc%0d=12345678901234567890 [0.060000ns] stime%0t=0.060000ns stime%0d=60 stime%0f=60.000000 [0.060000ns] rtime%0t=0.060000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,60000 vpiScaledRealTime = 60000 diff --git a/test_regress/t/t_time_vpi_1s10ns.out b/test_regress/t/t_time_vpi_1s10ns.out index f9a17a8f8..b950e9176 100644 --- a/test_regress/t/t_time_vpi_1s10ns.out +++ b/test_regress/t/t_time_vpi_1s10ns.out @@ -3,11 +3,11 @@ Time scale of t is 1s / 10ns [6000000000] time%0d=60 123%0t=12300000000 dig%0t=500000000 dig%0d=5 rdig%0t=543210988 rdig%0f=5.432110 - acc%0t=7888470988684038144 acc%0d=12345678901234567890 + acc%0t=1234567890123456789000000000 acc%0d=12345678901234567890 [60000000000.000000ns] time%0d=60 123%0t=123000000000.000000ns dig%0t=5000000000.000000ns dig%0d=5 rdig%0t=5432109876.543210ns rdig%0f=5.432110 - acc%0t=78884709886840389632.000000ns acc%0d=12345678901234567890 + acc%0t=12345678901234567890000000000.000000ns acc%0d=12345678901234567890 [60000000000.000000ns] stime%0t=60000000000.000000ns stime%0d=60 stime%0f=60.000000 [60000000000.000000ns] rtime%0t=60000000000.000000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 1,1705032704 vpiScaledRealTime = 6e+09 diff --git a/test_regress/t/t_time_vpi_1us1ns.out b/test_regress/t/t_time_vpi_1us1ns.out index 4c2c152d0..59d7e4ea8 100644 --- a/test_regress/t/t_time_vpi_1us1ns.out +++ b/test_regress/t/t_time_vpi_1us1ns.out @@ -3,11 +3,11 @@ Time scale of t is 1us / 1ns [60000] time%0d=60 123%0t=123000 dig%0t=5432110000 dig%0d=5432110 rdig%0t=5432109877 rdig%0f=5432109.876543 - acc%0t=4807115922877858816 acc%0d=12345678901234567890 + acc%0t=12345678901234567890000 acc%0d=12345678901234567890 [60000.000000ns] time%0d=60 123%0t=123000.000000ns dig%0t=5432110000.000000ns dig%0d=5432110 - rdig%0t=5432109876.543209ns rdig%0f=5432109.876543 - acc%0t=4807115922877858816.000000ns acc%0d=12345678901234567890 + rdig%0t=5432109876.543210ns rdig%0f=5432109.876543 + acc%0t=12345678901234567890000.000000ns acc%0d=12345678901234567890 [60000.000000ns] stime%0t=60000.000000ns stime%0d=60 stime%0f=60.000000 [60000.000000ns] rtime%0t=60000.000000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,60000 vpiScaledRealTime = 60000