Fix $display of fixed-width numbers (#3565).

This commit is contained in:
Wilson Snyder 2022-10-18 21:10:35 -04:00
parent b930d0731a
commit e7068369fe
7 changed files with 188 additions and 126 deletions

View File

@ -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]

View File

@ -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());

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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