-- Engineer: Mario Aicher -- Bruteforce FIR-Filter with Multiply Adder Blocks, Biased Rounding, -- Saturation. The coefficents are saved in the ROM (load .coe-Files) library IEEE; use IEEE.STD_LOGIC_1164.ALL; use ieee.numeric_std.all; -- ***************************************************************** -- NBTAB is equal to the number of filter coefficients. -- For every filter coefficient one Multiply Adder Block -- is generated. When using the characteristics of symmetrical -- FIR filters, it is possible to use only 1 Multiply Adder -- Block for 2 Coefficients. -- DSIZE determines the size of the input and output data. -- COESIZE determines the size of the coefficients -- datain (input data) and firout (filtered input data) are -- pretended to be in Q0.23 data format. -- The coefficients are in Q.0.15 data format. -- The coefficients can be designed using the MATLAB filterDesigner. -- All characteristics can be entered there. -- ***************************************************************** entity FIRFilter is generic( CHANNEL : natural := 0; -- 0: Left, 1: Right NBTAP : natural := 82; DSIZE : natural := 24; COESIZE : natural := 16); port( clk_100_MHz : in std_logic; datain : in std_logic_vector(DSIZE - 1 downto 0); firout : out std_logic_vector(DSIZE - 1 downto 0); new_sample : in std_logic); end FIRFilter; architecture Behavioral of FIRFilter is component blk_mem_gen_left port( clka : in std_logic; addra : in std_logic_vector(6 DOWNTO 0); douta : out std_logic_vector(15 DOWNTO 0)); end component; component blk_mem_gen_right port( clka : in std_logic; addra : in std_logic_vector(6 DOWNTO 0); douta : out std_logic_vector(15 DOWNTO 0)); end component; COMPONENT xbip_multadd PORT( CLK : in std_logic; CE : in std_logic; -- Clock Enable (active-HIGH) SCLR : in std_logic; -- Synchronous Clear (active-High) A : in std_logic_vector(DSIZE - 1 DOWNTO 0); -- A Input bus (multiplier operand 1) B : in std_logic_vector(COESIZE - 1 DOWNTO 0); -- B Input bus (multiplier operand 2) C : in std_logic_vector(2*DSIZE - 1 DOWNTO 0); -- C Input bus (operand 1 of add/sub operation) SUBTRACT : in std_logic; -- Controls Add/Subtract operation (High = subtraction, Low = addition) P : out std_logic_vector(2*DSIZE - 1 DOWNTO 0); -- Output bus PCOUT : out std_logic_vector(2*DSIZE - 1 DOWNTO 0)); -- Cascade Output END COMPONENT; signal state_reg: std_logic_vector(2 downto 0):="000"; alias s_load_data : std_logic is state_reg(0); alias s_start_calc : std_logic is state_reg(1); alias s_write_data : std_logic is state_reg(2); signal s_filtered_data : std_logic_vector(23 downto 0) := x"000000"; signal s_filter_data : std_logic_vector(DSIZE-1 downto 0) := x"000000"; -- ********************Biased Rounding****************************** constant s_rounding : std_logic_vector(2*DSIZE - 1 downto 0) := x"000000004000"; -- value for C for the first Multiply Adder Block -- ***************************************************************** -- ***************************************************************** -- Signals for Multiply Adder Blocks -- ***************************************************************** signal SCLR : std_logic := '0'; -- Synchronous Clear (active-HIGH) signal SUBTRACT : std_logic := '0'; -- LOW = Addition, HIGH = Subtraction -- ***************************************************************** -- ATTENTION: The necessary Bits for ADR_C depend on the number -- of filter coefficients. -- Example: filter order = 15 : -> 16 coefficients -- -> 2^L = 16 -> L = 4 -> 4 Bits necessary -- MAX represents the maximum value and has to be changed -- to fit the respective number of filter coefficients. -- ***************************************************************** signal ADR_C : std_logic_vector(6 downto 0) := b"0000000"; constant MAX : std_logic_vector(6 downto 0) := b"1010001"; -- => b"1010001" = 81 --> 0-81 -> and therefore 82 coefficents. signal COEF : std_logic_vector(COESIZE - 1 downto 0) := x"0000"; -- ***************************************************************** -- ASOP: Array Sum of Products with initialization to 0 -- Arraylength equals the number of filter coefficients. -- ASOP therefore equals an 48 Bit Akkumulator -- AND -- ACOEF: coefficients array with initialization to 0 -- Arraylength equals the number of filter coefficients. -- ***************************************************************** type ASOP is array (0 to NBTAP - 1) of std_logic_vector(2 * DSIZE - 1 downto 0); -- 48 Bit Akkumulator signal a_sop : ASOP := ( others => x"000000000000" ); type ACOEF is array (0 to NBTAP - 1) of std_logic_vector(0 to COESIZE - 1); signal a_coeff : ACOEF := ( others => x"0000" ); begin process begin wait until rising_edge(clk_100_MHz); state_reg <= state_reg(1 downto 0) & new_sample; if s_load_data = '1' then s_filter_data <= datain; end if; if s_write_data = '1' then firout <= s_filtered_data; end if; end process; -- ***************************************************************** -- Process to store the filter coefficients from the coe-File (that -- are saved in the ROM) into an array. -- ***************************************************************** ADR_CNT_COEF : process variable i : integer := 0; begin wait until rising_edge(clk_100_MHz); if(ADR_C = MAX) then a_coeff(NBTAP - 1) <= COEF; ADR_C <= (others => '0'); i := 0; else a_coeff(i) <= COEF; ADR_C <= std_logic_vector(unsigned(ADR_C) + 1); if i < NBTAP - 1 then i := i + 1; end if; end if; end process ADR_CNT_COEF; blk_mem_l: if CHANNEL = 0 generate blk_mem_left : blk_mem_gen_left PORT MAP( clka => clk_100_MHz, addra => ADR_C(6 downto 0), douta => COEF); end generate; blk_mem_r: if CHANNEL = 1 generate blk_mem_right : blk_mem_gen_right PORT MAP( clka => clk_100_MHz, addra => ADR_C(6 downto 0), douta => COEF); end generate; gen_l : for I in 0 to NBTAP - 1 generate begin g0_l : if I = 0 generate element_u0_l : xbip_multadd port map( CLK => clk_100_MHz, CE => s_start_calc, SCLR => SCLR, A => s_filter_data, B => a_coeff(NBTAP - 1), C => s_rounding, --no rounding: x"000000000000", SUBTRACT => SUBTRACT, P => a_sop(NBTAP - 1), PCOUT => open); end generate g0_l ; gi_l : if ( (I < (NBTAP - 1)) and (I > 0) ) generate element_ui_l : xbip_multadd port map( CLK => clk_100_MHz, CE => s_start_calc, SCLR => SCLR, A => s_filter_data, B => a_coeff(NBTAP - 1 - I), C => a_sop(NBTAP - I), SUBTRACT => SUBTRACT, P => a_sop(NBTAP - I - 1), PCOUT => open); end generate gi_l ; glast_l : if I = (NBTAP - 1) generate element_ui_l : xbip_multadd port map( CLK => clk_100_MHz, CE => s_start_calc, SCLR => SCLR, A => s_filter_data, B => a_coeff(0), C => a_sop(1), SUBTRACT => SUBTRACT, P => a_sop(0), PCOUT => open); end generate glast_l ; end generate gen_l ; s_filtered_data <= a_sop(0)(38 downto 15) when ((a_sop(0)(47 downto 38) = "0000000000") or (a_sop(0)(47 downto 38) = "1111111111" )) else x"7FFFFF" when ((a_sop(0)(47) = '0' ) and (a_sop(0)(46 downto 38) /= "000000000" )) else x"800001"; --((a_sop(0)(47) = '1' ) and (a_sop(0)(46 downto 38) /= "111111111" )); end Behavioral;