Fix compile error on bitstream with inline typecast
module foo;
initial begin
automatic reg [2:0] foo0 [1:0] = '{0, 0};
$display("foo0 %p -> %b", foo0, |type(logic [$bits(foo0)-1:0])'({>>{foo0}}));
$finish();
end
endmodule
Saving above code into foo.sv running verilator --lint-only foo.sv --debug causes this error output:
export VERILATOR_ROOT='/usr/local/share/verilator'
Starting Verilator 5.040 2025-08-30 rev v5.040
- Verilator.cpp:657: Option --verilate: Start Verilation
[...]
- V3Dead.cpp:567: deadifyDTypes:
- V3Ast.cpp:1378: Dumping obj_dir/Vverilator_bug_macro_or_reduce_033_deadDtypes.tree
%Error: Internal Error: foo.sv:4:72: ../V3Broken.cpp:173: Broken link in node->dtypep() to 0x55555702dd40
-node: STREAMR 0x5555570274a0 <e1134> {e4cu} @dt=0x55555702dd40@(G/w6)
4 | $display("foo0 %p -> %b", foo0, |type(logic [$bits(foo0)-1:0])'({>>{foo0}}));
| ^~
... See the manual at https://verilator.org/verilator_doc.html?v=5.040 for more assistance.
- V3Ast.cpp:1378: Dumping obj_dir/Vverilator_bug_macro_or_reduce_990_final.tree
- V3StatsReport.cpp:233:statsReport:
%Error: Internal Error: Aborting since under --debug
%Error: export VERILATOR_ROOT=/usr/local/share/verilator
%Error: ulimit -s unlimited 2>/dev/null; exec setarch --addr-no-randomize /usr/local/bin/verilator_bin_dbg --lint-only foo.sv --debug
%Error: Command Failed ulimit -s unlimited 2>/dev/null; exec setarch --addr-no-randomize /usr/local/bin/verilator_bin_dbg --lint-only foo.sv --debug
Tested on Ubuntu and verilator v5.040. (It passes on v5.012)
In contrast, linting this code with --debug is no problem:
module foo;
wire [5:0] bar;
initial begin
automatic reg [2:0] foo0 [1:0] = '{0, 0};
$display("foo0 %p -> %b", foo0, |type(bar)'({>>{foo0}}));
$finish();
end
endmodule
I noticed this when similar code crashed with
%Error: Verilator internal fault, sorry. Suggest trying --debug --gdbbt
%Error: Command Failed ulimit -s unlimited 2>/dev/null; exec /usr/local/bin/verilator_bin --lint-only /home/david/tmp/verilator_bug_macro_or_reduce.sv
or when trying to add --debug to try and figure out why the below code example, which usually takes 0.005 s to lint, sometimes takes up to 24 seconds(!) to lint. (something like every ~4th time)
module foo;
initial begin
automatic reg [2:0] foo0 [1:0] = '{0, 0};
automatic reg [2:0] foo1 [1:0] = '{0, 1};
automatic reg [2:0] foo2 [1:0] = '{0, 2};
automatic reg [2:0] foo3 [1:0] = '{0, 3};
automatic reg [2:0] foo4 [1:0] = '{1, 0};
automatic reg [2:0] foo5 [1:0] = '{2, 0};
automatic reg [2:0] foo6 [1:0] = '{3, 0};
$display("foo0 %p -> %b", foo0, |type(logic [$bits(foo0)-1:0])'({>>{foo0}}));
$display("foo1 %p -> %b", foo1, |type(logic [$bits(foo1)-1:0])'({>>{foo1}}));
$display("foo2 %p -> %b", foo2, |type(logic [$bits(foo2)-1:0])'({>>{foo2}}));
$display("foo3 %p -> %b", foo3, |type(logic [$bits(foo3)-1:0])'({>>{foo3}}));
$display("foo4 %p -> %b", foo4, |type(logic [$bits(foo4)-1:0])'({>>{foo4}}));
$display("foo5 %p -> %b", foo5, |type(logic [$bits(foo5)-1:0])'({>>{foo5}}));
$display("foo6 %p -> %b", foo6, |type(logic [$bits(foo6)-1:0])'({>>{foo6}}));
$finish();
end
`define OR_REDUCE(s) |type(logic [$bits(s)-1:0])'({>>{s}})
let or_reduce_let(s) = |type(logic [$bits(s)-1:0])'({>>{s}});
initial begin
automatic reg [2:0] bar0 [1:0] = '{0, 0};
automatic reg [2:0] bar1 [1:0] = '{0, 1};
automatic reg [2:0] bar2 [1:0] = '{0, 2};
automatic reg [2:0] bar3 [1:0] = '{0, 3};
automatic reg [2:0] bar4 [1:0] = '{1, 0};
automatic reg [2:0] bar5 [1:0] = '{2, 0};
automatic reg [2:0] bar6 [1:0] = '{3, 0};
$display("bar0 %p -> %b", bar0, `OR_REDUCE(bar0));
$display("bar1 %p -> %b", bar1, or_reduce_let(bar1));
$display("bar2 %p -> %b", bar2, `OR_REDUCE(bar2));
$display("bar3 %p -> %b", bar3, `OR_REDUCE(bar3));
$display("bar4 %p -> %b", bar4, `OR_REDUCE(bar4));
$display("bar5 %p -> %b", bar5, `OR_REDUCE(bar5));
$display("bar6 %p -> %b", bar6, `OR_REDUCE(bar6));
$finish();
end
endmodule
If the time is random then sounds there's at least two bugs here:
-
The functional problem of the bitstream
-
Why the behavior is non-determistic. We shouldn't depend in any performance or output way on address layout in any algorithms but seems from this we are. Comment out
aslr_offin bin/verilator, then use--debugto make a obj_dir of both the slow and fast version. Hopefully you will then see a difference in the tree files (you can useverilator_difftree) that suggests the problem, if not gdb through to see where the time is.
Could you continue to debug into this and see if you can identify the problems?
If you update to master you can now use --aslr --debug to force use of ASLR even when under debug.
Interesting enough adding an unused wire to the first crashing example avoids the crash iff the range of that wire is exactly [5:0]:
module foo;
wire [5:0] x;
initial begin
automatic reg [2:0] foo0 [1:0] = '{0, 0};
$display("foo0 %p -> %b", foo0, |type(logic [$bits(foo0)-1:0])'({>>{foo0}}));
$finish();
end
endmodule
When trying to lint the long example on my personal laptop I got this on 5.040:
$ verilator --lint-only bar.sv
%Error: Verilator threw signal 9. Suggest trying --debug --gdbbt
%Error: Command Failed ulimit -s unlimited 2>/dev/null; exec /usr/local/bin/verilator_bin --lint-only bar.sv
and on master (5.041) I get the "internal fault" no matter if I run with --aslr or not
The crash is fixed, however the specific streaming fails now at GCC compile time due to other issues, see test_regress/t/t_stream_type.py. Perhaps you'd be willing to look at a pull to fix this?