====== 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;