forked from github/verilator
Fix $display of fixed-width numbers (#3565).
This commit is contained in:
parent
b930d0731a
commit
e7068369fe
1
Changes
1
Changes
@ -37,6 +37,7 @@ Verilator 5.001 devel
|
||||
* Add --dump-tree-dot to enable dumping Ast Tree .dot files (#3636). [Marcel Chang]
|
||||
* Add error on real edge event control.
|
||||
* Fix LSB error on --hierarchical submodules (#3539). [danbone]
|
||||
* Fix $display of fixed-width numbers (#3565). [Iztok Jeras]
|
||||
* Fix foreach and pre/post increment in functions (#3613). [Nandu Raj]
|
||||
* Fix linker errors in user-facing timing functions (#3657). [Krzysztof Bieganski, Antmicro Ltd]
|
||||
* Fix null access on optimized-out fork statements (#3658). [Krzysztof Bieganski, Antmicro Ltd]
|
||||
|
@ -905,15 +905,22 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
||||
digits = append.length();
|
||||
}
|
||||
const int needmore = width - digits;
|
||||
std::string padding;
|
||||
if (needmore > 0) {
|
||||
if (pctp && pctp[0] && pctp[1] == '0') { // %0
|
||||
padding.append(needmore, '0'); // Pre-pad zero
|
||||
} else {
|
||||
std::string padding;
|
||||
if (left) {
|
||||
padding.append(needmore, ' '); // Pre-pad spaces
|
||||
output += append + padding;
|
||||
} else {
|
||||
if (pctp && pctp[0] && pctp[1] == '0') { // %0
|
||||
padding.append(needmore, '0'); // Pre-pad zero
|
||||
} else {
|
||||
padding.append(needmore, ' '); // Pre-pad spaces
|
||||
}
|
||||
output += padding + append;
|
||||
}
|
||||
} else {
|
||||
output += append;
|
||||
}
|
||||
output += left ? (append + padding) : (padding + append);
|
||||
break;
|
||||
}
|
||||
case '#': { // Unsigned decimal
|
||||
@ -927,15 +934,22 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
||||
digits = append.length();
|
||||
}
|
||||
const int needmore = width - digits;
|
||||
std::string padding;
|
||||
if (needmore > 0) {
|
||||
if (pctp && pctp[0] && pctp[1] == '0') { // %0
|
||||
padding.append(needmore, '0'); // Pre-pad zero
|
||||
} else {
|
||||
std::string padding;
|
||||
if (left) {
|
||||
padding.append(needmore, ' '); // Pre-pad spaces
|
||||
output += append + padding;
|
||||
} else {
|
||||
if (pctp && pctp[0] && pctp[1] == '0') { // %0
|
||||
padding.append(needmore, '0'); // Pre-pad zero
|
||||
} else {
|
||||
padding.append(needmore, ' '); // Pre-pad spaces
|
||||
}
|
||||
output += padding + append;
|
||||
}
|
||||
} else {
|
||||
output += append;
|
||||
}
|
||||
output += left ? (append + padding) : (padding + append);
|
||||
break;
|
||||
}
|
||||
case 't': { // Time
|
||||
@ -944,21 +958,62 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
||||
output += _vl_vsformat_time(t_tmp, ld, timeunit, left, width);
|
||||
break;
|
||||
}
|
||||
case 'b':
|
||||
for (; lsb >= 0; --lsb) output += (VL_BITRSHIFT_W(lwp, lsb) & 1) + '0';
|
||||
break;
|
||||
case 'o':
|
||||
for (; lsb >= 0; --lsb) {
|
||||
lsb = (lsb / 3) * 3; // Next digit
|
||||
// Octal numbers may span more than one wide word,
|
||||
// so we need to grab each bit separately and check for overrun
|
||||
// Octal is rare, so we'll do it a slow simple way
|
||||
output += static_cast<char>(
|
||||
'0' + ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 0)) ? 1 : 0)
|
||||
+ ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 1)) ? 2 : 0)
|
||||
+ ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 2)) ? 4 : 0));
|
||||
case 'b': // FALLTHRU
|
||||
case 'o': // FALLTHRU
|
||||
case 'x': {
|
||||
if (widthSet || left) {
|
||||
lsb = VL_MOSTSETBITP1_W(VL_WORDS_I(lbits), lwp);
|
||||
lsb = (lsb < 1) ? 0 : (lsb - 1);
|
||||
}
|
||||
|
||||
std::string append;
|
||||
int digits;
|
||||
switch (fmt) {
|
||||
case 'b': {
|
||||
digits = lsb + 1;
|
||||
for (; lsb >= 0; --lsb) append += (VL_BITRSHIFT_W(lwp, lsb) & 1) + '0';
|
||||
break;
|
||||
}
|
||||
case 'o': {
|
||||
digits = (lsb + 1 + 2) / 3;
|
||||
for (; lsb >= 0; --lsb) {
|
||||
lsb = (lsb / 3) * 3; // Next digit
|
||||
// Octal numbers may span more than one wide word,
|
||||
// so we need to grab each bit separately and check for overrun
|
||||
// Octal is rare, so we'll do it a slow simple way
|
||||
append += static_cast<char>(
|
||||
'0' + ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 0)) ? 1 : 0)
|
||||
+ ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 1)) ? 2 : 0)
|
||||
+ ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 2)) ? 4 : 0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: { // 'x'
|
||||
digits = (lsb + 1 + 3) / 4;
|
||||
for (; lsb >= 0; --lsb) {
|
||||
lsb = (lsb / 4) * 4; // Next digit
|
||||
const IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xf;
|
||||
append += "0123456789abcdef"[charval];
|
||||
}
|
||||
break;
|
||||
}
|
||||
} // switch
|
||||
|
||||
const int needmore = width - digits;
|
||||
if (needmore > 0) {
|
||||
std::string padding;
|
||||
if (left) {
|
||||
padding.append(needmore, ' '); // Pre-pad spaces
|
||||
output += append + padding;
|
||||
} else {
|
||||
padding.append(needmore, '0'); // Pre-pad zero
|
||||
output += padding + append;
|
||||
}
|
||||
} else {
|
||||
output += append;
|
||||
}
|
||||
break;
|
||||
} // b / o / x
|
||||
case 'u':
|
||||
case 'z': { // Packed 4-state
|
||||
const bool is_4_state = (fmt == 'z');
|
||||
@ -984,13 +1039,6 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'x':
|
||||
for (; lsb >= 0; --lsb) {
|
||||
lsb = (lsb / 4) * 4; // Next digit
|
||||
const IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xf;
|
||||
output += "0123456789abcdef"[charval];
|
||||
}
|
||||
break;
|
||||
default: { // LCOV_EXCL_START
|
||||
const std::string msg = std::string{"Unknown _vl_vsformat code: "} + pos[0];
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
|
||||
|
154
src/V3Number.cpp
154
src/V3Number.cpp
@ -603,86 +603,90 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const {
|
||||
string str;
|
||||
const char code = tolower(pos[0]);
|
||||
switch (code) {
|
||||
case 'b': {
|
||||
int bit = width() - 1;
|
||||
if (fmtsize == "0")
|
||||
while (bit && bitIs0(bit)) bit--;
|
||||
for (; bit >= 0; bit--) {
|
||||
if (bitIs0(bit)) {
|
||||
str += '0';
|
||||
} else if (bitIs1(bit)) {
|
||||
str += '1';
|
||||
} else if (bitIsZ(bit)) {
|
||||
str += 'z';
|
||||
} else {
|
||||
str += 'x';
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
case 'o': {
|
||||
int bit = width() - 1;
|
||||
if (fmtsize == "0")
|
||||
while (bit && bitIs0(bit)) bit--;
|
||||
while ((bit % 3) != 2) bit++;
|
||||
for (; bit > 0; bit -= 3) {
|
||||
const int numX = countX(bit - 2, 3);
|
||||
const int numZ = countZ(bit - 2, 3);
|
||||
if (numX == 3 || numX == width() - (bit - 2)) {
|
||||
str += 'x';
|
||||
continue;
|
||||
}
|
||||
if (numZ == 3 || numZ == width() - (bit - 2)) {
|
||||
str += 'z';
|
||||
continue;
|
||||
}
|
||||
if (numX > 0) {
|
||||
str += 'X';
|
||||
continue;
|
||||
}
|
||||
if (numZ > 0) {
|
||||
str += 'Z';
|
||||
continue;
|
||||
}
|
||||
const int v = bitsValue(bit - 2, 3);
|
||||
str += static_cast<char>('0' + v);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
case 'h':
|
||||
case 'b': // FALLTHRU
|
||||
case 'o': // FALLTHRU
|
||||
case 'h': // FALLTHRU
|
||||
case 'x': {
|
||||
int bit = width() - 1;
|
||||
if (fmtsize == "0")
|
||||
while (bit && bitIs0(bit)) bit--;
|
||||
while ((bit % 4) != 3) bit++;
|
||||
for (; bit > 0; bit -= 4) {
|
||||
const int numX = countX(bit - 3, 4);
|
||||
const int numZ = countZ(bit - 3, 4);
|
||||
if (numX == 4 || numX == width() - (bit - 3)) {
|
||||
str += 'x';
|
||||
continue;
|
||||
if (left || !fmtsize.empty()) {
|
||||
while (bit && bitIs0(bit)) --bit;
|
||||
}
|
||||
switch (code) {
|
||||
case 'b': {
|
||||
for (; bit >= 0; --bit) {
|
||||
if (bitIs0(bit)) {
|
||||
str += '0';
|
||||
} else if (bitIs1(bit)) {
|
||||
str += '1';
|
||||
} else if (bitIsZ(bit)) {
|
||||
str += 'z';
|
||||
} else {
|
||||
str += 'x';
|
||||
}
|
||||
}
|
||||
if (numZ == 4 || numZ == width() - (bit - 3)) {
|
||||
str += 'z';
|
||||
continue;
|
||||
}
|
||||
if (numX > 0) {
|
||||
str += 'X';
|
||||
continue;
|
||||
}
|
||||
if (numZ > 0) {
|
||||
str += 'Z';
|
||||
continue;
|
||||
}
|
||||
const int v = bitsValue(bit - 3, 4);
|
||||
if (v >= 10) {
|
||||
str += static_cast<char>('a' + v - 10);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
case 'o': {
|
||||
while ((bit % 3) != 2) ++bit;
|
||||
for (; bit > 0; bit -= 3) {
|
||||
const int numX = countX(bit - 2, 3);
|
||||
const int numZ = countZ(bit - 2, 3);
|
||||
if (numX == 3 || numX == width() - (bit - 2)) {
|
||||
str += 'x';
|
||||
continue;
|
||||
}
|
||||
if (numZ == 3 || numZ == width() - (bit - 2)) {
|
||||
str += 'z';
|
||||
continue;
|
||||
}
|
||||
if (numX > 0) {
|
||||
str += 'X';
|
||||
continue;
|
||||
}
|
||||
if (numZ > 0) {
|
||||
str += 'Z';
|
||||
continue;
|
||||
}
|
||||
const int v = bitsValue(bit - 2, 3);
|
||||
str += static_cast<char>('0' + v);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: { // h/x
|
||||
while ((bit % 4) != 3) ++bit;
|
||||
for (; bit > 0; bit -= 4) {
|
||||
const int numX = countX(bit - 3, 4);
|
||||
const int numZ = countZ(bit - 3, 4);
|
||||
if (numX == 4 || numX == width() - (bit - 3)) {
|
||||
str += 'x';
|
||||
continue;
|
||||
}
|
||||
if (numZ == 4 || numZ == width() - (bit - 3)) {
|
||||
str += 'z';
|
||||
continue;
|
||||
}
|
||||
if (numX > 0) {
|
||||
str += 'X';
|
||||
continue;
|
||||
}
|
||||
if (numZ > 0) {
|
||||
str += 'Z';
|
||||
continue;
|
||||
}
|
||||
const int v = bitsValue(bit - 3, 4);
|
||||
if (v >= 10) {
|
||||
str += static_cast<char>('a' + v - 10);
|
||||
} else {
|
||||
str += static_cast<char>('0' + v);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} // switch
|
||||
const size_t fmtsizen = static_cast<size_t>(std::atoi(fmtsize.c_str()));
|
||||
str = displayPad(fmtsizen, (left ? ' ' : '0'), left, str);
|
||||
return str;
|
||||
}
|
||||
} // case b/d/x/o
|
||||
case 'c': {
|
||||
if (width() > 8) fl->v3warn(WIDTH, "$display-like format of %c format of > 8 bit value");
|
||||
const unsigned int v = bitsValue(0, 8);
|
||||
@ -714,7 +718,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const {
|
||||
case 't': // Time
|
||||
case 'd': { // Unsigned decimal
|
||||
const bool issigned = (code == '~');
|
||||
if (fmtsize == "") {
|
||||
if (fmtsize == "" && !left) {
|
||||
const double mantissabits = width() - (issigned ? 1 : 0);
|
||||
// To get the number of digits required, we want to compute
|
||||
// log10(2**mantissabits) and round it up. To be able to handle
|
||||
@ -753,7 +757,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const {
|
||||
}
|
||||
}
|
||||
}
|
||||
const bool zeropad = fmtsize.length() > 0 && fmtsize[0] == '0';
|
||||
const bool zeropad = fmtsize.length() > 0 && fmtsize[0] == '0' && !left;
|
||||
// fmtsize might have changed since we parsed the %fmtsize
|
||||
const size_t fmtsizen = static_cast<size_t>(std::atoi(fmtsize.c_str()));
|
||||
str = displayPad(fmtsizen, (zeropad ? '0' : ' '), left, str);
|
||||
|
@ -37,7 +37,10 @@
|
||||
[0] %P="sv-str"
|
||||
[0] %u=dcba %0u=dcba
|
||||
[0] %U=dcba %0U=dcba
|
||||
[0] %D= 12 %d= 12 %01d=12 %06d=000012 %6d= 12
|
||||
[0] %D= 12 %d= 12 %01d=12 %06d=000012 %6d= 12 %-06d=12 %-6d=12
|
||||
[0] %X=00c %x=00c %01x=c %06x=00000c %6x=00000c %-06x=c %-6x=c
|
||||
[0] %O=014 %o=014 %01o=14 %06o=000014 %6o=000014 %-06o=14 %-6o=14
|
||||
[0] %B=000001100 %b=000001100 %01b=1100 %06b=001100 %6b=001100 %-06b=1100 %-6b=1100
|
||||
[0] %t= 0 %03t= 0 %0t=0
|
||||
|
||||
[0] %s=! %s= what! %s= hmmm!1234
|
||||
|
@ -120,8 +120,14 @@ module t;
|
||||
{"a","b","c","d"}, {"a","b","c","d"}); // Avoid binary output
|
||||
// %z is tested in t_sys_sformat.v
|
||||
|
||||
$display("[%0t] %%D=%D %%d=%d %%01d=%01d %%06d=%06d %%6d=%6d", $time,
|
||||
nine, nine, nine, nine, nine);
|
||||
$display("[%0t] %%D=%D %%d=%d %%01d=%01d %%06d=%06d %%6d=%6d %%-06d=%-06d %%-6d=%-6d", $time,
|
||||
nine, nine, nine, nine, nine, nine, nine);
|
||||
$display("[%0t] %%X=%X %%x=%x %%01x=%01x %%06x=%06x %%6x=%6x %%-06x=%-06x %%-6x=%-6x", $time,
|
||||
nine, nine, nine, nine, nine, nine, nine);
|
||||
$display("[%0t] %%O=%O %%o=%o %%01o=%01o %%06o=%06o %%6o=%6o %%-06o=%-06o %%-6o=%-6o", $time,
|
||||
nine, nine, nine, nine, nine, nine, nine);
|
||||
$display("[%0t] %%B=%B %%b=%b %%01b=%01b %%06b=%06b %%6b=%6b %%-06b=%-06b %%-6b=%-6b", $time,
|
||||
nine, nine, nine, nine, nine, nine, nine);
|
||||
$display("[%0t] %%t=%t %%03t=%03t %%0t=%0t", $time,
|
||||
$time, $time, $time);
|
||||
$display;
|
||||
|
@ -27,14 +27,14 @@ module t (/*AUTOARG*/);
|
||||
|
||||
initial begin
|
||||
// Note: Base index via $c to prevent optimizatoin by Verilator
|
||||
$display("0x%32x", C[$c(0*32)+:32]);
|
||||
$display("0x%32x", D[$c(1*32)+:32]);
|
||||
$display("0x%32x", C[$c(2*32)+:32]);
|
||||
$display("0x%32x", D[$c(3*32)+:32]);
|
||||
$display("0x%32x", C[$c(4*32)+:32]);
|
||||
$display("0x%32x", D[$c(5*32)+:32]);
|
||||
$display("0x%32x", C[$c(6*32)+:32]);
|
||||
$display("0x%32x", D[$c(7*32)+:32]);
|
||||
$display("0x%8x", C[$c(0*32)+:32]);
|
||||
$display("0x%8x", D[$c(1*32)+:32]);
|
||||
$display("0x%8x", C[$c(2*32)+:32]);
|
||||
$display("0x%8x", D[$c(3*32)+:32]);
|
||||
$display("0x%8x", C[$c(4*32)+:32]);
|
||||
$display("0x%8x", D[$c(5*32)+:32]);
|
||||
$display("0x%8x", C[$c(6*32)+:32]);
|
||||
$display("0x%8x", D[$c(7*32)+:32]);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
@ -29,11 +29,11 @@ module a(
|
||||
trig_o <= 1'd0;
|
||||
if (trig_i) begin
|
||||
// Note: Base index via $c to prevent optimizatoin by Verilator
|
||||
$display("0x%32x", C[$c(0*32)+:32]);
|
||||
$display("0x%32x", C[$c(2*32)+:32]);
|
||||
$display("0x%32x", C[$c(4*32)+:32]);
|
||||
$display("0x%32x", C[$c(6*32)+:32]);
|
||||
$display("0x%256x", C);
|
||||
$display("0x%8x", C[$c(0*32)+:32]);
|
||||
$display("0x%8x", C[$c(2*32)+:32]);
|
||||
$display("0x%8x", C[$c(4*32)+:32]);
|
||||
$display("0x%8x", C[$c(6*32)+:32]);
|
||||
$display("0x%32x", C);
|
||||
trig_o <= 1'd1;
|
||||
end
|
||||
end
|
||||
@ -61,11 +61,11 @@ module b(
|
||||
trig_o <= 1'd0;
|
||||
if (trig_i) begin
|
||||
// Note: Base index via $c to prevent optimizatoin by Verilator
|
||||
$display("0x%32x", C[$c(1*32)+:32]);
|
||||
$display("0x%32x", C[$c(3*32)+:32]);
|
||||
$display("0x%32x", C[$c(5*32)+:32]);
|
||||
$display("0x%32x", C[$c(7*32)+:32]);
|
||||
$display("0x%256x", C);
|
||||
$display("0x%8x", C[$c(1*32)+:32]);
|
||||
$display("0x%8x", C[$c(3*32)+:32]);
|
||||
$display("0x%8x", C[$c(5*32)+:32]);
|
||||
$display("0x%8x", C[$c(7*32)+:32]);
|
||||
$display("0x%32x", C);
|
||||
trig_o <= 1'd1;
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user