====== FIR ====== The FIR consists of the following generic components: * [[.:fir#package|fir_lib]]: Package for the FIR component * [[.:fir#model|fir]]: N_taps-Wx x Wc Bits FIR (unrolled) * [[.:fir#in_shifter_fir]]: N_taps-Wx Bit shifter The FIR component can be verified with this testbench: * [[.:fir#testbench|test_fir]] (example image for testbench: {{:synthesizeable_vhdl-model-library:patras:lena256.raw|}}) This component implements an FIR (Finite Impulse Response) Filter. An FIR filter of N_taps coefficients is defined by the following equation: {{:synthesizeable_vhdl-model-library:patras:patras_fir_equation.svg?nolink&200|FIR Equation}} Each filter's sample, xn-1, has a word length of Wx-bits, while each filter's coefficient, Ci, has a word length of Wc-bits. The f(x) FIR's output has a word length of Wx-bits. ===== Package ===== -- ############################################################################ -- # Project : Leonardo CBT-Kernel # -- # # -- # Filename : fir.vhd # -- # # -- # Component : fir : N_taps-Wx x Wc Bits FIR (unrolled) # -- # # -- # Model : behav # -- # # -- # Designer : S. Theoharis # -- # Institute : VLSI Design Lab., University of Patras # -- # Date : 01.05.1999 # -- ############################################################################ library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; PACKAGE fir_lib IS -- Constant & SubType declarations. CONSTANT Wx : integer :=9; -- Word length for FIR's X sample. CONSTANT Wc : integer :=10; -- Word length for FIR's coefficient. CONSTANT N_taps : integer :=4; -- Number of FIR taps. i.e. 4,6,8 -- Shifter type for FIR component. TYPE fir_shifter_type IS ARRAY(N_taps-1 downto 0) OF std_ulogic_vector(Wx-1 downto 0); -- Coefficient type for FIR component. TYPE fir_coefficient_type IS ARRAY(N_taps-1 downto 0) OF std_ulogic_vector(Wc-1 downto 0); -- Definition of coefficient matrix. CONSTANT C_matrix : fir_coefficient_type := ( -- "1010100100", -- "0101110000", -- "0101010000", -- "1010110100", "0010110001", "1100100000", "0010101000", "1001100101" ); -- Function declaration. FUNCTION log2 (N : integer) RETURN integer; FUNCTION mult_shift_add (X : IN std_ulogic_vector; C : IN std_ulogic_vector; N_taps : integer) RETURN std_ulogic_vector; END fir_lib; ------------------------------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; PACKAGE BODY fir_lib IS --------------------------------------------- FUNCTION log2 (N : integer) RETURN integer IS VARIABLE temp : INTEGER; BEGIN IF N < 2 THEN RETURN 0; ELSE temp := 2; FOR i IN 1 TO (N/2) LOOP temp := 2 * temp; IF (temp = N) THEN RETURN (i+1); ELSIF (temp > N) THEN RETURN i; END IF; END LOOP; END IF; END; --------------------------------------------- FUNCTION mult_shift_add (X : IN std_ulogic_vector; C : IN std_ulogic_vector; N_taps : integer) RETURN std_ulogic_vector IS VARIABLE W : integer := X'length+C'length+log2(N_taps); VARIABLE result : std_ulogic_vector(W-1 downto 0); VARIABLE X_int,C_int,X_int_neg,t : integer; VARIABLE X_neg : std_ulogic_vector(X'length-1 downto 0); VARIABLE C_neg : std_ulogic_vector(C'length-1 downto 0); VARIABLE sign : std_ulogic; BEGIN -- Convert X operand. X_int_neg is the correct integer value of X. X_int := conv_integer(X); IF (X(X'length-1)='1') THEN X_neg := to_stdulogicvector(-X_int,X'length); ELSE X_neg := to_stdulogicvector(X_int,X'length); END IF; X_int_neg := conv_integer(X_neg); -- Convert C operand. C_neg is the correct std_ulogic_vector of C. C_int := conv_integer(C); IF (C(C'length-1)='1') THEN C_neg := to_stdulogicvector(-C_int,C'length); ELSE C_neg := to_stdulogicvector(C_int,C'length); END IF; -- What is the result's sign ? sign:= X(X'length-1) xor C(C'length-1); t:=0; FOR i IN 0 TO C_neg'length-1 LOOP IF (C_neg(i)='1') THEN t:=t+X_int_neg*(2**i); END IF; END LOOP; IF (sign='0') THEN result := to_stdulogicvector(t,W); ELSE result := to_stdulogicvector(-t,W); END IF; RETURN(result); END; END fir_lib; ===== Model ===== -- ############################################################################ -- # Project : Leonardo CBT-Kernel # -- # # -- # Filename : fir.vhd # -- # # -- # Component : fir : N_taps-Wx x Wc Bits FIR (unrolled) # -- # # -- # Model : behav # -- # # -- # Designer : S. Theoharis # -- # Institute : VLSI Design Lab., University of Patras # -- # Date : 01.05.1999 # -- ############################################################################ library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; USE work.fir_lib.ALL; ENTITY fir IS GENERIC ( N_taps : integer := 4; -- # FIR's taps. Wx : integer := 4; -- # bits/X sample. Wc : integer := 4 -- # bits/X sample. ); PORT ( X : IN std_ulogic_vector(Wx-1 downto 0); C : IN fir_coefficient_type; CLK : IN std_ulogic; RESETB : IN std_ulogic; Y : OUT std_ulogic_vector(Wx-1 downto 0) ); END fir; ARCHITECTURE behav OF fir IS -------------------------------------------------------------- COMPONENT in_shifter_fir GENERIC ( N_taps : integer := 4; -- # shifter's words. Wx : integer := 6 -- # bits/sample. ); PORT ( SI : IN std_ulogic_vector(Wx-1 downto 0); CLK_SHIFT : IN std_ulogic; RESETB : IN std_ulogic; SO : OUT fir_shifter_type ); END COMPONENT; SIGNAL result : std_ulogic_vector(Wx+Wc+log2(N_taps)-1 downto 0); SIGNAL X_shifter : fir_shifter_type; BEGIN -------------------------------------------------------------- X_shifter_component : in_shifter_fir GENERIC MAP ( N_taps=>N_taps, Wx=>Wx ) PORT MAP ( SI=>X, CLK_SHIFT=>CLK, RESETB=>RESETB, SO=>X_shifter ); -------------------------------------------------------------- PROCESS (X_shifter,C) VARIABLE t : integer; BEGIN t:=0; FOR i IN 0 TO N_taps-1 LOOP t:= t + conv_integer(mult_shift_add(X_shifter(i),C(i),N_taps)); END LOOP; result<=to_stdulogicvector(t,Wx+Wc+log2(N_taps)); END PROCESS; -------------------------------------------------------------- PROCESS (RESETB,CLK) BEGIN IF (RESETB='0') THEN Y <= (OTHERS=>'0'); ELSIF (rising_edge(CLK)) THEN Y <= result(Wx-1 downto 0); END IF; END PROCESS; -------------------------------------------------------------- END behav; ===== in_shifter_fir ===== -- ############################################################################ -- # Project : Leonardo CBT-Kernel # -- # # -- # Filename : in_shifter_fir.vhd # -- # # -- # Component : in_shifter_fir : N_taps-Wx Bit shifter # -- # # -- # Model : behav # -- # # -- # Designer : S. Theoharis # -- # Institute : VLSI Design Lab., University of Patras # -- # Date : 01.05.1999 # -- ############################################################################ library IEEE; use IEEE.std_logic_1164.all; USE work.fir_lib.ALL; ENTITY in_shifter_fir IS GENERIC ( N_taps : integer := 4; -- # shifter's words. Wx : integer := 6 -- # bits/sample. ); PORT ( SI : IN std_ulogic_vector(Wx-1 downto 0); CLK_SHIFT : IN std_ulogic; RESETB : IN std_ulogic; SO : OUT fir_shifter_type ); END in_shifter_fir; ARCHITECTURE behav OF in_shifter_fir IS SIGNAL shifter : fir_shifter_type; BEGIN -- Shifter process : shifts out N samples of W bits. Shifter_process : PROCESS(CLK_SHIFT,RESETB) BEGIN IF (RESETB='0') THEN FOR i IN N_taps-1 downto 0 LOOP shifter(i) <= (OTHERS=>'0'); END LOOP; ELSIF (rising_edge(CLK_SHIFT)) THEN shifter(N_taps-1 downto 0) <= shifter(N_taps-2 downto 0) & SI; END IF; END PROCESS Shifter_process; SO <= shifter; END behav; ===== Testbench ===== -- ############################################################################ -- # Project : Leonardo CBT-Kernel # -- # # -- # Filename : test_fir.vhd # -- # # -- # Component : test_fir : Test bench for an FIR of N_taps-Wx x Wc Bits. # -- # # -- # Model : behav # -- # # -- # Designer : S. Theoharis # -- # Institute : VLSI Design Lab., University of Patras # -- # Date : 01.05.1999 # -- ############################################################################ library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; USE std.TEXTIO.ALL; USE work.fir_lib.ALL; ENTITY test_fir IS END test_fir; ARCHITECTURE behav OF test_fir IS -------------------------------------------------------------- COMPONENT fir GENERIC ( N_taps : integer := 4; -- # shifter's words. Wx : integer := 6 -- # bits/sample. ); PORT ( X : IN std_ulogic_vector(Wx-1 downto 0); C : IN fir_coefficient_type; CLK : IN std_ulogic; RESETB : IN std_ulogic; Y : OUT std_ulogic_vector(Wx-1 downto 0) ); END COMPONENT; -------------------------------------------------------------- TYPE sample_values IS FILE OF CHARACTER; FILE file_in : sample_values IS IN "./lena256.raw"; FILE file_out : sample_values IS OUT "./lena256_fir.raw"; -- FILE file_in : sample_values IS "./lena256.raw"; -- FILE file_out : sample_values IS "./lena256_fir.raw"; SIGNAL CLK,RESETB : std_ulogic := '0'; SIGNAL X,Y : std_ulogic_vector(Wx-1 downto 0); SIGNAL FIR_Coefficients : fir_coefficient_type; CONSTANT BINARY_VALUES : boolean := FALSE; SIGNAL X_int,Y_int : integer RANGE 0 TO 2**Wx-1; BEGIN -------------------------------------------------------------- X_int <= conv_integer('0' & X); Y_int <= conv_integer('0' & Y); FIR_coefficients <= C_matrix; RESETB <= '0', '1' AFTER 20 ns; CLK <= '1' xor CLK AFTER 50 ns; -------------------------- -- X sample generation. -- -------------------------- PROCESS(RESETB,CLK) VARIABLE char : CHARACTER; VARIABLE tmp_X : integer; BEGIN -- (1) Create binary counter values ... IF (BINARY_VALUES) THEN IF (RESETB='0') THEN X <= (OTHERS=>'0'); ELSIF (rising_edge(CLK)) THEN tmp_X := conv_integer('0' & X); IF (tmp_X=2**Wx-1) THEN tmp_X := 0; ELSE tmp_X := tmp_X + 1; END IF; X <= to_stdulogicvector(tmp_X,Wx); END IF; ELSE -- (2) Read values from file ... IF (RESETB='0') THEN X <= (OTHERS=>'0'); ELSIF (rising_edge(CLK)) THEN IF (NOT ENDFILE(file_in)) THEN READ(file_in,char); X <= to_stdulogicvector(CHARACTER'pos(char),Wx); END IF; ASSERT (NOT ENDFILE(file_in)) REPORT "End of file ./do/lena256.raw" SEVERITY FAILURE; END IF; END IF; END PROCESS; -------------------------------------------------------------- FIR_inst : fir GENERIC MAP ( N_taps=>N_taps, Wx=>Wx ) PORT MAP ( X=>X, C=>FIR_coefficients, CLK=>CLK, RESETB=>RESETB, Y=>Y ); -------------------------------------------------------------- END behav;