Support display/scan %u/%z (#2324) (#2332)

This commit is contained in:
Stephen Henry 2020-05-18 13:10:32 +01:00 committed by GitHub
parent 9c054a5774
commit ba3930777a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 2278 additions and 27 deletions

View File

@ -846,25 +846,22 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
+ ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 2)) ? 4 : 0));
}
break;
case 'u': // Packed 2-state
output.reserve(output.size() + 4 * VL_WORDS_I(lbits));
for (int i = 0; i < VL_WORDS_I(lbits); ++i) {
output += static_cast<char>((lwp[i]) & 0xff);
output += static_cast<char>((lwp[i] >> 8) & 0xff);
output += static_cast<char>((lwp[i] >> 16) & 0xff);
output += static_cast<char>((lwp[i] >> 24) & 0xff);
}
break;
case 'z': // Packed 4-state
output.reserve(output.size() + 8 * VL_WORDS_I(lbits));
for (int i = 0; i < VL_WORDS_I(lbits); ++i) {
output += static_cast<char>((lwp[i]) & 0xff);
output += static_cast<char>((lwp[i] >> 8) & 0xff);
output += static_cast<char>((lwp[i] >> 16) & 0xff);
output += static_cast<char>((lwp[i] >> 24) & 0xff);
output += "\0\0\0\0"; // No tristate
case 'u':
case 'z': { // Packed 4-state
const bool is_4_state = (fmt == 'z');
output.reserve(output.size() + ((is_4_state ? 2 : 1) * VL_WORDS_I(lbits)));
int bytes_to_go = VL_BYTES_I(lbits);
int bit = 0;
while (bytes_to_go > 0) {
const int wr_bytes = std::min(4, bytes_to_go);
for (int byte = 0; byte < wr_bytes; byte++, bit += 8)
output += static_cast<char>(VL_BITRSHIFT_W(lwp, bit) & 0xff);
output.append(4 - wr_bytes, (char)0);
if (is_4_state) output.append(4, (char)0);
bytes_to_go -= wr_bytes;
}
break;
}
case 'v': // Strength; assume always strong
for (lsb = lbits - 1; lsb >= 0; --lsb) {
if (VL_BITRSHIFT_W(lwp, lsb) & 1) {
@ -932,8 +929,8 @@ static inline void _vl_vsss_skipspace(FILE* fp, int& floc, WDataInP fromp,
_vl_vsss_advance(fp, floc);
}
}
static inline void _vl_vsss_read(FILE* fp, int& floc, WDataInP fromp, const std::string& fstr,
char* tmpp, const char* acceptp) VL_MT_SAFE {
static inline void _vl_vsss_read_str(FILE* fp, int& floc, WDataInP fromp, const std::string& fstr,
char* tmpp, const char* acceptp) VL_MT_SAFE {
// Read into tmp, consisting of characters from acceptp list
char* cp = tmpp;
while (true) {
@ -947,6 +944,19 @@ static inline void _vl_vsss_read(FILE* fp, int& floc, WDataInP fromp, const std:
*cp++ = '\0';
// VL_DBG_MSGF(" _read got='"<<tmpp<<"'\n");
}
static inline char* _vl_vsss_read_bin(FILE* fp, int& floc, WDataInP fromp, const std::string& fstr,
char* beginp, std::size_t n, bool inhibit = false) {
// Variant of _vl_vsss_read_str using the same underlying I/O functions but optimized
// specifically for block reads of N bytes (read operations are not demarcated by
// whitespace). In the fp case, except descriptor to have been opened in binary mode.
while (n-- > 0) {
const int c = _vl_vsss_peek(fp, floc, fromp, fstr);
if (c == EOF) return NULL;
if (!inhibit) *beginp++ = c;
_vl_vsss_advance(fp, floc);
}
return beginp;
}
static inline void _vl_vsss_setbit(WDataOutP owp, int obits, int lsb, int nbits,
IData ld) VL_MT_SAFE {
for (; nbits && lsb < obits; nbits--, lsb++, ld >>= 1) {
@ -1045,7 +1055,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
}
case 's': {
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read(fp, floc, fromp, fstr, tmp, NULL);
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, NULL);
if (!tmp[0]) goto done;
int lpos = (static_cast<int>(strlen(tmp))) - 1;
int lsb = 0;
@ -1057,7 +1067,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
}
case 'd': { // Signed decimal
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read(fp, floc, fromp, fstr, tmp, "0123456789+-xXzZ?_");
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "0123456789+-xXzZ?_");
if (!tmp[0]) goto done;
vlsint64_t ld;
sscanf(tmp, "%30" VL_PRI64 "d", &ld);
@ -1068,7 +1078,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
case 'e':
case 'g': { // Real number
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read(fp, floc, fromp, fstr, tmp, "+-.0123456789eE");
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "+-.0123456789eE");
if (!tmp[0]) goto done;
// cppcheck-suppress unusedStructMember // It's used
union {
@ -1082,7 +1092,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
case 't': // FALLTHRU // Time
case '#': { // Unsigned decimal
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read(fp, floc, fromp, fstr, tmp, "0123456789+-xXzZ?_");
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "0123456789+-xXzZ?_");
if (!tmp[0]) goto done;
QData ld;
sscanf(tmp, "%30" VL_PRI64 "u", &ld);
@ -1091,25 +1101,52 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
}
case 'b': {
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read(fp, floc, fromp, fstr, tmp, "01xXzZ?_");
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "01xXzZ?_");
if (!tmp[0]) goto done;
_vl_vsss_based(owp, obits, 1, tmp, 0, strlen(tmp));
break;
}
case 'o': {
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read(fp, floc, fromp, fstr, tmp, "01234567xXzZ?_");
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "01234567xXzZ?_");
if (!tmp[0]) goto done;
_vl_vsss_based(owp, obits, 3, tmp, 0, strlen(tmp));
break;
}
case 'x': {
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read(fp, floc, fromp, fstr, tmp, "0123456789abcdefABCDEFxXzZ?_");
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "0123456789abcdefABCDEFxXzZ?_");
if (!tmp[0]) goto done;
_vl_vsss_based(owp, obits, 4, tmp, 0, strlen(tmp));
break;
}
case 'u': {
// Read packed 2-value binary data
const int bytes = VL_BYTES_I(obits);
char* out = reinterpret_cast<char*>(owp);
if (!_vl_vsss_read_bin(fp, floc, fromp, fstr, out, bytes)) goto done;
const int last = bytes % 4;
if (last != 0
&& !_vl_vsss_read_bin(fp, floc, fromp, fstr, out, 4 - last, true))
goto done;
break;
}
case 'z': {
// Read packed 4-value binary data
char* out = reinterpret_cast<char*>(owp);
int bytes = VL_BYTES_I(obits);
while (bytes > 0) {
const int abytes = std::min(4, bytes);
// aval (4B) read {0, 1} state
out = _vl_vsss_read_bin(fp, floc, fromp, fstr, out, abytes);
if (!out) goto done;
// bval (4B) disregard {X, Z} state and align to new 8B boundary.
out = _vl_vsss_read_bin(fp, floc, fromp, fstr, out, 8 - abytes, true);
if (!out) goto done;
bytes -= abytes;
}
break;
}
default:
std::string msg = std::string("Unknown _vl_vsscanf code: ") + pos[0];
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
@ -1336,7 +1373,7 @@ void VL_FWRITEF(IData fpi, const char* formatp, ...) VL_MT_SAFE {
const int n = VerilatedImp::fdToFp(fpi, fp, 30);
for (std::size_t i = 0; i < n; i++) {
if (VL_UNLIKELY(!fp[i])) continue;
fputs(output.c_str(), fp[i]);
fwrite(output.c_str(), 1, output.size(), fp[i]);
}
}

View File

@ -2182,6 +2182,8 @@ void EmitCStmts::displayNode(AstNode* nodep, AstScopeName* scopenamep, const str
case 'g': displayArg(nodep, &elistp, isScan, vfmt, ignore, 'g'); break;
case '^': displayArg(nodep, &elistp, isScan, vfmt, ignore, '^'); break; // Realtime
case 'v': displayArg(nodep, &elistp, isScan, vfmt, ignore, 'v'); break;
case 'u': displayArg(nodep, &elistp, isScan, vfmt, ignore, 'u'); break;
case 'z': displayArg(nodep, &elistp, isScan, vfmt, ignore, 'z'); break;
case 'm': {
UASSERT_OBJ(scopenamep, nodep, "Display with %m but no AstScopeName");
string suffix = scopenamep->scopePrettySymName();

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,27 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(simulator => 1);
unlink("$Self->{obj_dir}/t_sys_file_basic_uz_test.log");
compile();
execute(
check_finished => 1,
);
files_identical("$Self->{obj_dir}/t_sys_file_basic_uz_test.log", $Self->{golden_filename});
files_identical("$Self->{obj_dir}/t_sys_file_basic_uz_test.bin",
"$Self->{t_dir}/t_sys_file_basic_uz.dat");
ok(1);
1;

View File

@ -0,0 +1,137 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2030 by Stephen Henry.
// SPDX-License-Identifier: CC0-1.0
module t;
int fdin_bin, fdout_txt, fdout_bin;
`define STRINGIFY(x) `"x`"
`define checkh(gotv,expv) \
do if ((gotv) !== (expv)) begin\
$write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv));\
end while(0)
//
//
task automatic test1; begin
for (int i = 0; i < 256; i++) begin
byte actual, expected;
expected = i[7:0];
$fscanf(fdin_bin, "%u", actual);
`checkh(actual, expected);
$fdisplay(fdout_txt, "%h", actual);
$fwrite(fdout_bin, "%u", actual);
end
for (int i = 0; i < 256; i++) begin
shortint actual, expected;
for (int j = 0; j < 2; j++)
expected[(8 * j)+:8] = i[7:0] + j[7:0];
$fscanf(fdin_bin, "%u", actual);
`checkh(actual, expected);
$fdisplay(fdout_txt, "%h", actual);
$fwrite(fdout_bin, "%u", actual);
end
for (int i = 0; i < 256; i++) begin
int actual, expected;
for (int j = 0; j < 4; j++)
expected[(8 * j)+:8] = i[7:0] + j[7:0];
$fscanf(fdin_bin, "%u", actual);
`checkh(actual, expected);
$fdisplay(fdout_txt, "%h", actual);
$fwrite(fdout_bin, "%u", actual);
end
for (int i = 0; i < 256; i++) begin
longint actual, expected;
for (int j = 0; j < 8; j++)
expected[(8 * j)+:8] = i[7:0] + j[7:0];
$fscanf(fdin_bin, "%u", actual);
`checkh(actual, expected);
$fdisplay(fdout_txt, "%h", actual);
$fwrite(fdout_bin, "%u", actual);
end
end endtask
//
//
task automatic test2; begin
for (int i = 0; i < 256; i++) begin
byte actual, expected;
expected = i[7:0];
$fscanf(fdin_bin, "%z", actual);
`checkh(actual, expected);
$fdisplay(fdout_txt, "%h", actual);
$fwrite(fdout_bin, "%z", actual);
end
for (int i = 0; i < 256; i++) begin
shortint actual, expected;
for (int j = 0; j < 2; j++)
expected[(8 * j)+:8] = i[7:0] + j[7:0];
$fscanf(fdin_bin, "%z", actual);
`checkh(actual, expected);
$fdisplay(fdout_txt, "%h", actual);
$fwrite(fdout_bin, "%z", actual);
end
for (int i = 0; i < 256; i++) begin
int actual, expected;
for (int j = 0; j < 4; j++)
expected[(8 * j)+:8] = i[7:0] + j[7:0];
$fscanf(fdin_bin, "%z", actual);
`checkh(actual, expected);
$fdisplay(fdout_txt, "%h", actual);
$fwrite(fdout_bin, "%z", actual);
end
for (int i = 0; i < 256; i++) begin
longint actual, expected;
for (int j = 0; j < 8; j++)
expected[(8 * j)+:8] = i[7:0] + j[7:0];
$fscanf(fdin_bin, "%z", actual);
`checkh(actual, expected);
$fdisplay(fdout_txt, "%h", actual);
$fwrite(fdout_bin, "%z", actual);
end
end endtask
initial begin : main_PROC
string filename;
filename = "t/t_sys_file_basic_uz.dat";
fdin_bin = $fopen(filename, "rb");
`ifdef IVERILOG
filename = $sformatf("%s/t_sys_file_basic_uz_test.log","obj_iv/t_sys_file_basic_uz");
`else
filename = $sformatf("%s/t_sys_file_basic_uz_test.log",`STRINGIFY(`TEST_OBJ_DIR));
`endif
fdout_txt = $fopen(filename, "w");
`ifdef IVERILOG
filename = $sformatf("%s/t_sys_file_basic_uz_test.bin","obj_iv/t_sys_file_basic_uz");
`else
filename = $sformatf("%s/t_sys_file_basic_uz_test.bin",`STRINGIFY(`TEST_OBJ_DIR));
`endif
$display(filename);
fdout_bin = $fopen(filename, "wb");
test1;
test2;
$fclose(fdin_bin);
$fclose(fdout_txt);
$write("*-* All Finished *-*\n");
$finish(0); // Test arguments to finish
end // block: main_PROC
`undef STRINGIFY
endmodule // t