0
votes

I'm trying to implement a serial adder/subtractor in VHDL, I've done it the ripple carry way before but now I'm supposed to implement the same functionality by just using one full adder cell instead of N-amount of cells so I have to shift the bits from the vectors in to the full adder/subtractor and store the result in another vector which I just shift the index for as well... The logic behind it is very easily understood, you just have a counter for the index and so on. But I obviously encounter problems since I'm probably still thinking a bit too much software programming I guess...

The problem I have is that the counter increases to 1 right away when it enters the process so that when I try to add the vectors a = 0101 0101 and b = 1010 1010 I get y = 1111 111X and the carrys = 0000 000X. I've tried to start storing the result at index_counter - 1 since the index jumps to 1 on the first clock cycle, but then I get a fatal error in the simulation...

I've been trying to solve this problem for a few hours now and can't seem to figure out how to do it, so could you please take a look and see what I can do to fix it? Would be very much appreciated!

I do have signals for saturation and overflow that I am going to implement later on but they aren't really used at the moment so don't worry about them.

The design shouldn't update the final result before the addition/subtraction is finished if you're wondering why I have done it the way I have..

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;

entity serial_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);
          saturate : IN STD_LOGIC := '0';
          add_sub : IN STD_LOGIC := '1';
          clk : IN STD_LOGIC;
          start : IN STD_LOGIC;
          reset : IN STD_LOGIC;
          y : OUT STD_LOGIC_VECTOR(WIDTH-1 downto 0);
          overflow : OUT STD_LOGIC;
          finished : OUT STD_LOGIC);
end serial_adder_subtracter_saturate;

ARCHITECTURE behavior OF serial_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

signal a_temp : STD_LOGIC;
signal b_temp : STD_LOGIC;
signal y_temp : STD_LOGIC;
signal cin_temp : STD_LOGIC; 
signal cout_temp : STD_LOGIC;

begin 
AddSub: bitAdder 
    port map(a => a_temp, 
             b => b_temp, 
             cin => cin_temp, 
             add_sub => add_sub, 
              y => y_temp, 
             cout => cout_temp);

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

test: process(clk)
variable index_counter : integer range 0 to (WIDTH) := 0;
begin
    if rising_edge(clk) then
        if reset = '1' then
            index_counter := 0;
            carry <= (others => '0');
            temp_sum <= (others => '0');
            finished <= '0';
        elsif reset = '0' AND start = '1' then
            if index_counter = (WIDTH) then
                finished <= '1';
                y <= temp_sum;
            else
                if index_counter = 0 then
                    cin_temp <= NOT add_sub;
                else
                    cin_temp <= carry(index_counter);
                end if;

                a_temp <= a(index_counter);
                b_temp <= b(index_counter);
                carry(index_counter) <= cout_temp;
                temp_sum(index_counter) <= y_temp;

                index_counter := index_counter + 1;
            end if;             
        end if;
    end if;
end process;
end behavior;

Here's how the full adder/subtractor looks if that's of interest:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.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_sig : STD_LOGIC := '1';
BEGIN
    b_sig <= not b when add_sub = '0' else
                 b;             -- b_sig <= 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 behavior;
1
If you don't want us to worry about a part of your code, then please remove that part. It is considered polite and helpful to post a minimal, working example that illustrates your question; not just dump your source files.Philippe

1 Answers

1
votes

I haven't tried to debug this, but I think it is a timing problem:

At the very first rising clock edge, you define both the inputs to your adder and register the adder's outputs (which are X at this point, because its inputs weren't defined before).

With the idea of storing the result at index_counter - 1 you are on the right track however you need to take care that you never try to store the result in a non-existing register such as carry(-1) or temp_sum(-1). You can use if index_counter > 0 for that for example.

Similarly, you then need to allow for one more cycle at the end of the calculation or assign the last result bit directly to your y output or you'll miss the last result bit.

Hope that helps!