f



Behavior of Arithmetic Right Shift For Verilog 2001

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




0
Russell
1/18/2005 11:37:27 PM
comp.lang.verilog 3837 articles. 2 followers. Post Follow

9 Replies
547 Views

Similar Articles

[PageSpeed] 48

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

0
glen
1/19/2005 12:00:57 AM
"glen herrmannsfeldt" <gah@ugcs.caltech.edu> wrote in message
news:csk7uf$fj0$1@gnus01.u.washington.edu...
> 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?

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!

> 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).

Thanks,
Russell


0
Russell
1/19/2005 12:47:56 AM
Russell Fredrickson wrote:
> Hi all,
> 
>     I'm seeing some mismatching results for a Verilog 2001 arithmetic shift
> 
> 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


Russel,

I ran your code through gplcver and it passed. Could it be a ncverilog 
glitch?
0
Jason
1/19/2005 1:04:00 AM
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

0
glen
1/19/2005 1:10:16 AM
Jason Zheng wrote:
> Russell Fredrickson wrote:
> 
>> Hi all,
>>
>>     I'm seeing some mismatching results for a Verilog 2001 arithmetic 
>> shift
>>
>> 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
> 
> 
> 
> Russel,
> 
> I ran your code through gplcver and it passed. Could it be a ncverilog 
> glitch?

This is the simulator output:

GPLCVER_2.10a of 10/12/04 (Sparc-Solaris).
Copyright (c) 1991-2004 Pragmatic C Software Corp.
   All Rights reserved.  Licensed under the GNU General Public License 
(GPL).
   See the 'COPYING' file for details.  NO WARRANTY provided.
Today is Tue Jan 18 17:09:16 2005.
Compiling source file "shift_test.v"
Highest level modules:
ArithmeticShiftTest

PASS: 80000000 >>> 32 = 0xffffffff
0 simulation events and 0 declarative immediate assigns processed.
8 behavioral statements executed (4 procedural suspends).
   Times (in sec.):  Translate 0.0, load/optimize 0.1, simulation 0.1.
End of GPLCVER_2.10a at Tue Jan 18 17:09:16 2005 (elapsed 0.0 seconds).

Compilation finished at Tue Jan 18 17:09:16

I got similar results on ncverilog (5.10), however.

- Jason
0
Jason
1/19/2005 1:12:15 AM
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
0
Jason
1/19/2005 1:25:32 AM
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

0
glen
1/19/2005 2:19:36 AM
I ran you code in latest version of modelsim ie 6.0 and it ran fine,
got the message as :
PASS: 32'sh80000000 >>> 6'd32 = 0x8000000032         -1
I think it should work as you expected.

-Neo

0
zingafriend
1/19/2005 9:35:00 AM
Thanks everyone for looking at this!  I started to file a bug report with
Cadence on this and in the process I was pointed to a solution that
mentioned that they knew about this issue and it is fixed in a later service
release of the NCVerilog than I am using.

Thanks again!
Russell


0
Russell
1/19/2005 7:33:30 PM
Reply: