1

Suppose that I have two logic vectors:

logic [4:0] a;
logic [4:0] b;

that hold 2's complement values. I want to perform a subtraction and extend the result by 1 bit. For example, assume that I want to compute -12 - 13 and store the result of -25:

logic [5:0] sum;
sum = a - b;

The above simulates as I expect and I get the expected value of 6'b100111. Working through this by hand:

  1 0 1 0 0   -12
  1 0 0 1 0   invert bits of +13
          1   carry-in
---------------
1 0 0 1 1 1   = -25

So, the MSB of the result is simply the carry-out of the addition. However, if I compute 12 - 13, the result should be 6'b111111, but instead I get the simulated result of 6'b011111. Working through this example by hand:

  0 1 1 0 0   12
  1 0 0 1 0   invert bits of +13
          1   carry-in
---------------
0 1 1 1 1 1   = +31

So, the result is not correct as the carry-out into the MSB is zero.

I can fix the simulated result by changing the RTL as follows:

logic [5:0] sum;
sum = $signed(a) - $signed(b);

which returns the expected result of 6'b111111. After reading through the SystemVerilog LRM to understand what's happening here, I discovered that additions are done at the bit size of the largest operand, including the LHS of assignment operations. In addition, using the $signed keyword causes the 5-bit input operands to be sign-extended to 6-bits. Taking this into account and performing the operation by hand again:

[0] 0 1 1 0 0   12
[1] 1 0 0 1 0   invert bits of +13
            1   carry-in
---------------
 1  1 1 1 1 1   = -1

where [0] and [1] are the sign-extension bits. From this it is clear that the MSB is actually calculated by a full-adder ([0] + [1] + carry-out from previous column).

My question is this:

  1. Am I correct in thinking that a signed adder does indeed require a full-adder on the MSB to calculate the correct result?
  2. If above is correct, what will a synthesis tool make of this? Will it also know to instantiate a full-adder on the MSB?

I had always assumed that writing an adder in SystemVerilog, where the inputs are n-bits wide, would cause a synthesis tool to instantiate a n-bit adder where the (n+1)-bit output was simply the carry-out of that adder.

1 Answers1

1

You forgot about sign extension. -13 (10011) in 6-bit incarnation is supposed to be 110011. Therefore, you are interpreting the second resulst incorrectly. It is not +31 (6-bit), it should be interpreted as -1 in the 5-bit version. To make a 6-bit result do sigh-extend both operands:

  ext
  0 | 0 1 1 0 0   -- 12
  1 | 1 0 0 1 1   -- -13
  ==|==========
  1 | 1 1 1 1 1   -- -1 (6 bit)

With unsigned numbers only you can get away without extension, because it is always '0'.

Serge
  • 11,616
  • 3
  • 18
  • 28
  • Hi Serge, thanks for the answer. I do agree that sign-extension is required to get the correct result, I eventually figured that out. However, I'm still not sure if a synthesis tool would interpret this correctly? It appears that to implement this circuit, it requires 1 additional full adder on the MSB, when compared to an adder that works on unsigned numbers. Is this the correct way of coding a signed adder (using $signed) or should I explicitly code it myself with the additional full adder on the MSB? – Andrew Lees Jun 05 '21 at 19:56
  • no , they will not. You need to design your model in such a way that the sign extension is built into it. So, at mininmum you would need 6 bit operands for a 6-bit answer. – Serge Jun 05 '21 at 21:05
  • So then what's the correct way of coding this? From what you're saying, this is enough? `sum = {a[4], a[4:0} - {b[4], b[4:0]}`. Is this different from `sum = $signed(a) - $signed(b)` ? – Andrew Lees Jun 05 '21 at 22:25
  • something like that would do – Serge Jun 05 '21 at 23:11
  • Don't use ```sum = {a[4], a[4:0} - {b[4], b[4:0]}```. Use ```sum = $signed(a) - $signed(b)```. – ToTamire Jun 06 '21 at 12:27
  • `$signed` is synthesizable by DC, but you need to check other synthesis tools if it is available there. – Serge Jun 06 '21 at 12:38