mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
Format time string using integer (#2940)
Co-authored-by: Wilson Snyder <wsnyder@wsnyder.org>
This commit is contained in:
parent
80d62adec7
commit
31779b8b8b
@ -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);
|
||||
@ -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<double>(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 {
|
||||
|
@ -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
|
||||
|
@ -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, "");
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user