You are on page 1of 8

-- FIR Filter Model --- +-----------------------------+ -- | -- | -- | -- | Copyright 1996 DOULOS Library: DSP | | | |

designer : Tim Pagden opened: 30 Sep 1995

-- +-----------------------------+

library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.types.all;

library maths; use maths.maths_class.all; library matrix; use matrix.matrix_class.all;

entity FIR_32tap_8_8 is port ( a : in b : in std_logic_vector(7 downto 0); logic_8_vector(31 downto 0); std_logic; std_logic;

clock : in reset : in

y : out std_logic_vector(20 downto 0) );

end FIR_32tap_8_8;

architecture behavioural of FIR_32tap_8_8 is

constant number_of_taps: integer := 32;

signal data_table: single_vector(number_of_taps-1 downto 0); signal coefficient_table: single_vector(number_of_taps-1 downto 0);

begin

-- y <= sum_over (0, k-1, a((k-1)-i), b(i)) -- coefficient_table <= b;

fir_algorithm: process (clock) variable data_out : single; variable fir_result : single; variable data_table_var: single_vector(number_of_taps-1 downto 0); -- the interface coeff table assignment really ought to be handled at the entity

variable coefficient_table_var: single_vector(number_of_taps-1 downto 0); variable tmp : single_vector(number_of_taps-1 downto 0); variable tmp2 : single; variable tmp3 : single_vector(number_of_taps-1 downto 0); variable tmp4 : integer; variable num_taps_minus_1 : integer; variable y_result : signed(20 downto 0);

begin if rising_edge(clock) then -data_table_var := data_table(number_of_taps-2 downto 0); data_table(number_of_taps-1) &

-- putting the coeff table in a loop like this allows dynamic coeff updating for i in 0 to number_of_taps-1 loop coefficient_table_var(i) := single(to_integer(unsigned(b(i))))/127.0; end loop; -- tmp := reverse_order(data_table_var);

-- tmp2 := 0.15;

+ to_integer(a);

data_table_var := data_table; tmp2 := single(to_integer(signed(a))); data_table_var := shift_fifo (data_table_var, tmp2); -- fifo => data_table <= data_table_var; data_in =>

-- tmp3 := reverse_order(data_table_var); -- tmp4 := 0; num_taps_minus_1 := number_of_taps-1; fir_result := sum_of_products ( lower_limit => 0, upper_limit => number_of_taps-1, a_in => reverse_order(data_table_var), b_in => coefficient_table_var ); y_result := to_signed(integer(fir_result), y_result'length); y <= std_logic_vector(y_result);

end if; end process;

end behavioural;

VHDL code for a 4 tap FIR filter


Finite Impulse Response(FIR) filters are one of the two main type of filters available for signal processing. As the name suggests the output of a FIR filter is finite and it settles down to zero after some time. For a basic FAQ on FIR filters see this post by dspguru. A FIR filter output, 'y' can be defined by the following equation:

Here, 'y' is the filter output, 'x' in the input signal and 'b' is the filter coefficients. 'N' is the filter order. The higher the value of N is, the more complex the filter will be. For writing the code in VHDL I have referred to the paper, VHDL generation of optimized FIR filters , available online. You can say I have coded the exact block diagram available in the paper, "Figure 2". This is a 4 tap filter. That means the order of the filter is 4 and so it has 4 coefficients. I have defined the input as signed type of 8 bits wide. The output is also of signed type with 16 bits width. The design contains two files. One is the main file with all multiplications and adders defined in it, and another for defining the D flip flop operation. The main file is given below:

library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity fir_4tap is port( Clk : in std_logic; --clock signal Xin : in signed(7 downto 0); --input signal Yout : out signed(15 downto 0) --filter output ); end fir_4tap; architecture Behavioral of fir_4tap is component DFF is port( Q : out signed(15 downto 0); --output connected to the adder Clk :in std_logic; -- Clock input D :in signed(15 downto 0) -- Data input from the MCM block. ); end component; signal H0,H1,H2,H3 : signed(7 downto 0) := (others => '0'); signal MCM0,MCM1,MCM2,MCM3,add_out1,add_out2,add_out3 : sign ed(15 downto 0) := (others => '0'); signal Q1,Q2,Q3 : signed(15 downto 0) := (others => '0'); begin

--filter coefficient initializations. --H = [-2 -1 3 4]. H0 <= to_signed(-2,8); H1 <= to_signed(-1,8); H2 <= to_signed(3,8); H3 <= to_signed(4,8); --Multiple constant multiplications. MCM3 <= H3*Xin; MCM2 <= H2*Xin; MCM1 <= H1*Xin; MCM0 <= H0*Xin; --adders add_out1 <= Q1 + MCM2; add_out2 <= Q2 + MCM1; add_out3 <= Q3 + MCM0; --flipflops(for dff1 : DFF port dff2 : DFF port dff3 : DFF port introducing a delay). map(Q1,Clk,MCM3); map(Q2,Clk,add_out1); map(Q3,Clk,add_out2);

--an output produced at every positive edge of clock cycle. process(Clk) begin if(rising_edge(Clk)) then Yout <= add_out3; end if; end process; end Behavioral;
VHDL code for the component DFF is given below:

library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity DFF is port( Q : out signed(15 downto 0); --output connected to the adder Clk :in std_logic; -- Clock input D :in signed(15 downto 0) -- Data input from the MCM block. ); end DFF;

architecture Behavioral of DFF is signal qt : signed(15 downto 0) := (others => '0'); begin Q <= qt; process(Clk) begin if ( rising_edge(Clk) ) then qt <= D; end if; end process; end Behavioral;
I have written a small test bench code for testing the design. It contains 8 test inputs which are serially applied to the filter module. See below:

LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE ieee.numeric_std.ALL; ENTITY tb IS END tb; ARCHITECTURE behavior OF tb IS signal Clk : std_logic := '0'; signal Xin : signed(7 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_4tap PORT MAP ( Clk => Clk, 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 wait for Clk_period*2; Xin <= to_signed(-3,8); wait for clk_period*1; Xin <= to_signed(1,8); wait for clk_period*1; Xin <= to_signed(0,8); wait for clk_period*1; Xin <= to_signed(-2,8); wait for clk_period*1; Xin <= to_signed(-1,8); wait for clk_period*1; Xin <= to_signed(4,8); wait for clk_period*1; Xin <= to_signed(-5,8); wait for clk_period*1; Xin <= to_signed(6,8); wait for clk_period*1; Xin <= to_signed(0,8); wait; end process; END;
The simulation waveform is given below:

The code is synthesisable and with a few changes can be ported for a higher order filter.

You might also like