Signed binary multiplication and signed binary division - verilog

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)

Related

if you have a long signed array, can you break it up using wires?

Imagine for simplicity that I have a 50-bit input into my module. This 50-bit input is split into ten 5-bit signed words. Is this how you would make each part of the input signed?
module(in, out)
input signed [49:0] in;
wire signed [4:0] in_temp [0:9];
genvar i;
for(i = 0; i < 128; i = i+1)
assign in_temp[i] = in[5*(i+1)-1 -: 5];
....
That's one way. You can also cast each slice using $signed(in[5*(i+1)-1 -: 5]), then you don't need an intermediate signal.
SystemVerilog adds another option. You can defined a packed array which is a 50-bit vector made up of 10 signed 5-bit vectors.
typedef logic signed [4:0] int5_t;
typedef int_5_t signed [9:0] int50_t;
module m(input int_50_t in, output out));
// can now use in[1] as a 5-bit signed signal which corresponds to bits [9:5] of the 50-bit vector
It does not matter if you make the result signed or unsigned. once you split up a wire it losses its meaning.
For example: If you split up signed 8'b00011111 into two equal parts you get 4'b0001 and 4'b1111. What would be the 'value' of each of those 4 bit numbers?
Only if you later concatenate them again in the right order do you get the original number back.
Answering you question:
It does not really matter but I would make all the individual parts unsigned as the top bit from all but one, is no longer a sign bit and as such the type can be confusing. You could be pedantic and make one signed and nine unsigned vectors.
What would be more useful is to use a name like in_split to indicate this is a part of a vector which has been split up.

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

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

How can I determine the register bit widths correctly?

This is the simple code I wrote.From 'outt' I get 122116. But if I change 'outt' width to be 33 bits ([32:0]) then code seems to work and give the correct answer -140028. What is the reason for this behaviour??
`timescale 1ns / 1ps
module valu_parser(clk,outt);
input clk;
reg signed [31:0] r_1;
reg signed [31:0] r_2;
output reg signed [31:0] outt;
initial begin
r_1 = -47938;
r_2 = -150096;
end
always # (posedge clk) begin
outt <= ((r_1 + r_2)* 11585 + 8192)>>>14;
end
endmodule
You are performing an operation that needs at least 33 bits (the temporary result before the right shift uses 33 bits) and theoretically it could need 32+"the size of the multiplicand constant" assuming that r_1 and r_2 are not constants.
If you think of the hardware your code will generate, these bits needs to be stored somewhere temporarily to allow the hardware to first perform multiplication, then addition followed by the right shift.
This will do the trick, but will also generate more registers than you wanted initially. If you are using this module to generate a constant, I would recommend hard-coding the constant.
module valu_parser(clk,outt);
input clk;
reg signed [31:0] r_1;
reg signed [31:0] r_2;
reg signed [32:0] temp;
output reg signed [31:0] outt;
initial begin
r_1 = -47938;
r_2 = -150096;
end
always # (posedge clk) begin
temp <= ((r_1 + r_2)* 11585 + 8192);
end
assign outt = temp>>>14;
endmodule
The concept can be seen here: https://www.edaplayground.com/x/3BXy.
In an expression Verilog needs to decide how many bits to use in the calculation.
The + and * operators result in what are called context-determined expressions. With the expression F = A + B; the number of bits used is the maximum of F, A, and B. This usually works fine, because normally you would ensure that F was wide enough to store the result of adding A and B. Likewise with the expression F = A * B; would usually work fine, because normally you would ensure that F was wide enough to store the result of multiplying A and B.
However, by adding the shift right operator you have been able to make the variable being assigned narrower than the number of bits actually needed to calculate the expression on the left of the shift operator. The number of bits Verilog uses in the calculation is the maximum of the width of outt, r_1, r_2, 11585 and 8192. All of these are 32 bits wide (including 11585 and 8192), so 32 bits are used in the calculation. As you have discovered, 32 bits is not enough, but, with the values you have chosen, 33 bits is. With other values, 33 bits wouldn't be enough either. For a completely flexible solution, you should be using 66 bits (32 + 32 + 1 + 1) - 32 bits + 32 bits for the multiplication plus 1 more bit for each addition.
The solution to your problem is to make r_1 and/or r_2 wider or to use an intermediate value (as suggested by Hida's answer here).
When you multiply -198034 (r1+r1) on 11585 you have in result highest bit is 0 (outt[31]), then if you have 32bit signed value its start be positive and in answer you have positive result. And when you change it for 33bit your highest bit is 1 (outt[32]) and result is negative value and you have correct answer.

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