Signed Addition of two std logic vectors while looking for overflow and carry

addervhdl

I have what I think to be a working implentation for finding the sum of two signed 32 bit (std_logic_vector) vectors in which I chose to expand the result to always have 33 bits so as to preserve the sign bit while being able to check for carry out with the expanded bit.

My method seems incredibly dirty and I was wondering if there was a cleaner way of accomplishing my goal, for future reference.

sum <= std_logic_vector(resize(signed(std_logic_vector(signed(a_alu32) + signed(b_alu32))), 33));
c_alu32 <= sum(31);
--overflow--
if ((a_alu32(31)='0' and b_alu32(31)='0' and sum(31)='1') or (a_alu32(31)='1' and b_alu32(31)='1' and sum(31)='0')) then 
  ov_alu32<='1'; --logic to check for overflow
else
  ov_alu32<='0';
end if;

--removing the extra bit through concatenation to achieve my 32 bit sum
o_alu32 <= sum(32) & sum(30 downto 0);

Best Answer

Your implementation is not correct:

  • You must perform the sign extension before the addition of a and b.
  • A signed addition has no carry Flag, only overflow (it can be calculated but it's not valid); unsigned addition produces a carry flag but has no valid overflow.
  • The sign-bit is -- per definition -- always store in the highest bit

This could be a more or less nice rewriting, which is more generic. It only depends on a, b and c's length. So you could reuse this code for 16 or 64 bit, or whatever.

-- create locale signals with suffix '_s' for signed
-- both signals have one more bit than the original
signal a_alu32_s   : SIGNED(a_alu32'length downto 0);
signal b_alu32_s   : SIGNED(b_alu32'length downto 0);
signal sum_alu32_s : SIGNED(a_alu32'length downto 0);
signal temp        : std_logic_vector(2 downto 0);

-- convert type and perform a sign-extension
a_alu32_s <= resize(signed(a_alu32), a_alu32_s'length);
b_alu32_s <= resize(signed(b_alu32), b_alu32_s'length);

-- addition of two 33 bit values
sum_alu32_s <= a_alu32_s + b_alu32_s;

-- resize to require size and type conversion
o_alu32 <= std_logic_vector(resize(sum_alu32_s, o_alu32'length));

-- flag calculations
--c_alu32  <= sum_32_s(sum_alu32_s'high);

-- concat the three relevant sign-bits from a,b and sum to one vector
temp     <= a_alu32_s(a_alu32_s'high) & b_alu32_s(b_alu32_s'high) & sum_alu32_s(sum_alu32_s'high);
ov_alu32 <= (temp = "001") or (temp = "110");