0
votes

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.

1
In HW subtraction adds the two's complement of b (not b + 1), the + 1 uses carry in. When subtracting you should be using the sign of the actual b adder operand for overflow which would be opb_sign <= b(3) when sel = '1' else not b(3);. You could show this as a separate multiplexer (selector) or using XOR collapse this to the term (b(3) xor not sel). Also collapsing the original overflow selector gives localflow <= a(3) xor b(3) xor not sel xor localsum(3); Parentheses are unneeded, XOR is commutative. and not is the higher priority. - user1155120
Hi there, Your suggestion worked - I kept the same program, with an additonal mux. Thanks a lot! - xen20

1 Answers

1
votes

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;