Search code examples
additionvhdl

VHDL - Add operation between Signed


I'm new at VHDL. I'm trying to realize the block diagram in the following picture: enter image description here The code which realize the Z^1 block (which is just a delay) is the following:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity DFF is 
    generic (N : INTEGER:=16);
    port( 
      D     : in  signed(N-1 downto 0);      -- Data input
      clk   : in std_logic;                  -- Clock input   
      reset : in std_logic;                  -- Reset input
      Q     : out signed(N-1 downto 0));     -- Data output
end DFF;

  architecture Behavioral of DFF is 
  begin
     DFF:process(clk)
     begin
         IF (clk'EVENT AND clk='1') THEN
             FOR i IN 0 TO N-1 LOOP
                 Q(i) <= reset AND D(i);      
             END LOOP;
         END IF;
     END process DFF;

  end Behavioral;   

The code which realize the entire block diagram is the following:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity fir is
    generic (N : INTEGER:=16);
    port(   
        Clk         : in std_logic;              --clock signal    
        reset       : in std_logic;
        Xin         : in signed(N-1 downto 0);   --input signal
        Yout        : out signed(N-1 downto 0)   --filter output
    );
end fir;

architecture fir_struct of fir is

    component dff is  

        generic (N : INTEGER:=16);
        port(
            D           : in  signed(N-1 downto 0);
            clk         : in  std_logic;    
            reset       : in std_logic;
            Q           : out signed(N-1 downto 0));
   END component;   

signal y_delayed, add2_in1, add2_in2, y_temp : signed(N-1 downto 0) := (others => '0');  

-- add2_in1 is the first input of the adder (The input of the block diagram)
-- add2_in2 is the delayed output of the adder
-- y_temp is the output of the adder
-- y_delayed is the output of the delay operation

begin

    add2_in1 <= Xin;
    y_temp <= add2_in1 + add2_in2;   -- this line is giving me troubles

    DELAY1: dff port map(y_temp, Clk, reset, y_delayed);

    Yout <= y_temp;
    add2_in2 <= y_delayed;

end fir_struct;

I highlighted the line which gives me troubles. I tried to remove it and to put as first parameter of DELAY1 my input Xin (just to try if it works or the problem was in another line) and it works (of course it doesn't do what I want, but the waveform behave as I expeted). The testbench is the following:

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

ENTITY iir_wav_tb IS
END iir_wav_tb;

ARCHITECTURE behavior OF iir_wav_tb IS                

    signal Clk          : std_logic := '0'; 
    signal reset        : std_logic := '1';
    signal Xin          : signed(15 downto 0) := (others => '0');
    signal Yout         : signed(15 downto 0) := (others => '0');
    constant Clk_period : time := 10 ns;     

begin   

   -- Instantiate the Unit Under Test (UUT)
   uut: entity work.fir PORT MAP (
       Clk => Clk, 
       reset => reset,
       Xin => Xin,
       Yout => Yout);

   -- Clock process definitions
   Clk_process :process
   begin
        Clk <= '0';
        wait for Clk_period/2;
        Clk <= '1';
        wait for Clk_period/2;  
   end process;

   -- Stimulus process
   stim_proc: process
   begin 
            Xin <= to_signed(1,16);
            wait for clk_period*1;

            Xin <= to_signed(23,16);    
            wait for clk_period*1;
    end process;
end

The waveform which I obtain is the following:

enter image description here

The problem is that when the add operation occurs, the value of y_temp become '?' (the components of this 16bits signal are all 'X'). I think is a problem of inizialization, as passing Xin directly without adding anything won't rise the problem. Could anyone help me?


Solution

  • Before start with your code, you need to remember that VHDL is to create hardware and it's not a software language. So, every process is executed in parallel by simulator. Only variables are executed immediately.

    Second thing, don't initialize signals that don't need initialization.

    So, I propose this changes:

    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    use IEEE.NUMERIC_STD.ALL;
    
    entity DFF is 
       generic (N : INTEGER:=16);
       port( 
          D     : in  signed(N-1 downto 0);      -- Data input
          clk   : in std_logic;                  -- Clock input   
          reset : in std_logic;                  -- Reset input
          Q     : out signed(N-1 downto 0))      -- Data output
       end DFF;
    
    architecture Behavioral of DFF is 
    begin
       DFF:process(clk,reset)
       begin
         IF (reset = '0') then
            Q <= (others => '0');
         elsif (clk'EVENT AND clk='1') THEN
            Q <= D;      
         END IF;
     END process DFF;
    
    end Behavioral;   
    

    Doing so, you initialize add2_in2 inside the flip-flop (it's necessary that the reset at the begin going from 0 to 1). You don't need a loop to assign every bit.

    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    use IEEE.NUMERIC_STD.ALL;
    
    entity fir is
        generic (N : INTEGER:=16);
        port(   
           Clk         : in std_logic;              --clock signal    
           reset       : in std_logic;
           Xin         : in signed(N-1 downto 0);   --input signal
           Yout        : out signed(N-1 downto 0)   --filter output
         );
    end fir;
    
    architecture fir_struct of fir is
    
    component dff is  
    
        generic (N : INTEGER:=16);
        port(
            D           : in  signed(N-1 downto 0);
            clk         : in  std_logic;    
            reset       : in std_logic;
            Q           : out signed(N-1 downto 0));
    END component;   
    
    signal y_delayed, y_temp : signed(N-1 downto 0);
    
    -- add2_in1 is the first input of the adder (The input of the block diagram)
    -- add2_in2 is the delayed output of the adder
    -- y_temp is the output of the adder
    -- y_delayed is the output of the delay operation
    
    begin
    
       y_temp <= Xin + y_delayed;
    
       DELAY1: dff port map(y_temp, Clk, reset, y_delayed);
    
       Yout <= y_temp;
    
    end fir_struct;
    

    I think that so your adder will work. You need to update your test-bench:

    signal reset        : std_logic;
    
    process
    begin
        reset <= '0';
        wait for 5 ns;
        reset <= '1';
        wait;
    end process;
    

    If I forgot something, please ask me.