Implementing Overflow Checking in 4-bit Adder/Subtractor (VHDL)

fpgavhdl

I am rather new (3 weeks) to VHDL, and I am having a problem in my latest assignment, which involves implementing overflow checking in a simple 4-bit adder:

    library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity add_sub_4bit is
    Port ( a : in  STD_LOGIC_VECTOR(3 downto 0);
           b : inout  STD_LOGIC_VECTOR(3 downto 0);
              sel: in STD_LOGIC );
           --sum : inout  STD_LOGIC_VECTOR(3 downto 0) 
end add_sub_4bit;

architecture Behavioral of add_sub_4bit is
signal localflow : STD_LOGIC;
signal localsum : STD_LOGIC_VECTOR (3 downto 0);

begin
    localsum <= a + b when sel = '1'
    else
    a - b;
process(a,b,localsum) begin
    if a(3) = '0' AND b(3) = '0' AND localsum(3) = '1' then
        localflow <= '1'; 
    elsif  a(3) = '1' AND b(3) = '1' AND localsum(3) = '0' then
        localflow <='1';
    else
        localflow <='0';
    end if;
end process;
end Behavioral;

Now, the test cases are as such:
A=5, B=-3, giving 0 to sel adds them, 1 subtracts.
A=6, B=2, working much the same.

Now, given that the numbers are signed, of course, they are two's complement numbers, so is the result. However, I can only detect overflow in a case of adding 6 (0110) and 2 (0010), giving out -8 (1000), which is obviously an overflow case in 4-bit. But, when doing 5 -(-3), the result is much the same, 1000, but since I have given numbers of two different signs, I cannot detect overflow using my method.

My teacher has suggested that we change the sign of B depending on the value of sel – I tried something like making b <= b+"1000" based on that but that didn't help, and I don't know of other ways, being very new to the language. What can I do to get a proper program? Thank you.

Best Answer

Firstly:

use IEEE.STD_LOGIC_UNSIGNED.ALL;

Don't do that. Especially if you want the numbers to be signed. Normal to use is:

use IEEE.numeric_std.all;

After that, you should cast the std_logic_vector to the wanted data type, e.g. 'signed', for the correct arithmetic.

Secondly, don't use inout. VHDL is not so good with bidirectional assignments. Either use in or out.

So combining the above, you could do (n.b. not the best code):

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;

entity add_sub_4bit is
    Port (
        a : in  STD_LOGIC_VECTOR(3 downto 0);
        b : in  STD_LOGIC_VECTOR(3 downto 0);
        sel: in STD_LOGIC;
        sum : out  STD_LOGIC_VECTOR(3 downto 0);
        overflow : out std_logic
        );
end add_sub_4bit;

architecture Behavioral of add_sub_4bit is
signal localflow : STD_LOGIC;
signal locala, localb, localsum : signed(4 downto 0); -- one bit more then input
signal sumout : std_logic_vector(4 downto 0);

begin
    locala <= resize(signed(a), 5);
    localb <= resize(signed(b), 5);
    localsum <= locala + localb when sel = '1' else locala - localb;
    -- overflow occurs when bit 3 is not equal to the sign bit(4)
    localflow <= '1' when localsum(3) /= localsum(4) else '0';
    -- convert outputs
    sumout <= std_logic_vector(localsum);
    --outputs
    sum <= sumout(4)&sumout(2 downto 0);
    overflow <= localflow;
end Behavioral;

You can test this using a testbench:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;

entity add_sub_4bit_tb is
end add_sub_4bit_tb;

architecture Behavioral of add_sub_4bit_tb is
signal sel : std_logic_vector(0 downto 0);
signal a, b, sum : std_logic_vector(3 downto 0);

begin
    uut: entity work.add_sub_4bit
    port map (a, b, sel(0), sum);

    test: process
    begin
        for sel_o in 0 to 1 loop
            sel <= std_logic_vector(to_signed(sel_o, 1));
            for a_o in -8 to 7 loop
                a <= std_logic_vector(to_signed(a_o, 4));
                for b_o in -8 to 7 loop
                    b <= std_logic_vector(to_signed(b_o, 4));
                    wait for 1 ns;
                end loop;
            end loop;
        end loop;
        wait;
    end process;
end Behavioral;
Related Topic