-
Notifications
You must be signed in to change notification settings - Fork 58
Description
sv2v 0.0.13
Yosys 0.54 (git sha1 db72ec3bde296a9512b2d1e6fabf81cfb07c2c1b, g++ 15.1.1 -fPIC -O3)
cat >foo.sv <<-EOF
module foo (
input bit[7:0] arg,
input bit cond,
output bit result
);
always_comb begin
if (cond)
result = '0;
else begin
result = '0;
foreach (arg[i])
result ^= arg[i];
end
end
endmodule
EOF
sv2v --exclude=Always foo.sv >foo.translated.sv
yosys -p 'read_verilog -sv foo.translated.sv; proc'
The last command fails with:
3.8. Executing PROC_DLATCH pass (convert process syncs to latches).
No latch inferred for signal '\foo.\result' from process '\foo.$proc$foo.translated.sv:0$2'.
ERROR: Latch inferred for signal '\foo.\sv2v_autoblock_1.i' from always_comb process '\foo.$proc$foo.translated.sv:0$2'.
The sv2v output in foo.translated.sv
is:
module foo (
arg,
cond,
result
);
input wire [7:0] arg;
input wire cond;
output reg result;
always_comb if (cond)
result = 1'sb0;
else begin
result = 1'sb0;
begin : sv2v_autoblock_1
integer i;
for (i = 7; i >= 0; i = i - 1)
result = result ^ arg[i];
end
end
endmodule
The problem is caused by the integer i;
declaration. yosys would've been accepted it if sv2v had emitted for (integer i = 7; ...
; it just doesn't like when integer i;
is declared separately.
Note this only happens when the foreach
is inside a branch like the else
here. If it was at the top-level yosys is fine. I'm guessing that yosys's behavior is that it lifts the integer i;
declaration to static lifetime, and then notices that it is only assigned definitely in the else
branch, hence infers a latch.
Removing --exclude=Always
makes it work because yosys has no problem inferring a latch inside always @(*)
, though it (correctly) does not generate a latch in the final netlist.
This problem also exists for regular for ($declations; ...
because sv2v moves the declaration outside the loop, eg for (int i = 7; ...
-> reg signed [31:0] i; for (i = 7; ...
, which then trips up yosys in the same way.
I'm a Verilog novice, but if I'm reading the Verilog and SystemVerilog specs correctly:
-
In Verilog, variable declarations are always static lifetime. In SystemVerilog this is still the case for declarations not annotated with
automatic
. So yosys is justified in inferring a latch forinteger i;
-
In SystemVerilog, in a for-loop where the initialization statement declares a variable, eg
for (integer i = ...
, the variable has an automatic lifetime by default. So yosys is justified in not inferring a latch fori
in this case.
I guess the more correct downleveling would be to move the variable declaration to the scope containing the always
block (module / function / task), with hygienic renaming if necessary, and then assign it to 'x
at the start of the always
block?