Negative Numbers |
A negative number is internally represented as 2's complement in Verilog. To quickly find two's complement, just invert the bits and add 1 to the resulting number. Consider the following example
module negativenumbers; reg [4:0] x; reg [4:0] y; initial begin x = 5; $display("x = %5b", x ); y = -x; $display("y = %5b", y ); $finish; end endmodule |
The result is
x = 00101
y = 11011
Inverting all bits of x gives
11010
Now add 1 to it and you get two's complement
y = 11011
If you however, wish to display y in decimal as in
$display("y = %d", y );
It will not display -5 as you may possibly expect. The reason is that, verilog represents the numbers as unsigned by default. It will display y as
y = 27
If you wish to display y as a signed number, you will have to explicitly declare is as in
reg signed [4:0] y;
See this complete example for decimal output in
module negativenumbers; reg [4:0] x; reg signed [4:0] y; initial begin x = 5; $display("x = %5b", x ); y = -x; $display("y = %d", y ); $finish; end endmodule |
The output is
x = 00101
y = -5
Notice that, in above case y is still internally represented in same way. So if you use
$display("y = %4b", y );
in above case, then the output is same as in previous case
y = 11011
Talking purely of reg, verilog contains binary data. How is it interpreted, depends upon, if it is delcared signed or not.
Let us take a look at a 4 bit value and see how the numbers can be interpreted in case of signed versus unsigned.
Binary Unsigned signed
1000 8 -8
0010 2 2
1110 14 -2
1111 15 -1
0001 1 1
0111 7 7
Before moving further, we ask you to copy paste the following code and run using a compiler.
module negativenumbers; reg signed [3:0] x; reg signed [2:0] y; reg signed [4:0] z; initial begin x = -7; $display("x = %d", x ); y = -5 ; z = x+y; $display("z = %d", z ); $finish; end endmodule |
What do you expect the result for z to be ?
Well, the actual answer is z = -4. Why ?
Before applying the operation, Verilog checks if the size of the operators need adjustments. There is some rule regariding which operations need length adjustment. In the above case, all operands are adjusted to have the size of the operand that has maximum size. In this case z has max size, so all operands are extended to size of 5 bit wide.
Now let us see the binary values of x and y, before length extension.
x = 4'b1001 ; // 7 is 4'b0111 - invery all => 4'b1000 , add 1 => 4'b1001
y = 3'b011 ; // 5 is 3'b101 - invert all => 3'b010, add 1 => 3'b011
Now these have to be "sign extended to 5 bits. What are thier values after sign extension ?
x = 5'b11001 ;
y = 5'b11011 ;
If this is not clear, consider x again. In 5 bits, the decimal 7 is represented as
x = 5'b00111 ; // Decimal 7
Now to get -7 we need to make it 2's complement. So we fisrt invert all bits to get
5'b11000
Now we add 1 to the above to get 2's complement or -5;
x = 5'b11001 ; // Decimal -7 in 5 bit 2's complement.
In a similar fashion we can show that -5 in 5 bit 2's complement is ( Do this exercize)
y = 5'b11011 ;
Now add these and you get
z = 5'b10100 ;
Which is displayed as -4 in decimal.
Mixture of Signed and unsigned |
Now let us consider the case where we have an arithmetic operation with mixture of signed and unsigned. In such case, the length is extented as in the previous example. So all operands now have their sizes made to the size of the operand that has maximum size.
However, the signed numers are now extented to have unsigned extension. Take a look at this example
module negativenumbers; reg signed [3:0] x; reg unsigned [2:0] y; reg signed [4:0] z; initial begin x = -7; $display("x = %d", x ); y = -5 ; z = x+y; $display("z = %d", z ); $finish; end endmodule |
The length of all operands are made 5 bit, because z has length of 5 bits. Before extending, the binary values of x and y are
x = 4'b1001 ; // 7 is 4'b0111 - invery all => 4'b1000 , add 1 => 4'b1001
y = 3'b011 ; // 5 is 3'b101 - invert all => 3'b010, add 1 => 3'b011
After length extension, they get the value as
x = 5'b01001 ;
y = 5'b00011 ;
Now add these two numbers and you get
z = 5'b01100
Which is 12 in decimal unsigned and this is what is displayed by $display statement.