Behavior of Arithmetic Right Shift For Verilog 2001

  • Thread starter Russell Fredrickson
  • Start date
R

Russell Fredrickson

Guest
Hi all,

I'm seeing some mismatching results for a Verilog 2001 arithmetic shift
operator in NCVerilog and since I don't have a Verilog 2001 LRM handy, I
thought I'd ask to experts to see if they knew what the LRM specified in
this regards. I originally found this when we had an RTL/gates simulation
mismatch, but have extracted the problem to the following Verilog code:

module ArithmeticShiftTest;
reg signed [31:0] in;
reg [5:0] shift;
reg signed [31:0] out;

//calculate arithmetic barrel shift right
always@(*) out = in >>> shift;

initial begin
//set up inputs for always block
in = 32'sh80000000;//set to highest value negative number(-2147483648)
shift = 6'd32; //shift the entire width of the word

#1; //allow time for inputs to propagate

//check output
if(out === (32'sh80000000 >>> 6'd32)) begin
$display("PASS: 32'sh80000000 >>> 6'd32 = 0x%h", in, shift, out);
end
else begin
$display("FAIL: 32'sh80000000 >>> 6'd32 != 0x%h,",
(32'sh80000000 >>> 6'd32), " actual = 0x%h.", out);
end
end // initial begin
endmodule // ArithmeticShiftTest

When I simulate with ncverilog (version 5.3-s005) I get the following
message:

FAIL: 32'sh80000000 >>> 6'd32 != 0xffffffff, actual = 0x00000000.

So in other words, the output of the always block is 0x00000000 when I would
expect it to be 0xffffffff (which is what the manual testbench calculation
and the synthesis come out to). Is this a bug in NCVerilog? What does the
Verilog 2001 LRM specify in this regards when the arithmetic shift is
greater or equal to the width of the operand? When one envisions how one
would implement an arithmetic shift in hardware (by left-filling with the
sign bit), I would expect the answer to be 0xffffffff.

Thanks in advance,
Russell
 
Russell Fredrickson wrote:

(snip)

//check output
if(out === (32'sh80000000 >>> 6'd32)) begin
$display("PASS: 32'sh80000000 >>> 6'd32 = 0x%h", in, shift, out);
end
else begin
$display("FAIL: 32'sh80000000 >>> 6'd32 != 0x%h,",
(32'sh80000000 >>> 6'd32), " actual = 0x%h.", out);
end

When I simulate with ncverilog (version 5.3-s005) I get the following
message:

FAIL: 32'sh80000000 >>> 6'd32 != 0xffffffff, actual = 0x00000000.
If you expect 0xffffffff why do you compare to 0x80000000?

So in other words, the output of the always block is 0x00000000 when I would
expect it to be 0xffffffff (which is what the manual testbench calculation
and the synthesis come out to). Is this a bug in NCVerilog? What does the
Verilog 2001 LRM specify in this regards when the arithmetic shift is
greater or equal to the width of the operand? When one envisions how one
would implement an arithmetic shift in hardware (by left-filling with the
sign bit), I would expect the answer to be 0xffffffff.
I only have verilog 95 books, so I can't say for 2001.

For many languages including C and Java, and for most hardware
including x86, a shift greater than or equal to the width of the
word does not perform as you expect. On x86 shift amount are
modulo 32, so 0x80000000 would be expected in that case.

A barrel shifter on 32 bit words could easily only use the low
five bits of the shift amount.

-- glen
 
Russell Fredrickson wrote:
(snip)

I'm not comparing to 0x80000000 but to 0x80000000 arithmetic shifted by 32
(which is surrounded by parenthesis). I did this to illustrate the point
that not only is the result of the calculation of the always block not what
I expect, but that the same expression calculated in different way by the
same simulator yields different results!
Oops, I didn't read carefully enough. Hmmm.

For many languages including C and Java, and for most hardware
including x86, a shift greater than or equal to the width of the
word does not perform as you expect. On x86 shift amount are
modulo 32, so 0x80000000 would be expected in that case.

Good point -- this is in part why I posted this -- since I realize that the
result of shifting greater than or equal to the width may not be what you
think it is. Note that in my case -- since I have 6 bits for the right-hand
side (RHS) operand, I won't get modulo 32 on the shift as you suggest
(though I would get modulo 32 if I only were using a 5-bit RHS operator).
Well, yes, but C and x86 do it with 32 bits. Well, x86 might
use an 8 bit register, but that is still more than 5, and that
is common to many processors.

IBM S/360, S/370, and successors use six bits (modulo 64) for
both 32 bit and 64 bit shift operations, but that is unusual.

The 8086 would actually shift up to 255, the execution time
depended on the shift amount. That was fixed in the 80286 where
the module 32 shift was introduced.

-- glen
 
glen herrmannsfeldt wrote:
Russell Fredrickson wrote:
For many languages including C and Java, and for most hardware
including x86, a shift greater than or equal to the width of the
word does not perform as you expect. On x86 shift amount are
modulo 32, so 0x80000000 would be expected in that case.


Good point -- this is in part why I posted this -- since I realize
that the
result of shifting greater than or equal to the width may not be what you
think it is. Note that in my case -- since I have 6 bits for the
right-hand
side (RHS) operand, I won't get modulo 32 on the shift as you suggest
(though I would get modulo 32 if I only were using a 5-bit RHS operator).


Well, yes, but C and x86 do it with 32 bits. Well, x86 might use an 8
bit register, but that is still more than 5, and that is common to many
processors.

IBM S/360, S/370, and successors use six bits (modulo 64) for both 32
bit and 64 bit shift operations, but that is unusual.

The 8086 would actually shift up to 255, the execution time
depended on the shift amount. That was fixed in the 80286 where
the module 32 shift was introduced.

Quoting from verilog 2001 LRM

Copyright Š 2001 IEEE. All rights reserved. 49

The right shift operators, >> and >>>, shall shift their left operand to
the right by the number of bit positions given by the right operand. The
logical right shift shall fill the vacated bit positions with IEEE Std
1364-2001 Version C IEEE STANDARD VERILOGŽ zeroes. The arithmetic right
shift shall fill the vacated bit positions with zeroes if the result
type is unsigned. It shall fill the vacated bit positions with the value
of the most-significant (i.e., sign) bit of the left operand if the
result type is signed. If the right operand has an unknown or high
impedance value, then the result shall be unknown. The right operand is
always treated as an unsigned number and has no effect on the signedness
of the result. The result signedness is determined by the left-hand
operand and the remainder of the expression, as outlined in 4.5.1.

Clearly, machine archetecture has nothing to do with the result of the
shift.

Jason
 
Jason Zheng wrote:

(snip)

Quoting from verilog 2001 LRM

Copyright Š 2001 IEEE. All rights reserved. 49

The right shift operators, >> and >>>, shall shift their left operand to
the right by the number of bit positions given by the right operand. The
logical right shift shall fill the vacated bit positions with IEEE Std
1364-2001 Version C IEEE STANDARD VERILOGŽ zeroes. The arithmetic right
shift shall fill the vacated bit positions with zeroes if the result
type is unsigned. It shall fill the vacated bit positions with the value
of the most-significant (i.e., sign) bit of the left operand if the
result type is signed. If the right operand has an unknown or high
impedance value, then the result shall be unknown. The right operand is
always treated as an unsigned number and has no effect on the signedness
of the result. The result signedness is determined by the left-hand
operand and the remainder of the expression, as outlined in 4.5.1.
That sounds reasonably convincing.

The "Verilog 2001: What's New" that I could find on the web only
gave 3 as a shift value for the example.

-- glen
 

Welcome to EDABoard.com

Sponsor

Back
Top