Verliog: Different Outputs when using an intermediate variable for Arithmetic Shift - verilog

Why is out1 any different from out2
module diff_outputs(in,out1,out2);
input in;
output out1,out2,out3;
wire [8:0] in, out1, out2;
wire [8:0] interm;
assign out1 = in>>>4 + in[3];
assign interm = in>>>4;
assign out2 = interm + in[3];
endmodule
out1 and out2 are the same for positive inputs. But for negative inputs, out1 is positive while out2 is negative (so effectively the shift operator in out1 is performing a logical shift)

The difference is caused by the way that Verilog deals with unsigned and signed arithmetic. Verilog is very liberal, but because of that you need to be familiar with the detail of how it works. 3 such details relevant to this case are:
part selects are always unsigned
and
unbased integer literals are signed
and
if you mix signed and unsigned values, unsigned arithmetic is done
So, with this expression
assign out1 = (in>>>4) + in[3];
in[3] is a part select and so is unsigned. Therefore, unsigned arithmetic is used for the whole expression and so a logical shift is used. (With a logical shift right, zeros are added from the left.) If however, you split this into two expressions:
assign interm = in>>>4;
assign out2 = interm + in[3];
then signed arithmetic is used for the first expression (because both in and 4 are signed), so an arithmetic shift is used. (With an arithmetic shift right, the left hand bit is _sign_extended_, so in this case ones are added from the left.) The second expression is a mixed of signed (interm) and unsigned (in[3]), so unsigned arithmetic is used (as before).
So, when you do everything is one expression there is a mix of unsigned and signed, so unsigned arithmetic is used and so a logical shift right is done. However, when you use two expressions the expression for the shift is purely signed, so signed arithmetic is used and so an arithmetic shift right is done.
You'll find this
assign out3 = $signed(in>>>4) + in[3];
behaves the same way as the two-expression case, because the $signed() system function forces an arithmetic shift to be done.
https://www.edaplayground.com/x/6CGk

Related

Applying Modulo To a Negative Number In Verilog

In general math and software programming, -4 mod 5 = 1. But in Verilog, the answer turns out to be 2. The reason for this seems to be because of division happening in binary. How do I properly handle this calculation? Following is a Verilog code that reproduces this behaviour.
module test (a,b,c);
input [0:3]a,b;
output [0:3]c;
assign a = -4'd4;
assign b = 4'd5;
assign c = a%b;
endmodule
Your code does % operation on unsigned data. In this scheme -4 is just the same as 12 unsigned and the result of modulo is 2.
You need to use signed data as in here:
module test (
input signed [0:3]a,b, // <<<< signed
output signed [0:3]c // <<<< signed
):
assign a = -4'd4;
assign b = 4'd5;
assign c = a%b;
always #*
$display(a,b,c);
endmodule
And the result is -4, as expected from general programming rules.
You didn’t declare the variables as signed, so they are treated as unsigned. -4’d4 is being interpreted as it’s 2’s complement 4’b12 (~4’b0100 + 1’b1 == 4’b1100)
You need to add the signed keyword to the signal definition.
module test;
wire signed [3:0] a,b,c;
assign a = -4'd4;
assign b = 4'd5;
assign c = a%b;
endmodule

Casting wire vector to integer in verilog

In an example like this
function module(
input [3:0] in
output out);
for(integer i = in; i < in+10; i += 1) begin
// do stuff
end
endfunction
How would in be cast to i?
From what I understand an integer is a 32-bit bit vector, interpreted in 2's complement.
So does verilog pad the bit vector with 28{in[3]}?
From LRM
If needed, extend the size of the right-hand side, performing sign extension if, and only if, the type of the right-hand side is signed.
So, in your case i will be padded with '0', not with in[3], because in is not signed.
To do sign extension, you will need to make in signed: input signed [3:0] in;

Signed binary multiplication and signed binary division

What is the difference between the result of the multiplication when multiplying two unsigned numbers vs multiplying two signed numbers?
What is the difference between the remainder and quotient when dividing two signed numbers vs dividing two unsigned numbers?
An example may be illuminating.
module top;
reg [3:0] a;
reg [3:0] b;
reg [7:0] r1;
reg [7:0] r2;
initial begin
a = 4'hc;
b = 4'h5;
r1 = a * b; // 12 * 5
r2 = $signed(a) * $signed(b); //-4 * 5
$display("r1 = %b", r1);
$display("r2 = %b", r2);
end
endmodule
Result:
r1 = 00111100 (60)
r2 = 11101100 (-20)
The difference is that signed numbers utilize the MSB of the vector as an indicator of sign (see here, no really, read this) that shifts the range of expressible numbers from [0..2^n-1] to [-2^(n-1)..2^(n-1)-1]
A couple of things to note:
Verilog is odd and will only produce a signed results if both
operands are signed.
You can mark a reg/wire as signed like reg signed [3:0] foo or with the $signed system task. The latter is often useful if you have sub-expressions you want to treat as signed. For example, taking a bit slice of a vector is always unsigned even if the original var is signed.
The link I provided also covers the slight changes in mechanics required to get the right answer when multiplying signed quantities.
For purposes of Verilog's behavior division is essentially the same although unless dealing with strict powers of 2 is not usually synthesisable.
just a bit different view based on Brian's example
Signed vs unsigned arithmetic in verilog causes differences in sign propagation and relational operations. Regular arithmetic on 2-complement data produces the same results for signed and unsigned if no sign extension is involved
so in this case, if r1 and r2 would be of size '4' (as the operands) you would get the same results:
r1 = 1100 was (60)
r2 = 1100 was (-20)
In Brian's case the size of the result of the expression is 8; Verilog will extend your operands to occupy the 8-bit space. In case of the signed 'a' it will sing extend it and this will make the difference:
unsigned a[3:0] <1100> --> tmp[7:0] --> 00001100
signed a[3:0] <1100> --> tmp[7:0] --> 11111100
So, if a[3] is '1', it is considered a sign and gets sign promoted to the left. now, your arithmetic looks like the following:
unsigned: tmpa(00001100) * tmpb(00000101) --> 00111100
signed: tmpa(11111100) * tmpb(00000101) --> 11101100
When you display the second result as an integer, it will yet be sign extended to 32 bits and will be displayed as (-20)

Unsigned reg subtraction in Verilog

I have some troubles with unsigned reg subtraction in Verilog.
The following Verilog code is designed for a 4-bit ALU :
module p2(in_1,in_2,s,out);
input [3:0]in_1,in_2;
input [1:0]s;
output [4:0]out;
reg [4:0]out;
parameter ADD=2'b00;
parameter SUBTRACT=2'b01;
parameter AND=2'b10;
parameter OR=2'b11;
always #(in_1,in_2,s)
begin
case (s)
ADD: out=in_1+in_2;
SUBTRACT: out=in_1-in_2;
AND: out={1'b0,(in_1&in_2)};
OR: out={1'b0,(in_1|in_2)};
endcase
end
endmodule
Problem1:
For the case in_1=4'b0000,in_2=4'b0001,s=2'b01
I think in_1-in_2 should be: 0000-0001=0000+(1110+1)=1111
So 1111 should be zero-extended(due to unsigned subtraction) to 01111,
then is assigned to out=5'b01111
However,the correct result show that out=5'b11111
Why?
Problem2:
For the case in_1=4'b0001,in_2=4'b0001,s=2'b01
I think in_1-in_2 should be: 0001-0001=0001+(1110+1)=10000
Then it is assigned to out=5'b10000
However,the correct result show that out=5'b00000
Why?
For physical hardware, a register contains only the binary data, signed unsigned are of just a matter of human interpretations.
Here, in your case, it is a matter of Expression width evaluation. Referring to SystemVerilog LRM 1800-2012, section 11.6:
The number of bits of an expression is determined by the operands and the context.
SystemVerilog uses the bit length of the operands to determine how many bits to use while evaluating an expression.
The bit length rules are given in 11.6.1. In the case of the addition operator, the bit length of the
largest operand, including the left-hand side of an assignment, shall be used.
The number of bits of an expression (known as the size of the expression) shall be determined by the
operands involved in the expression and the context in which the expression is given.
Referring to example given in LRM:
logic [15:0] a, b; // 16-bit variable
logic [15:0] sumA;
logic [16:0] sumB; // 17-bit variable
sumA = a + b; // expression evaluates using 16 bits
sumB = a + b; // expression evaluates using 17 bits
The mistake you are making here is calculating 2's complement for 4-bits and expecting a 5-bit output. While the language uses maximum bit length in an expression to do the same.
Here, out is a 5-bit register. So the 2's complement of minuend is taken for five bits. That is, 2's complement of 4'b0001 is 5'b11111. Adding this to an extension of 4'b0000 as 5'b00000, we get 5'b11111. Henceforth your first problem's result.
Similar, comments applies for your Problem-2, Adding 5'b11111 to 5'b00001 results in 5'b00000.
For more information about signed subtraction, refer to this, this and this links.

How does Verilog behave with negative numbers?

For instance, say I have a reg [7:0] myReg
I assign it the value -8'D69
I know Verilog stores it as 2's complement so it should be stored as
10111011
The question I have now is if I were to perform an operation on it, say myReg/2
Would it evaluate to -34? Or would it take 10111011 and turn it into 187 then perform the division, returning 93?
You need to remember that -8d69 is just a bit pattern. reg is a type which holds bit patterns. It is the type of variable that instructs / to perform signed or unsigned arithmetic.
If this is for synthesis bare in mind that you want to try and avoid dividers, you really want to try and avoid signed dividers. It will likely synthesis smaller with >>> 1
reg [7:0] a;
reg signed [7:0] b;
reg [7:0] c;
reg signed [7:0] d;
initial begin
a = -8'd69 ;
b = -8'd69 ;
c = -8'd69 ;
d = -8'd69 ;
#10ns;
a = a/2 ;
b = b/2 ;
#10ns;
$display("a : %8b, %d", a, a);
$display("b : %8b, %d", b, b);
$display("c >>>1 : %8b, %d", c>>>1, c>>>1);
$display("d >>>1 : %8b, %d", d>>>1, d>>>1);
end
Gives:
a : 01011101, 93
b : 11011110, -34
c >>>1 : 01011101, 93
d >>>1 : 11011101, -35
>> x Shifts right by x places, >>> x Shifts right x places but sign extends for signed types.
NB: the /2 is also rounding up in my examples, >>> will round down/truncate.
For instance, say I have a reg [7:0] myReg I assign it the value
-8'D69
This actually isn't a signed number but instead an expression consisting of a unary negation applied to a positive constant. If the expression was -8'd130 the result would overflow. Signed constants are declared as 8'sd69 or just 69.
The question I have now is if I were to perform an operation on it,
say myReg/2
myReg is unsigned so the expression result will also be unsigned*. If you need the result to be signed than all operands must be signed. There are a couple ways to achieve this:
//Declare the reg as signed and divide by a signed value
reg signed [7:0] myReg;
assign result = myReg/2;
//Use system functions
assign result = $signed(myReg)/2;
*The complete rules regarding expression evaluation are much more complex but basically the result of any expression is unsigned, unless all operands are signed.
reg signed [7:0] a;
reg [7:0] b;
initial
begin
result = a; //Signed
result = a * a; //Signed
result = a * 10; //Signed
result = $unsigned(a); //Unsigned
result = a[0]; //Unsigned
result = a[7:0]; //Unsigned
result = {a,a}; //Unsigned
result = 10{a}; //Unsigned
result = a + b; //Unsigned
result = a * b; //Unsigned
end
I'll add that
1. Data types bit and reg are unsigned, by default.
2. Data types int, integer, longint, shortint, and byte are signed, by default.
3. All these data types can take a signed or unsigned qualifier to change the default.
So, assigning -8'D69 to myReg does an implicit conversion to 187. Then, myReg/2 = 187/2 = 93, unsigned. It's important to understand when and how SystemVerilog does implicit type conversions in expressions and assignments.
The best place to check is the Language Reference Manual. Predictably, given Verilog's "eh" attitude to proper typing, it's a bit of a mess.
Basically signed doesn't affect the actual data stored in the variable/net, but it does affect what the arithmetic operators do in some case. The obvious case is comparison, but also multiplication and division would behave differently. Addition and subtraction should be the same for both signed and unsigned.
Note especially that when one or more of the operands is unsigned it is treated as an unsigned comparison, which is different to what you would expect from C. So if we have
byte a = -10; // byte is signed
logic [7:0] b = 10; // this is unsigned
Then a > b is true.
Again if at least one operator is unsigned then it treats them both as unsigned so if we have:
byte a = -1;
logic [7:0] b = 255;
Then a == b is true.

Resources