diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 72f1e9dc7..af921dad7 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -224,6 +224,7 @@ Marshal Qiao Martijn Wobbes Martin Schmidt Martin Stadler +Martin Velay Mateusz Gancarz Matt Stroud Matthew Ballance diff --git a/include/verilated.cpp b/include/verilated.cpp index ecfb98881..f1f7af607 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -1695,7 +1695,8 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf _vl_vsss_read_str(fp, floc, fromp, fstr, std::back_insert_iterator{t_tmp}, "0123456789+-xXzZ?_"); - if (!t_tmp[0]) goto done; + t_tmp.erase(std::remove(t_tmp.begin(), t_tmp.end(), '_'), t_tmp.end()); + if (t_tmp.empty()) goto done; if (formatAttr == VL_VFORMATATTR_SIGNED) { QData ld = 0; std::sscanf(t_tmp.c_str(), "%30" PRIu64, &ld); @@ -2401,8 +2402,10 @@ IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_M VL_ZERO_W(rbits, rwp); switch (std::tolower(fmt)) { case 'd': { + std::string digits{dp}; + digits.erase(std::remove(digits.begin(), digits.end(), '_'), digits.end()); int64_t lld = 0; - std::sscanf(dp, "%30" PRId64, &lld); + std::sscanf(digits.c_str(), "%30" PRId64, &lld); VL_SET_WQ(rwp, lld); break; } diff --git a/test_regress/t/t_sys_plusargs.py b/test_regress/t/t_sys_plusargs.py index fa6e7da58..3b0ce06a9 100755 --- a/test_regress/t/t_sys_plusargs.py +++ b/test_regress/t/t_sys_plusargs.py @@ -13,6 +13,10 @@ test.scenarios('simulator') test.compile(v_flags2=['-v', 't/t_flag_libinc.v']) -test.execute(all_run_flags=['+PLUS +INT=1234 +STRSTR +REAL=1.2345 +IP%P101']) +test.execute(all_run_flags=[ + '+PLUS +INT=1234 +STRSTR +REAL=1.2345 +IP%P101', + '+DECIMAL=300_000_000_000 +NEGATIVE=-300_000_000_000', + '+LEADING=_1_234 +TRAILING=1_234_ +UNDERSCORE=_', +]) test.passes() diff --git a/test_regress/t/t_sys_plusargs.v b/test_regress/t/t_sys_plusargs.v index 45efb4c88..fd0c1cdc4 100644 --- a/test_regress/t/t_sys_plusargs.v +++ b/test_regress/t/t_sys_plusargs.v @@ -4,6 +4,11 @@ // SPDX-FileCopyrightText: 2009 Wilson Snyder // SPDX-License-Identifier: CC0-1.0 +// verilog_format: off +`define stop $stop +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +// verilog_format: on + module t; integer p_i; // signal type IData @@ -15,6 +20,8 @@ module t; reg [7*8:1] p_in; string sv_in; integer unread; // never read + longint signed p_decimal; + int code; initial begin if ($test$plusargs("PLUS") !== 1) $stop; @@ -128,6 +135,23 @@ module t; if (p_i !== 32'd1234) $stop; if (p_r !== 1.2345) $stop; + code = $value$plusargs("DECIMAL=%d", p_decimal); + `checkd(code, 1); + `checkd(p_decimal, 64'sd300_000_000_000); + code = $value$plusargs("NEGATIVE=%d", p_decimal); + `checkd(code, 1); + `checkd(p_decimal, -64'sd300_000_000_000); + code = $value$plusargs("LEADING=%0d", p_decimal); + `checkd(code, 1); + `checkd(p_decimal, 1_234); + code = $value$plusargs("TRAILING=%d", p_decimal); + `checkd(code, 1); + `checkd(p_decimal, 1_234); + // A matching plusarg returns 1 even when its value contains no digits. + code = $value$plusargs("UNDERSCORE=%d", p_decimal); + `checkd(code, 1); + `checkd(p_decimal, 0); + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_sys_sscanf.v b/test_regress/t/t_sys_sscanf.v index 3d32dd0ca..dd88e62fa 100644 --- a/test_regress/t/t_sys_sscanf.v +++ b/test_regress/t/t_sys_sscanf.v @@ -6,6 +6,7 @@ // verilog_format: off `define stop $stop +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); `define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); `define checks(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); // verilog_format: on @@ -18,6 +19,9 @@ module t; int unsigned idx; logic [XLEN-1:0] val; int code; + longint signed scanned; + real scanned_real; + byte next_char; reg [255:0] line; reg [63:0] token; @@ -49,6 +53,55 @@ module t; code = $sscanf("", "%d", idx); `checkh(code, -1); + // Decimal digit separators, including leading and trailing underscores. + code = $sscanf("10_000_000", "%d", scanned); + `checkd(code, 1); + `checkd(scanned, 10_000_000); + code = $sscanf("-10_000_000", "%d", scanned); + `checkd(code, 1); + `checkd(scanned, -10_000_000); + code = $sscanf("1_234", "%d", idx); + `checkd(code, 1); + `checkd(idx, 1_234); + code = $sscanf("_1_234", "%d", scanned); + `checkd(code, 1); + `checkd(scanned, 1_234); + code = $sscanf("1_234_", "%d", scanned); + `checkd(code, 1); + `checkd(scanned, 1_234); + + // An underscore-only field must not assign a value or count as a conversion. + scanned = 99; + code = $sscanf("_", "%d", scanned); + `checkd(code, -1); + `checkd(scanned, 99); + code = $sscanf("_ ", "%d", scanned); + `checkd(code, 0); + `checkd(scanned, 99); + code = $sscanf("7 _", "%d %d", idx, scanned); + `checkd(code, 1); + `checkd(idx, 7); + `checkd(scanned, 99); + + // IEEE 1800-2023 Table 21-7 excludes underscores from floating-point fields. + // Leave the underscore unread so the following conversion can consume it. + code = $sscanf("1_234.5", "%f%c", scanned_real, next_char); + `checkd(code, 2); + `checkh($realtobits(scanned_real), $realtobits(1.0)); + `checkd(next_char, 8'h5f); + code = $sscanf("1.25_e2", "%e%c", scanned_real, next_char); + `checkd(code, 2); + `checkh($realtobits(scanned_real), $realtobits(1.25)); + `checkd(next_char, 8'h5f); + code = $sscanf("1.25e1_0", "%g%c", scanned_real, next_char); + `checkd(code, 2); + `checkh($realtobits(scanned_real), $realtobits(12.5)); + `checkd(next_char, 8'h5f); + scanned_real = 99.0; + code = $sscanf("_", "%f", scanned_real); + `checkd(code, 0); + `checkh($realtobits(scanned_real), $realtobits(99.0)); + $finish; end