I've read multiple questions on how to implement an arithmetic shift in Verilog. All suggest using $signed(…) >>> …
.
This works when directly assigning the result to a wire or register, but not when using it as part of a larger expression. That is:
reg[2:0] a = $signed(3'b100) >>> 1 ;
produces3'b110
reg[2:0] a = 1'b1 ? $signed(3'b100) >>> 1 : 3'b000;
produces3'b010
The fix seems to be to wrap the computation into $unsigned
:
reg[2:0] a = $unsigned($signed(3'b100) >>> 1) ;
produces3'b110
reg[2:0] a = 1'b1 ? $unsigned($signed(3'b100) >>> 1) : 3'b000;
produces3'b110
Why does inlining the arithmetic shift cause it to act like a logical one, and why does adding $unsigned
around it fix the issue?
Here is a minimal working example:
module puzzle();
reg [2:0] a_u = 3'b100 >>> 1; // 3'b010
reg [2:0] a_s = $signed(3'b100) >>> 1; // 3'b110
reg [2:0] a_mux = 1'b1 ? $signed(3'b100) >>> 1 : 3'b000; // 3'b010
reg [2:0] b_u = $unsigned(3'b100 >>> 1); // 3'b010
reg [2:0] b_s = $unsigned($signed(3'b100) >>> 1); // 3'b110
reg [2:0] b_mux = 1'b1 ? $unsigned($signed(3'b100) >>> 1) : 3'b000; // 3'b110
initial begin
$display("a_u = 3'b%3b", a_u);
$display("a_s = 3'b%3b", a_s);
$display("a_mux = 3'b%3b", a_mux);
$display("b_u = 3'b%3b", b_u);
$display("b_s = 3'b%3b", b_s);
$display("b_mux = 3'b%3b", b_mux);
end
endmodule
Output:
a_u = 3'b010
a_s = 3'b110
a_mux = 3'b010
b_u = 3'b010
b_s = 3'b110
b_mux = 3'b110