Open WeneneW opened 1 month ago
Is it trying to right shift by a negative value and thereby doing a left shift which will always shift in 0?
Thank you for your reply.
However, after trying to force wire2
to an unsigned conversion, the result after the right shift remains as previously mentioned.
module top (
output wire y,
output wire [2:0] y2,
output wire [2:0] y3,
input wire clk,
input wire wire1
);
assign y3 = $unsigned(8'b10100000 + wire1);
assign y2 = $unsigned(y3 - 1'b1);
assign y = (8'b10011100 >> y2);
endmodule
I can't reproduce this on my machine, please provide a yosys synthesis script.
I can't reproduce this on my machine, please provide a yosys synthesis script.
These are all the files:
rtl.v
: The original design.identity_testbench.v
and yosys_testbench.v
: Two identical test files.syn_yosys.v
: The synthesized code by Yosys.Commands used for synthesis:
yosys
read_verilog rtl.v
synth
write_verilog syn_yosys.v
Other files can be tested using the following commands:
iverilog -o identity_main identity_testbench.v > icarus_stderr_identity.log 2>&1
vvp -n identity_main -lxt2 > vvp_identity.log
iverilog -o yosys_main yosys_testbench.v > icarus_stderr_yosys.log 2>&1
vvp -n yosys_main -lxt2 > vvp_yosys.log
Finally, you can compare the results of vvp_identity.log
and vvp_yosys.log
to observe the differences.
This is a bug in peepopt_shiftadd.pmg
I suspect it's this check that's faulty here:
// if a value of var is able to wrap the output, the transformation might give wrong results
// an addition/substraction can at most flip one more bit than the largest operand (the carry bit)
// as long as the output can show this bit, no wrap should occur (assuming all signed-ness make sense)
select ( GetSize(port(add, \Y)) > max(GetSize(port(add, \A)), GetSize(port(add, \B))) )
A minimized test case for this bug:
module shift(
input wire x,
output wire y
);
wire [1:0] x0 = x - 1'b1;
assign y = 4'b1000 >> x0;
endmodule
with the script
read_verilog test.v
dump
eval -set x 0
peepopt
dump
eval -set x 0
The peephole optimiser tries to optimise A>>B-C into {A,{C{1'b0}}} >> B which is incorrect when the subtraction can overflow. The current check for overflow makes sense for addition but not for subtraction, but I'm not sure what the fix would be.
@phsauter Since you wrote this code, maybe you have a better idea what's going on here :)
Yes thats definitely on me, I need to rethink the checks here:
// checking some value boundaries as well:
// data[...-c +:W1] is fine for +/-var (pad at LSB, all data still accessible)
// data[...+c +:W1] is only fine for +var(add) and var unsigned
// (+c cuts lower C bits, making them inaccessible, a signed var could try to access them)
// either its an add or the variable port is A (it must be positive)
select (add->type.in($add) || varport == \A)
// -> data[var+c +:W1] (with var signed) is illegal
filter !(!offset_negative && varport_signed)
Its possible there are other illegal combinations that aren't covered yet either. Tomorrow I will write out all cases and fix it. Shouldn't be too difficult.
Thanks for spotting this!
Version
Yosys 0.39+165
On which OS did this happen?
Linux
Reproduction Steps
Consider the following code:
y2
has a bit width of3
bits, and when it is3'b111
, the value ofy
should be1
. This means thaty
can take the value1
. However, after synthesis with Yosys, the value ofy
is fixed at1'b0
.The synthesized
syn_yosys.v
is as follows: (Note theassign y = 1'h0;
)The testbench file is as follows:
Expected Behavior
The right shift result is correct.
Actual Behavior
The right shift result is incorrect.