N-bit Adder/Subtractor VHDL

logicvhdl

Hello I'm trying to implement a N-bit adder/subtractor in VHDL but I'm not getting it to work properly for some reason and I can't seem to find what the problem is..

The adder is working as it should but the subtractor isn't and I can't really see what the problem is since I've checked the expression and it is correct, but when I simulate it seems like the subtraction part isn't working at all…

Here's how my implementation with overflow detection and saturation control:

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;

entity ripple_adder_subtracter_saturate is
    generic (WIDTH : INTEGER := 8);
     port (a : IN STD_LOGIC_VECTOR(WIDTH-1 downto 0);
           b : IN STD_LOGIC_VECTOR(WIDTH-1 downto 0);
           cin : IN STD_LOGIC := '0';
           saturate : IN STD_LOGIC := '0';
           add_sub : IN STD_LOGIC := '1';
           y : OUT STD_LOGIC_VECTOR(WIDTH-1 downto 0);
           cout : OUT STD_LOGIC;
           overflow : OUT STD_LOGIC);
  end ripple_adder_subtracter_saturate;

 ARCHITECTURE behavior OF ripple_adder_subtracter_saturate is

 component bitAdder is
 port(a : IN STD_LOGIC;
      b : IN STD_LOGIC;
      cin : IN STD_LOGIC;
      add_sub : IN STD_LOGIC;
      y : OUT STD_LOGIC;
     cout : OUT STD_LOGIC);
 end component;

 signal carry : STD_LOGIC_VECTOR (WIDTH-1 downto 0); -- hold the carry outs from the adders
 signal temp_sum : STD_LOGIC_VECTOR (WIDTH-1 downto 0);
 signal o_flow : STD_LOGIC;                             -- internal overflow signal so I can read it in the process

 begin 
cell_0: bitAdder port map(a(0), b(0), cin, add_sub, temp_sum(0), carry(0));
 G: FOR i IN 1 TO WIDTH-1 GENERATE
    cell_i: bitAdder port map(a(i), b(i), carry(i-1), add_sub, temp_sum(i), carry(i));
    end GENERATE;

    o_flow <= carry(WIDTH-1) XOR carry(WIDTH-2);
    overflow <= o_flow;
    cout <= carry(WIDTH-1);

    process(saturate, temp_sum, carry, o_flow) 
    begin
        if (saturate = '1' AND o_flow = '1') then
            if (carry(WIDTH-1) = '0') then
                y <= (WIDTH-1 => '0', others => '1');
            else
                y <= (WIDTH-1 => '1', others => '0');
            end if;
        else
            y <= temp_sum;
         end if;
    end process;
end behavior;

When the signal add_sub = 0, it should subtract and when it's 1 it should do additon etc..
This is how the full adder/subtractor looks like:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

ENTITY bitAdder IS
    PORT (a: IN STD_LOGIC;
      b: IN STD_LOGIC;
      cin: IN STD_LOGIC;
      add_sub : IN STD_LOGIC;
      y: OUT STD_LOGIC;
      cout: OUT STD_LOGIC);
END bitAdder;

ARCHITECTURE behavior OF bitAdder IS
signal b_sub : STD_LOGIC := '1';
BEGIN
    process(a, b, cin, add_sub)
    begin
        if (add_sub = '0') then
            b_sub <= (not b);
            y <= (a XOR b_sub) XOR cin;
            cout <= (a AND b_sub) OR (b_sub AND cin) OR (a AND cin);
        else
            y <= (a XOR b) XOR cin;
            cout <= (a AND b) OR (b AND cin) or (a AND cin);
        end if;
    end process;
END behavior;

Can you see what I might've done wrong? I've been bashing my head towards the wall for multiple hours now without any success. So any kind of pointers would be of help!

Here's the testbench that it should pass through:

-----------------------------------
-- testbench type 3 for          --
-- ripple carry adder/subtracter --
-- with overflow signal          --
-- and saturation logic          --
-- for generic vector            --
-----------------------------------

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;

ENTITY ripple_adder_subtracter_saturate_tb3 IS
   GENERIC (WIDTH:INTEGER:=8);
   PORT(test_OK:OUT STD_LOGIC);
END ripple_adder_subtracter_saturate_tb3;

ARCHITECTURE arch_ripple_adder_subtracter_saturate_tb3 OF
                       ripple_adder_subtracter_saturate_tb3 IS

   COMPONENT ripple_adder_subtracter_saturate IS
      GENERIC (WIDTH:INTEGER:=8);
      PORT(a:IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
           b:IN STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
           add_sub:IN STD_LOGIC;
           saturate:IN STD_LOGIC;
           y:OUT STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
           overflow:OUT STD_LOGIC);
   END COMPONENT ripple_adder_subtracter_saturate;

   SIGNAL a_tb_signal:STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
   SIGNAL b_tb_signal:STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
   SIGNAL y_tb_signal:STD_LOGIC_VECTOR(WIDTH-1 DOWNTO 0);
   SIGNAL add_sub_tb_signal:STD_LOGIC;
   SIGNAL saturate_tb_signal:STD_LOGIC;
   SIGNAL overflow_tb_signal:STD_LOGIC;
BEGIN
   ripple_adder_subtracter_saturate_comp:
   COMPONENT ripple_adder_subtracter_saturate
         PORT MAP(a=>a_tb_signal,
                  b=>b_tb_signal,
                  add_sub=>add_sub_tb_signal,
                  saturate=>saturate_tb_signal,
                  y=>y_tb_signal,
                  overflow=>overflow_tb_signal);

   saturate_tb_signal<='0',               -- overflow
                '1' AFTER 1400 ns; -- saturate
   add_sub_tb_signal<='1',               -- add
               '0' AFTER 700 ns,  -- sub
               '1' AFTER 1400 ns, -- add
               '0' AFTER 2100 ns; -- sub
   a_tb_signal<="00000000",  -- 0
         "01010101" AFTER 100 ns, -- 85
         "11100101" AFTER 300 ns, -- -27
         "00000000" AFTER 700 ns, -- 0
         "01010101" AFTER 800 ns, -- 85
         "11100101" AFTER 1000 ns,  -- -27
         "00000000" AFTER 1400 ns,  -- 0
         "01010101" AFTER 1500 ns, -- 85
         "11100101" AFTER 1700 ns, -- -27
         "00000000" AFTER 2100 ns, -- 0
         "01010101" AFTER 2200 ns, -- 85
         "11100101" AFTER 2400 ns;  -- -27

   b_tb_signal<="00000000",  -- 0
         "00011101" AFTER 100 ns, -- 29
         "00111000" AFTER 200 ns, -- 56
         "00000110" AFTER 400 ns, -- 6
         "11001000" AFTER 500 ns, -- -56
         "10010111" AFTER 600 ns, -- -105
         "00000000" AFTER 700 ns, -- 0
         "00011101" AFTER 800 ns, -- 29
         "11001000" AFTER 900 ns, -- -56
         "00111000" AFTER 1000 ns, -- 56
         "00000110" AFTER 1100 ns, -- 6
         "11001000" AFTER 1200 ns, -- -56
         "01101001" AFTER 1300 ns, -- 105
         "00000000" AFTER 1400 ns,  -- 0
         "00011101" AFTER 1500 ns, -- 29
         "00111000" AFTER 1600 ns, -- 56
         "00000110" AFTER 1800 ns, -- 6
         "11001000" AFTER 1900 ns, -- -56
         "10010111" AFTER 2000 ns, -- -105
         "00000000" AFTER 2100 ns, -- 0
         "00011101" AFTER 2200 ns, -- 29
         "11001000" AFTER 2300 ns, -- -56
         "00111000" AFTER 2400 ns, -- 56
         "00000110" AFTER 2500 ns, -- 6
         "11001000" AFTER 2600 ns, -- -56
         "01101001" AFTER 2700 ns; -- 105

test_proc:
PROCESS
   BEGIN
--overflow
--addition
      WAIT FOR 50 ns; -- 50 ns 0+0=0 (00000000)
      ASSERT (y_tb_signal="00000000")
      REPORT "Error for 0+0=0=00000000"
      SEVERITY ERROR;
      ASSERT (overflow_tb_signal='0')
      REPORT "Error in overflow bit when 0+0=0=00000000"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 150 ns 85+29=114 (01110010)
      ASSERT (y_tb_signal="01110010")
      REPORT "Error for 85+29=114=01110010"
      SEVERITY ERROR;
      ASSERT (overflow_tb_signal='0')
      REPORT "Error in overflow bit when 85+29=114=01110010"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 250 ns 85+56=141->-115 (10001101)
      ASSERT (y_tb_signal="10001101")
      REPORT "Error for 85+56=141->-115=10001101"
      SEVERITY ERROR;
      ASSERT (overflow_tb_signal='1')
      REPORT "Error in overflow bit when 85+56=141->-115=10001101"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 350 ns -27+56=29 (00011101)
      ASSERT (y_tb_signal="00011101")
      REPORT "Error for -27+56=29=00011101"
      SEVERITY ERROR;
      ASSERT (overflow_tb_signal='0')
      REPORT "Error in overflow bit when -27+56=29=00011101"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 450 ns -27+6=-21 (11101011)
      ASSERT (y_tb_signal="11101011")
      REPORT "Error for -27+6=-21=11101011"
      SEVERITY ERROR;
      ASSERT (overflow_tb_signal='0')
      REPORT "Error in overflow bit when -27+6=-21=11101011"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 550 ns -27-56=-83 (10101101)
      ASSERT (y_tb_signal="10101101")
      REPORT "Error for -27-56=-83=10101101"
      SEVERITY ERROR;
      ASSERT (overflow_tb_signal='0')
      REPORT "Error in overflow bit when -27-56=-83=10101101"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 650 ns -27-105=-132->124 (01111100)
      ASSERT (y_tb_signal="01111100")
      REPORT "Error for -27-105=-132->124=01111100"
      SEVERITY ERROR;
      ASSERT (overflow_tb_signal='1')
      REPORT "Error in overflow bit when -27-105=-132->124=01111100"
      SEVERITY ERROR;
--subtraction
      WAIT FOR 100 ns; -- 750 ns 0-0=0 (00000000)
      ASSERT (y_tb_signal="00000000")
      REPORT "Error for 0-0=0=00000000"
      SEVERITY ERROR;     
      ASSERT (overflow_tb_signal='0')
      REPORT "Error in overflow bit when 0-0=0=00000000"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 850 ns 85-29=56 (00111000)
      ASSERT (y_tb_signal="00111000")
      REPORT "Error for 85-29=56=00111000"
      SEVERITY ERROR;     
      ASSERT (overflow_tb_signal='0')
      REPORT "Error in overflow bit when 85-29=56=00111000"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 950 ns 85-(-56)=141->-115 (10001101)
      ASSERT (y_tb_signal="10001101")
      REPORT "Error for 85-(-56)=141->-115=10001101"
      SEVERITY ERROR;     
      ASSERT (overflow_tb_signal='1')
      REPORT "Error in overflow bit when 85-(-56)=141->-115=10001101"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 1050 ns -27-56=-83 (10101101)
      ASSERT (y_tb_signal="10101101")
      REPORT "Error for -27-56=-83=10101101"
      SEVERITY ERROR;    
      ASSERT (overflow_tb_signal='0')
      REPORT "Error in overflow bit when -27-56=-83=10101101"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 1150 ns -27-6=-33 (11011111)
      ASSERT (y_tb_signal="11011111")
      REPORT "Error for -27-6=-33=11011111"
      SEVERITY ERROR;    
      ASSERT (overflow_tb_signal='0')
      REPORT "Error in overflow bit when -27-6=-33=11011111"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 1250 ns -27-(-56)=29 (00011101)
      ASSERT (y_tb_signal="00011101")
      REPORT "Error for -27-(-56)=29=00011101"
      SEVERITY ERROR;  
      ASSERT (overflow_tb_signal='0')
      REPORT "Error in overflow bit when -27-(-56)=29=00011101"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 1350 ns -27-105=-132->124 (01111100)
      ASSERT (y_tb_signal="01111100")
      REPORT "Error for -27-105=-132->124=01111100"
      SEVERITY ERROR;  
      ASSERT (overflow_tb_signal='1')
      REPORT "Error in overflow bit when -27-105=-132->124=01111100"
      SEVERITY ERROR;
--saturate
--addition
      WAIT FOR 100 ns; -- 1450 ns 0+0=0 (00000000)
      ASSERT (y_tb_signal="00000000")
      REPORT "Error for 0+0=0=00000000"
      SEVERITY ERROR;
      ASSERT (overflow_tb_signal='0')
      REPORT "Error in overflow bit when 0+0=0=00000000"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 1550 ns 85+29=114 (01110010)
      ASSERT (y_tb_signal="01110010")
      REPORT "Error for 85+29=114=01110010"
      SEVERITY ERROR;
      ASSERT (overflow_tb_signal='0')
      REPORT "Error in overflow bit when 85+29=114=01110010"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 1650 ns 85+56=141->127 (01111111)
      ASSERT (y_tb_signal="01111111")
      REPORT "Error for 85+56=141->127=10001101"
      SEVERITY ERROR;
      ASSERT (overflow_tb_signal='1')
      REPORT "Error in overflow bit when 85+56=141->127=10001101"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 1750 ns -27+56=29 (00011101)
      ASSERT (y_tb_signal="00011101")
      REPORT "Error for -27+56=29=00011101"
      SEVERITY ERROR;
      ASSERT (overflow_tb_signal='0')
      REPORT "Error in overflow bit when -27+56=29=00011101"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 1850 ns -27+6=-21 (11101011)
      ASSERT (y_tb_signal="11101011")
      REPORT "Error for -27+6=-21=11101011"
      SEVERITY ERROR;
      ASSERT (overflow_tb_signal='0')
      REPORT "Error in overflow bit when -27+6=-21=11101011"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 1950 ns -27-56=-83 (10101101)
      ASSERT (y_tb_signal="10101101")
      REPORT "Error for -27-56=-83=10101101"
      SEVERITY ERROR;
      ASSERT (overflow_tb_signal='0')
      REPORT "Error in overflow bit when -27-56=-83=10101101"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 2050 ns -27-105=-132->-128 (10000000)
      ASSERT (y_tb_signal="10000000")
      REPORT "Error for -27-105=-132->-128=01111100"
      SEVERITY ERROR;
      ASSERT (overflow_tb_signal='1')
      REPORT "Error in overflow bit when -27-105=-132->-127=10000000"
      SEVERITY ERROR;
--subtraction
      WAIT FOR 100 ns; -- 2150 ns 0-0=0 (00000000)
      ASSERT (y_tb_signal="00000000")
      REPORT "Error for 0-0=0=00000000"
      SEVERITY ERROR;     
      ASSERT (overflow_tb_signal='0')
      REPORT "Error in overflow bit when 0-0=0=00000000"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 2250 ns 85-29=56 (00111000)
      ASSERT (y_tb_signal="00111000")
      REPORT "Error for 85-29=56=00111000"
      SEVERITY ERROR;     
      ASSERT (overflow_tb_signal='0')
      REPORT "Error in overflow bit when 85-29=56=00111000"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 2350 ns 85-(-56)=141->127 (01111111)
      ASSERT (y_tb_signal="01111111")
      REPORT "Error for 85-(-56)=141->127=01111111"
      SEVERITY ERROR;     
      ASSERT (overflow_tb_signal='1')
      REPORT "Error in overflow bit when 85-(-56)=141->127=01111111"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 2450 ns -27-56=-83 (10101101)
      ASSERT (y_tb_signal="10101101")
      REPORT "Error for -27-56=-83=10101101"
      SEVERITY ERROR;    
      ASSERT (overflow_tb_signal='0')
      REPORT "Error in overflow bit when -27-56=-83=10101101"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 2550 ns -27-6=-33 (11011111)
      ASSERT (y_tb_signal="11011111")
      REPORT "Error for -27-6=-33=11011111"
      SEVERITY ERROR;    
      ASSERT (overflow_tb_signal='0')
      REPORT "Error in overflow bit when -27-6=-33=11011111"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 2650 ns -27-(-56)=29 (00011101)
      ASSERT (y_tb_signal="00011101")
      REPORT "Error for -27-(-56)=29=00011101"
      SEVERITY ERROR;  
      ASSERT (overflow_tb_signal='0')
      REPORT "Error in overflow bit when -27-(-56)=29=00011101"
      SEVERITY ERROR;

      WAIT FOR 100 ns; -- 2750 ns -27-105=-132->-128 (10000000)
      ASSERT (y_tb_signal="10000000")
      REPORT "Error for -27-105=-132->-128=10000000"
      SEVERITY ERROR;  
      ASSERT (overflow_tb_signal='1')
      REPORT "Error in overflow bit when -27-105=-132->-128=10000000"
      SEVERITY ERROR;
    END PROCESS test_proc;
END arch_ripple_adder_subtracter_saturate_tb3;

And the .do file:

-- ripple_adder_saturate_tb3.do

restart -f -nowave
view signals wave
add wave saturate_tb_signal a_tb_signal b_tb_signal y_tb_signal
add wave -radix signed a_tb_signal b_tb_signal y_tb_signal
add wave -radix unsigned y_tb_signal
add wave overflow_tb_signal
run 1380ns

Best Answer

Without running your testbench there are a couple of things that appear wrong in the unlabeled adder process.

Firs, in bitAdder the process sensitivity list is missing b_sub, which will have an event one delta cycle after b. You could end up operating on the last b_sub value, which also has an inferred latch should you want to synthesize this (b_sub is not assigned under else).

Also note that add_sub effectively one's complements the top level b, by inverting the bitAdder b bits.

To accomplish subtraction by adding the two's complement of the top level b you need a + 1 accomplished by carry in. To preserve the ability to use your top level cin, you can simply invert the value of cin being delivered to cell_0 when add_sub = '0'. This allows you to chain operations of WIDTH width operands.

In ripple_adder_subtracter_saturate:

signal o_flow : STD_LOGIC;                             -- internal overflow ...

signal cin_add_sub: std_logic;                         -- added

begin

    cin_add_sub <= not add_sub xor cin;                -- added

And substituting cin_add_sub for cin in the cell_0 instantiation:

cell_0: bitAdder port map(a(0), b(0), cin_add_sub, add_sub, temp_sum(0), carry(0));

You could add a separate statement or process in bitAdder to invert b when add_sub = '0' and eliminate the else in the if statement in the present process.

Something like:

architecture foo of bitAdder is
    signal b_sig:   std_logic;
begin
    b_sig   <= not b when add_sub = '0' else
                   b;              -- b_sig <= not add_sub xor b;
    y       <= a xor b_sig xor cin; 

    cout    <= (a and b_sig)   or 
               (b_sig and cin) or
               (a and cin);
end architecture;

Likewise you could move the entire two's complement operation to the design top level.

I made the above changes and your design did not produce any assertion violations. (As long as you don't let it run long enough for the process with the assertion statements to wrap, it should be terminated by say wait 49 ns; wait;. The extra wait so you can display waveforms more or less uniformly for all tests.)

Examining a waveform dump shows subtraction getting the right value. I didn't verify the rest of the assertions.

Related Topic