pp.320-322
入力4ビット幅、係数5個、よって出力11ビット幅のFIRフィルターを作る。単なる練習であって係数に意味はない。
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; --use ieee.math_real.all; entity fir_filter is generic( NUM_COEF : natural := 5; NUM_BITS : natural := 4; -- 乗算でビット数が最大2倍になるので2 * NUM_BITS、 -- さらにそれらを加算するので最大ceil(log2(NUM_COEF))増える。 OUT_BITS : natural := 11 -- 2 * NUM_BITS + integer(ceil(log2(real(NUM_COEF)))) ); port( clk, rst: in std_logic; x : in std_logic_vector(4-1 downto 0); y : out std_logic_vector(11-1 downto 0) ); end entity; architecture rtl of fir_filter is type int_array is array (0 to NUM_COEF-1) of integer range -2**(NUM_BITS-1) to 2**(NUM_BITS-1)-1; constant COEF: int_array := (-5,-1,1,2,3); type signed_array is array (natural range <>) of signed; signal shift_reg: signed_array(1 to NUM_COEF-1)( NUM_BITS-1 downto 0); signal prod : signed_array(0 to NUM_COEF-1)(2*NUM_BITS-1 downto 0); -- 乗算でビット幅が最大2倍必要になる。 signal sum : signed_array(0 to NUM_COEF-1)( OUT_BITS-1 downto 0); begin -- これがシフトレジジスタ process(clk, rst) begin if rst then -- (非同期)リセットがかかったら、 shift_reg <= (others => (others => '0')); -- 全部ゼロにするが、 elsif rising_edge(clk) then -- rising edgeのタイミングで、 shift_reg <= signed(x) & shift_reg(1 to NUM_COEF-2); -- 新値を最前列に挿入、最後列を追い出す。 end if; end process; -- 乗算結果をprod(i)に格納する。 prod(0) <= COEF(0) * signed(x); mult: for i in 1 to NUM_COEF-1 generate prod(i) <= to_signed(COEF(i), NUM_BITS) * shift_reg(i); end generate; -- 加算結果をsum(i)に格納する。 sum(0) <= resize(prod(0), OUT_BITS); adder: for i in 1 to NUM_COEF-1 generate sum(i) <= sum(i-1) + prod(i); end generate; y <= std_logic_vector(sum(NUM_COEF-1)); end architecture;