Skip to content

Commit

Permalink
Format time string using integer (verilator#2940)
Browse files Browse the repository at this point in the history
Co-authored-by: Wilson Snyder <wsnyder@wsnyder.org>
  • Loading branch information
yTakatsukasa and wsnyder committed May 16, 2021
1 parent 80d62ad commit 31779b8
Show file tree
Hide file tree
Showing 12 changed files with 132 additions and 58 deletions.
116 changes: 98 additions & 18 deletions include/verilated.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename T>
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<T>::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<vluint64_t>::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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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<double>(ld), left, width);
const int timeunit = va_arg(ap, int);
output += _vl_vsformat_time(t_tmp, ld, timeunit, left, width);
break;
}
case 'b':
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions include/verilated.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions src/V3EmitC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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, "");
}
Expand Down
21 changes: 0 additions & 21 deletions src/V3Width.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3864,27 +3864,6 @@ class WidthVisitor final : public AstNVisitor {
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;
Expand Down
4 changes: 2 additions & 2 deletions test_regress/t/t_time_vpi_100s10ms.out
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions test_regress/t/t_time_vpi_10ms10ns.out
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions test_regress/t/t_time_vpi_1fs1fs.out
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions test_regress/t/t_time_vpi_1ms10ns.out
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions test_regress/t/t_time_vpi_1ns1ns.out
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions test_regress/t/t_time_vpi_1ps1fs.out
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions test_regress/t/t_time_vpi_1s10ns.out
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions test_regress/t/t_time_vpi_1us1ns.out
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 31779b8

Please sign in to comment.