Search code examples
vhdl

Implementations of an Adder in VHDL comparison


Can someone explain me why this implementation works

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

entity Adder is
    port(A: in std_logic_vector(3 downto 0);
    B: in std_logic_vector(3 downto 0);
    SUM: out std_logic_vector(3 downto 0);
    CO: out std_logic);
end;

architecture DescriptionAdders of Adder is

signal temp:  std_logic_vector(4 downto 0);
signal temp1: std_logic_vector(4 downto 0);
signal temp2: std_logic_vector(4 downto 0);

begin

temp1 <= '0' & A;
temp2 <= '0' & B;
temp <= std_logic_vector(unsigned(temp1) + unsigned(temp2));

SUM <= temp(3 downto 0);
CO <= temp(4);

end;

while this doesn't (the SUM is XX when it starts running, then it is always one step behind the real result, but the temps update well).

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

entity Adder is
    port(A: in std_logic_vector(3 downto 0);
    B: in std_logic_vector(3 downto 0);
    SUM: out std_logic_vector(3 downto 0);
    CO: out std_logic);
end;

architecture DescriptionAdders of Adder is

signal temp:  std_logic_vector(4 downto 0);
signal temp1: std_logic_vector(4 downto 0);
signal temp2: std_logic_vector(4 downto 0);

begin

process(A, B) is
begin
    temp1 <= '0' & A;
    temp2 <= '0' & B;
    temp <= std_logic_vector(unsigned(temp1) + unsigned(temp2));
end process;

SUM <= temp(3 downto 0);
CO <= temp(4);

end;

Sorry if the question is too easy, I'm a begginer.


Solution

  • This question seems to be based about a common misconception of how VHDL simulation works.

    process(A, B)
    

    means the process will be triggered at an event of A or B. What happens in the process are assignments to additional objects

    temp1 <= '0' & A;
    temp2 <= '0' & B;
    temp <= std_logic_vector(unsigned(temp1) + unsigned(temp2));
    

    This means three events will be scheduled, one to each of temp1, temp2 and temp. But the way VHDL works, the actual assignments will not occur until the next delta cycle. Which occurs after the process is evaluated. So even though the lines for assignment to temp1 and temp2 are located before the assignemnt to temp, their values have not been changed yet.

    Considering values of temp1 and temp2 change after the process is finished, the assignment to temp is missed. Unless you re-enter the process, by adding the objects to the sensitivity list. E.g.

    process(A, B, temp1, temp2) is
    begin
        temp1 <= '0' & A;
        temp2 <= '0' & B;
        temp <= std_logic_vector(unsigned(temp1) + unsigned(temp2));
    end process;
    

    An alternative solution would be to use variables, which can change inside of the process. But please note that variables can cause difficulties in logic synthesis if not properly used. This example will work:

    process(A, B) is
        variable temp1, temp2 : std_logic_vector(4 downto 0);
    begin
        temp1 := '0' & A;
        temp2 := '0' & B;
        temp <= std_logic_vector(unsigned(temp1) + unsigned(temp2));
    end process;
    

    But the question is: why do you need temp1 and temp2 at all. Just write

    process(A, B) is
    begin
        temp <= std_logic_vector(unsigned('0' & A) + unsigned('0' & B));
    end process;
    

    Or a bit more flexible

    process(A, B) is
    begin
        temp <= std_logic_vector(
            resize(unsigned(A), temp'length) +
            resize(unsigned(B), temp'length));
    end process;
    

    Or even using the integer type (limited to 32 bits!)

    process(A, B) is
    begin
        temp <= std_logic_vector(to_unsigned(
            to_integer(unsigned(A)) + to_integer(unsigned(B))
            , temp'length));
    end process;