Search code examples
filtervhdlsimulationmodelsim

Transposed form fir filter in vhdl


I am trying to implement a transposed form FIR filter of order 4.I am attaching the code and the waveform alongwith.In the first clock cycle, I have given a reset signal which will initialize the adder_output to 0.Input data is loaded in the second clock cycle.Input is written in a register.So the input is loaded at third clock cycle and the multiplication result of the input and filter coefficient is obtained in the third clock cycle.But at the same clock cycle, the adder output becomes dont care.Hence I am not getting the output for the first 3 clock cycles and after that the output is correct.

 library ieee;
    use ieee.std_logic_1164.all;
    use ieee.std_logic_signed.all;
    use ieee.numeric_std.all;

    entity bpf is 
    
    port 
    (
    rst     :in std_logic;
    clk    : in std_logic;
    bpf_enable : in std_logic;
    bpf_input  : in std_logic_vector(14 downto 0);  
    bpf_output : out std_logic_vector(14 downto 0);
    bpf_ready  : out std_logic  
    );
    
    end bpf;

architecture bpf_behav OF bpf is


    component multiplier is
        port(
    
        in1    :in std_logic_vector(14 downto 0);
        in2    :in std_logic_vector(12 downto 0);
        product:out std_logic_vector(27 downto 0)
        );
    end component;

    
    type coeff_array is array(0 to 3) of std_logic_vector(12 downto 0);
    type product_array is array(0 to 3) of std_logic_vector(27 downto 0);
    type adder_array is array(0 to 3) of std_logic_vector(34 downto 0); 
    signal input_data :std_logic_vector(14 downto 0);
    signal output_data:std_logic_vector(14 downto 0);
    signal coefficient : coeff_array; -- Coefficient array
    signal product :product_array;
    signal adder_out: adder_array; -- Adder array
    signal multiplier_en:std_logic;
 begin
 
    coefficient(0)<=std_logic_vector(to_signed(250,13));
    coefficient(1)<=std_logic_vector(to_signed(608,13));
    coefficient(2)<=std_logic_vector(to_signed(1530,13));
    coefficient(3)<=std_logic_vector(to_signed(2603,13));

        
    data_load:process(clk)
      begin
      if(rising_edge(clk)) then
            if(bpf_enable='1') then
                input_data<= bpf_input;            
            end if;
     end if;
    end process data_load;
        
    mulgen :for index1 in 0 to 3 generate
    
        u_multiplier:multiplier port map    
        (
        in1=>input_data,
        in2=>coefficient(index1),
        product=>product(index1)
        );  
    end generate;       
                
        
    adder:process(clk)
           begin
            if(rst='1') then
                   adder_out<=(others=>(others=>'0'));         
             elsif(rising_edge(clk)) then                                
                for index1 in 0 to 2 loop         
                   adder_out(index1)<=((34 downto 28=>product(index1)(27)) & product(index1))+adder_out(index1+1);              
                end loop;               
                adder_out(3)<=(34 downto 28=>product(3)(27)) & product(3);                      
            end if;          
        end process adder;      
     bpf_output<=adder_out(0)(29 downto 15);            
end bpf_behav;



entity multiplier is
  
  port 
  (  
    in1: in std_logic_vector(14 downto 0);
    in2:in std_logic_vector(12 downto 0);
    product:out std_logic_vector(27 downto 0)
  );
end multiplier;  
architecture multiplier_behav of multiplier is 
  begin 
         product<=in1*in2;  
   end multiplier_behav;

enter image description here


Solution

  • The adder is at 0 initially because you reset it correctly. After that the reset is not active anymore so the value assigned to the accumulator is defined by this piece of code:

     elsif(rising_edge(clk)) then                                
                    for index1 in 0 to 2 loop         
                       adder_out(index1)<=((34 downto 28=>product(index1)(27)) & product(index1))+adder_out(index1+1);              
                    end loop;               
                    adder_out(3)<=(34 downto 28=>product(3)(27)) & product(3);                      
                end if;
    

    When you get an Xvalue it means that one or more of the signals used to generate the value is an X, hence we need to analyze such values.

    Looking at the product waveforms we can see that before the reset it is all Xs. As soon as we exit the reset the assignment is then:

    adder_out(0)<=((34 downto 28=>product(0)(27)) & product(0))+adder_out(1); 
    adder_out(1)<=((34 downto 28=>product(1)(27)) & product(1))+adder_out(2); 
    adder_out(2)<=((34 downto 28=>product(2)(27)) & product(2))+adder_out(3); 
    adder_out(3)<= (34 downto 28=>product(3)(27)) & product(3);
    
    adder_out(0)<= XXXXX & XXX + 0 
    adder_out(1)<= XXXXX & XXX + 0 
    adder_out(2)<= XXXXX & XXX + 0 
    adder_out(3)<= XXXXX & XXX 
    

    The next clock cycle the product becomes defined, but now the X are in the adder itself, and they disappear one cycle at a time (starting from the last element because it does not use any adder in its assignment), until no Xs are there anymore (I use DDD to indicate data).

    
    cc n+1
    
    adder_out(0)<= DDDDD & DDD + XXX 
    adder_out(1)<= DDDDD & DDD + XXX 
    adder_out(2)<= DDDDD & DDD + XXX 
    adder_out(3)<= DDDDD & DDD 
    
    
    cc n+2
    
    adder_out(0)<= DDDDD & DDD + DDD 
    adder_out(1)<= DDDDD & DDD + XXX 
    adder_out(2)<= DDDDD & DDD + XXX 
    adder_out(3)<= DDDDD & DDD 
    
    
    cc n+2
    
    adder_out(0)<= DDDDD & DDD + DDD 
    adder_out(1)<= DDDDD & DDD + DDD 
    adder_out(2)<= DDDDD & DDD + XXX 
    adder_out(3)<= DDDDD & DDD 
    
    
    cc n+3
    
    adder_out(0)<= DDDDD & DDD + DDD 
    adder_out(1)<= DDDDD & DDD + DDD 
    adder_out(2)<= DDDDD & DDD + DDD 
    adder_out(3)<= DDDDD & DDD 
    

    How to fix this? product should be a defined value when is read by the accumulator. This can't be enforced before reset, so I think you should wait some cycles before reading it in your adder logic, or implement a valid signal to tell that the first result from the multiplier is ready.