From 9ba625225d768c23492e03efd2301b3eb7eae52e Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 8 Feb 2026 17:54:04 -0500 Subject: [PATCH] Internals: Minor cleanups preparing for initialization fixes. No functional change. --- src/V3Width.cpp | 18 +- test_regress/t/t_assigndly_dynamic.v | 88 +++---- test_regress/t/t_fork_dynscope.v | 30 +-- test_regress/t/t_process_fork_block.v | 34 +-- test_regress/t/t_randomize_inline_var_ctl.v | 248 +++++++++--------- .../t/t_var_static_assign_decl_bad.out | 70 ++--- test_regress/t/t_var_static_assign_decl_bad.v | 6 +- 7 files changed, 250 insertions(+), 244 deletions(-) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 02e7836e9..ad8607d69 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -5495,6 +5495,16 @@ class WidthVisitor final : public VNVisitor { } } + bool firstNewStatementOkRecurse(AstNode* nodep) { + if (AstVar* const varp = VN_CAST(nodep, Var)) { + if (!varp->valuep() || VN_CAST(varp->valuep(), Const) || varp->isIO()) return true; + } + if (AstAssign* const aitemp = VN_CAST(nodep, Assign)) { + if (VN_IS(aitemp->rhsp(), Const) || VN_IS(aitemp->rhsp(), CReset)) return true; + } + return false; + } + //-------------------- // Top levels @@ -6510,13 +6520,7 @@ class WidthVisitor final : public VNVisitor { } continue; } - if (AstVar* const varp = VN_CAST(itemp, Var)) { - if (!varp->valuep() || VN_CAST(varp->valuep(), Const) || varp->isIO()) - continue; - } - if (AstAssign* const aitemp = VN_CAST(itemp, Assign)) { - if (VN_IS(aitemp->rhsp(), Const)) continue; - } + if (firstNewStatementOkRecurse(itemp)) continue; firstp = itemp; } } diff --git a/test_regress/t/t_assigndly_dynamic.v b/test_regress/t/t_assigndly_dynamic.v index 261ee1b45..f1fac2ecf 100644 --- a/test_regress/t/t_assigndly_dynamic.v +++ b/test_regress/t/t_assigndly_dynamic.v @@ -15,56 +15,56 @@ `endif class nba_waiter; - // Task taken from UVM - task wait_for_nba_region; - static int nba; - int next_nba; - next_nba++; - nba <= `DELAY next_nba; - @(nba); - endtask + // Task taken from UVM + task wait_for_nba_region; + static int nba; + int next_nba; + next_nba++; + nba <= `DELAY next_nba; + @(nba); + endtask endclass class Foo; - task bar(logic a, logic b); - static int x; - static int y; - // bar's local vars and intravals could be overwritten by other locals - if (a) x <= `DELAY 'hDEAD; - if (b) y <= `DELAY 'hBEEF; - #2 - if (x != 'hDEAD) $stop; - endtask + task bar(logic a, logic b); + static int x; + static int y; + // bar's local vars and intravals could be overwritten by other locals + if (a) x <= `DELAY 'hDEAD; + if (b) y <= `DELAY 'hBEEF; + #2; + if (x != 'hDEAD) $stop; + endtask endclass module t; - nba_waiter waiter = new; - Foo foo = new; - event e; - int cnt = 0; + nba_waiter waiter = new; + Foo foo = new; + event e; + int cnt = 0; - initial begin - #1 ->e; - if (cnt != 0) $stop; - cnt++; - waiter.wait_for_nba_region; - ->e; - if (cnt != 2) $stop; - if ($time != `TIME_AFTER_FIRST_WAIT) $stop; - cnt++; - waiter.wait_for_nba_region; - if (cnt != 4) $stop; - if ($time != `TIME_AFTER_SECOND_WAIT) $stop; - foo.bar(1, 1); - #2 - $write("*-* All Finished *-*\n"); - $finish; - end + initial begin + #1 ->e; + if (cnt != 0) $stop; + cnt++; + waiter.wait_for_nba_region; + ->e; + if (cnt != 2) $stop; + if ($time != `TIME_AFTER_FIRST_WAIT) $stop; + cnt++; + waiter.wait_for_nba_region; + if (cnt != 4) $stop; + if ($time != `TIME_AFTER_SECOND_WAIT) $stop; + foo.bar(1, 1); + #2; + $write("*-* All Finished *-*\n"); + $finish; + end - initial begin - @e if (cnt != 1) $stop; - cnt++; - @e if (cnt != 3) $stop; - cnt++; - end + initial begin + @e if (cnt != 1) $stop; + cnt++; + @e if (cnt != 3) $stop; + cnt++; + end endmodule diff --git a/test_regress/t/t_fork_dynscope.v b/test_regress/t/t_fork_dynscope.v index 62d919e6b..64c36dfb1 100644 --- a/test_regress/t/t_fork_dynscope.v +++ b/test_regress/t/t_fork_dynscope.v @@ -8,44 +8,44 @@ class Foo; task do_something(int arg_v); int dynscope_var; int x; - dynscope_var = 0; + if (dynscope_var != 0) $stop; + dynscope_var = 10; + if (dynscope_var != 10) $stop; fork #10 begin x = 0; // Test capturing a variable that needs to be modified - $display("Incremented dynscope_var: %d", ++dynscope_var); - if (dynscope_var != 1) - $stop; + if (dynscope_var != 10) $stop; + $display("Incremented dynscope_var: %0d", ++dynscope_var); + if (dynscope_var != 11) $stop; // Check nested access fork #10 begin - $display("Incremented x: %d", ++x); - $display("Incremented dynscope_var: %d", ++dynscope_var); - if (dynscope_var != 2) - $stop; + $display("Incremented x: %0d", ++x); + $display("Incremented dynscope_var: %0d", ++dynscope_var); + if (dynscope_var != 12) $stop; end join_none end #10 begin // Same as the first check, but with an argument // (so it needs to be copied to the dynamic scope instead of being moved there) - $display("Incremented arg_v: %d", ++arg_v); - if (arg_v != 2) - $stop; + if (arg_v != 1) $stop; + $display("Incremented arg_v: %0d", ++arg_v); + if (arg_v != 2) $stop; end join_none // Check if regular access to arg_v has been substituted with access to its copy from // a dynamic scope - $display("Incremented arg_v: %d", ++arg_v); - if (arg_v != 1) - $stop; + $display("Incremented arg_v: %0d", ++arg_v); + if (arg_v != 1) $stop; endtask endclass -module t(); +module t; initial begin Foo foo; foo = new; diff --git a/test_regress/t/t_process_fork_block.v b/test_regress/t/t_process_fork_block.v index 97cc73ebe..6bf216615 100644 --- a/test_regress/t/t_process_fork_block.v +++ b/test_regress/t/t_process_fork_block.v @@ -5,22 +5,22 @@ // SPDX-License-Identifier: CC0-1.0 module t; - process job; + process job; - initial begin - process p1 = process::self(); - fork - begin - wait(p1.status() != process::RUNNING); - $write("job started\n"); - job = process::self(); - end - join_none - wait (job); - $write("all jobs started\n"); - job.await(); - $write("all jobs finished\n"); - $write("*-* All Finished *-*\n"); - $finish; - end + initial begin + automatic process p1 = process::self(); + fork + begin + wait (p1.status() != process::RUNNING); + $write("job started\n"); + job = process::self(); + end + join_none + wait (job); + $write("all jobs started\n"); + job.await(); + $write("all jobs finished\n"); + $write("*-* All Finished *-*\n"); + $finish; + end endmodule diff --git a/test_regress/t/t_randomize_inline_var_ctl.v b/test_regress/t/t_randomize_inline_var_ctl.v index 4a1bf977a..3a5cf0a72 100644 --- a/test_regress/t/t_randomize_inline_var_ctl.v +++ b/test_regress/t/t_randomize_inline_var_ctl.v @@ -5,152 +5,152 @@ // SPDX-License-Identifier: CC0-1.0 class Foo; - rand int zero; - int two; + rand int zero; + int two; endclass class Bar extends Foo; - rand int one; - static int three; + rand int one; + static int three; - function void test; - logic[1:0] ok = '0; - zero = 100; - one = 200; - two = 300; - three = 400; - for (int i = 0; i < 20; i++) begin - void'(randomize(one)); - if (zero != 100) $stop; - if (one != 200) ok[0] = 1; - if (two != 300) $stop; - if (three != 400) $stop; - end - if (!ok[0]) $stop; - ok = '0; + function void test; + logic [1:0] ok = '0; + zero = 100; + one = 200; + two = 300; + three = 400; + for (int i = 0; i < 20; i++) begin + void'(randomize(one)); + if (zero != 100) $stop; + if (one != 200) ok[0] = 1; + if (two != 300) $stop; + if (three != 400) $stop; + end + if (!ok[0]) $stop; + ok = '0; - if (zero.rand_mode() != 1) $stop; - if (one.rand_mode() != 1) $stop; - zero = 500; - one = 600; - two = 700; - three = 800; - one.rand_mode(0); - for (int i = 0; i < 20; i++) begin - void'(randomize(one, two)); - if (zero != 500) $stop; - if (one != 600) ok[0] = 1; - if (two != 700) ok[1] = 1; - if (three != 800) $stop; - end - if (one.rand_mode() != 0) $stop; - one.rand_mode(1); - if (ok != 'b11) $stop; - endfunction + if (zero.rand_mode() != 1) $stop; + if (one.rand_mode() != 1) $stop; + zero = 500; + one = 600; + two = 700; + three = 800; + one.rand_mode(0); + for (int i = 0; i < 20; i++) begin + void'(randomize(one, two)); + if (zero != 500) $stop; + if (one != 600) ok[0] = 1; + if (two != 700) ok[1] = 1; + if (three != 800) $stop; + end + if (one.rand_mode() != 0) $stop; + one.rand_mode(1); + if (ok != 'b11) $stop; + endfunction endclass class Baz; - int four; - Bar bar; + int four; + Bar bar; - function new; - bar = new; - endfunction + function new; + bar = new; + endfunction endclass class Qux; - Baz baz; + Baz baz; - function new; - baz = new; - endfunction + function new; + baz = new; + endfunction endclass class Boo extends Bar; - rand int five; + rand int five; endclass module t; - initial begin - Boo boo = new; - Bar bar = boo; - Qux qux = new; - logic[2:0] ok = '0; + initial begin + automatic Boo boo = new; + automatic Bar bar = boo; + automatic Qux qux = new; + automatic logic [2:0] ok = '0; - bar.test; + bar.test; - bar.zero = 1000; - bar.one = 2000; - bar.two = 3000; - bar.three = 4000; - boo.five = 999999; - for (int i = 0; i < 20; i++) begin - int res = bar.randomize(two); - if (boo.five != 999999) $stop; - end + bar.zero = 1000; + bar.one = 2000; + bar.two = 3000; + bar.three = 4000; + boo.five = 999999; + for (int i = 0; i < 20; i++) begin + automatic int res = bar.randomize(two); + if (boo.five != 999999) $stop; + end - bar.zero = 1000; - bar.one = 2000; - bar.two = 3000; - bar.three = 4000; - boo.five = 999999; - for (int i = 0; i < 20; i++) begin - int res = bar.randomize(two) with { two > 3000 && two < 4000; }; - if (bar.zero != 1000) $stop; - if (bar.one != 2000) $stop; - if (!(bar.two > 3000 && bar.two < 4000)) $stop; - if (bar.three != 4000) $stop; - if (boo.five != 999999) $stop; - end + bar.zero = 1000; + bar.one = 2000; + bar.two = 3000; + bar.three = 4000; + boo.five = 999999; + for (int i = 0; i < 20; i++) begin + automatic int res = bar.randomize(two) with {two > 3000 && two < 4000;}; + if (bar.zero != 1000) $stop; + if (bar.one != 2000) $stop; + if (!(bar.two > 3000 && bar.two < 4000)) $stop; + if (bar.three != 4000) $stop; + if (boo.five != 999999) $stop; + end - qux.baz.bar.zero = 5000; - qux.baz.bar.one = 6000; - qux.baz.bar.two = 7000; - qux.baz.bar.three = 8000; - qux.baz.four = 9000; - for (int i = 0; i < 20; i++) begin - void'(qux.randomize(baz)); - if (qux.baz.bar.zero != 5000) $stop; - if (qux.baz.bar.one != 6000) $stop; - if (qux.baz.bar.two != 7000) $stop; - if (qux.baz.bar.three != 8000) $stop; - if (qux.baz.four != 9000) $stop; - end - for (int i = 0; i < 20; i++) begin - void'(qux.randomize(baz.bar)); - if (qux.baz.bar.zero != 5000) ok[0] = 1; - if (qux.baz.bar.one != 6000) ok[1] = 1; - if (qux.baz.bar.two != 7000) $stop; - if (qux.baz.bar.three != 8000) $stop; - if (qux.baz.four != 9000) $stop; - end - if (!ok[0]) $stop; - if (!ok[1]) $stop; - ok = '0; - qux.baz.bar.zero = 10000; - qux.baz.bar.one = 20000; - for (int i = 0; i < 20; i++) begin - void'(qux.randomize(baz.four)); - if (qux.baz.bar.zero != 10000) $stop; - if (qux.baz.bar.one != 20000) $stop; - if (qux.baz.bar.two != 7000) $stop; - if (qux.baz.bar.three != 8000) $stop; - if (qux.baz.four != 9000) ok[0] = 1; - end - if (!ok[0]) $stop; - ok = '0; - qux.baz.four = 30000; - for (int i = 0; i < 20; i++) begin - void'(qux.randomize(baz.bar, qux.baz.bar.one, baz.four)); - if (qux.baz.bar.zero != 10000) ok[0] = 1; - if (qux.baz.bar.one != 20000) ok[1] = 1; - if (qux.baz.bar.two != 7000) $stop; - if (qux.baz.bar.three != 8000) $stop; - if (qux.baz.four != 30000) ok[2] = 1; - end - if (ok != 'b111) $stop; + qux.baz.bar.zero = 5000; + qux.baz.bar.one = 6000; + qux.baz.bar.two = 7000; + qux.baz.bar.three = 8000; + qux.baz.four = 9000; + for (int i = 0; i < 20; i++) begin + void'(qux.randomize(baz)); + if (qux.baz.bar.zero != 5000) $stop; + if (qux.baz.bar.one != 6000) $stop; + if (qux.baz.bar.two != 7000) $stop; + if (qux.baz.bar.three != 8000) $stop; + if (qux.baz.four != 9000) $stop; + end + for (int i = 0; i < 20; i++) begin + void'(qux.randomize(baz.bar)); + if (qux.baz.bar.zero != 5000) ok[0] = 1; + if (qux.baz.bar.one != 6000) ok[1] = 1; + if (qux.baz.bar.two != 7000) $stop; + if (qux.baz.bar.three != 8000) $stop; + if (qux.baz.four != 9000) $stop; + end + if (!ok[0]) $stop; + if (!ok[1]) $stop; + ok = '0; + qux.baz.bar.zero = 10000; + qux.baz.bar.one = 20000; + for (int i = 0; i < 20; i++) begin + void'(qux.randomize(baz.four)); + if (qux.baz.bar.zero != 10000) $stop; + if (qux.baz.bar.one != 20000) $stop; + if (qux.baz.bar.two != 7000) $stop; + if (qux.baz.bar.three != 8000) $stop; + if (qux.baz.four != 9000) ok[0] = 1; + end + if (!ok[0]) $stop; + ok = '0; + qux.baz.four = 30000; + for (int i = 0; i < 20; i++) begin + void'(qux.randomize(baz.bar, qux.baz.bar.one, baz.four)); + if (qux.baz.bar.zero != 10000) ok[0] = 1; + if (qux.baz.bar.one != 20000) ok[1] = 1; + if (qux.baz.bar.two != 7000) $stop; + if (qux.baz.bar.three != 8000) $stop; + if (qux.baz.four != 30000) ok[2] = 1; + end + if (ok != 'b111) $stop; - $write("*-* All Finished *-*\n"); - $finish; - end + $write("*-* All Finished *-*\n"); + $finish; + end endmodule diff --git a/test_regress/t/t_var_static_assign_decl_bad.out b/test_regress/t/t_var_static_assign_decl_bad.out index cd0e9d02c..d44e94c57 100644 --- a/test_regress/t/t_var_static_assign_decl_bad.out +++ b/test_regress/t/t_var_static_assign_decl_bad.out @@ -1,71 +1,71 @@ -%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:101:17: Static variable initializer +%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:103:17: Static variable initializer : is dependent on function/task I/O variable - 101 | logic tmp = in; + 103 | logic tmp = in; | ^~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:106:17: Static variable initializer +%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:108:17: Static variable initializer : is dependent on function/task I/O variable - 106 | logic tmp = in; + 108 | logic tmp = in; | ^~ -%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:111:24: Static variable initializer +%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:113:24: Static variable initializer : is dependent on function/task I/O variable - 111 | static logic tmp = in; + 113 | static logic tmp = in; | ^~ -%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:116:17: Static variable initializer +%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:118:17: Static variable initializer : is dependent on function/task I/O variable - 116 | logic tmp = out; + 118 | logic tmp = out; | ^~~ -%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:121:20: Static variable initializer +%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:123:20: Static variable initializer : is dependent on function/task I/O variable - 121 | logic tmp = in + 1; + 123 | logic tmp = in + 1; | ^ -%Error: t/t_var_static_assign_decl_bad.v:126:26: Static variable initializer +%Error: t/t_var_static_assign_decl_bad.v:128:26: Static variable initializer : is dependent on automatic variable - 126 | static int foo = tmp + 1; + 128 | static int foo = tmp + 1; | ^ ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. -%Error: t/t_var_static_assign_decl_bad.v:132:26: Static variable initializer +%Error: t/t_var_static_assign_decl_bad.v:134:26: Static variable initializer : is dependent on automatic variable - 132 | static int foo = tmp + 1; + 134 | static int foo = tmp + 1; | ^ -%Error: t/t_var_static_assign_decl_bad.v:138:29: Static variable initializer +%Error: t/t_var_static_assign_decl_bad.v:140:29: Static variable initializer : is dependent on automatic variable - 138 | static logic func_var = loc; + 140 | static logic func_var = loc; | ^~~ -%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:9:15: Static variable initializer - : is dependent on function/task I/O variable - 9 | logic tmp = in; +%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:11:15: Static variable initializer + : is dependent on function/task I/O variable + 11 | logic tmp = in; | ^~ -%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:14:15: Static variable initializer +%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:16:15: Static variable initializer : is dependent on function/task I/O variable - 14 | logic tmp = in; + 16 | logic tmp = in; | ^~ -%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:20:17: Static variable initializer +%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:22:17: Static variable initializer : is dependent on function/task I/O variable - 20 | logic tmp = in; + 22 | logic tmp = in; | ^~ -%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:25:17: Static variable initializer +%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:27:17: Static variable initializer : is dependent on function/task I/O variable - 25 | logic tmp = in; + 27 | logic tmp = in; | ^~ -%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:32:17: Static variable initializer +%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:34:17: Static variable initializer : is dependent on function/task I/O variable - 32 | logic tmp = in; + 34 | logic tmp = in; | ^~ -%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:37:17: Static variable initializer +%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:39:17: Static variable initializer : is dependent on function/task I/O variable - 37 | logic tmp = in; + 39 | logic tmp = in; | ^~ -%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:44:17: Static variable initializer +%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:46:17: Static variable initializer : is dependent on function/task I/O variable - 44 | logic tmp = in; + 46 | logic tmp = in; | ^~ -%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:49:17: Static variable initializer +%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:51:17: Static variable initializer : is dependent on function/task I/O variable - 49 | logic tmp = in; + 51 | logic tmp = in; | ^~ -%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:72:17: Static variable initializer +%Error-UNSUPPORTED: t/t_var_static_assign_decl_bad.v:74:17: Static variable initializer : is dependent on function/task I/O variable - 72 | logic tmp = in; + 74 | logic tmp = in; | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_var_static_assign_decl_bad.v b/test_regress/t/t_var_static_assign_decl_bad.v index 7b1b07771..b186c850a 100644 --- a/test_regress/t/t_var_static_assign_decl_bad.v +++ b/test_regress/t/t_var_static_assign_decl_bad.v @@ -4,6 +4,8 @@ // SPDX-FileCopyrightText: 2024 Antmicro // SPDX-License-Identifier: CC0-1.0 +// verilator lint_off NORETURN + function static func_stat; input logic in; logic tmp = in; @@ -63,8 +65,8 @@ module no_warn#(PARAM = 1)(input in, input clk); // Do not warn on constant assignments. function static func_param; - static logic func_var = PARAM; - static logic func_enum = A; + static bit func_var = PARAM != 0; + static bit func_enum = A != B; endfunction // Do not warn on assignment referencing module I/O.