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.