Skip to content
Snippets Groups Projects
Commit 80b6d852 authored by Pepping's avatar Pepping
Browse files

Copied from old tree

parent ef9e6486
No related branches found
No related tags found
No related merge requests found
-------------------------------------------------------------------------------
-- Author: Harm Jan Pepping : pepping at astron.nl: 2012
-- Copyright (C) 2012
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-------------------------------------------------------------------------------
library ieee, common_lib;
use IEEE.std_logic_1164.all;
use common_lib.common_pkg.all;
package fil_pkg is
-- Parameters for the (wideband) poly phase filter.
type t_fil_ppf is record
wb_factor : natural; -- = 1, the wideband factor
nof_chan : natural; -- = default 0, defines the number of channels (=time-multiplexed input signals): nof channels = 2**nof_chan
nof_bands : natural; -- = 1024, the number of subbands is N (N=nof_points of the FFT)
nof_taps : natural; -- = 16, the number of FIR taps per subband
nof_streams : natural; -- = 1, the number of streams that are served by the same coefficients.
in_dat_w : natural; -- = 8, number of input bits per stream
out_dat_w : natural; -- = 16, number of output bits per stream
coef_dat_w : natural; -- = 16, data width of the FIR coefficients
end record;
constant c_fil_ppf : t_fil_ppf := (1, 0, 1024, 16, 1, 8, 16, 16);
-- Definitions for fil slv array (an array can not have unconstraint elements, so choose sufficiently wide 32 bit slv elements)
subtype t_fil_slv_arr is t_slv_32_arr; -- use subtype to ease interfacing to existing types and to have central definition for filter components
constant c_fil_data_w : natural := 32; -- match slv width of t_fil_slv_arr
-- Record with the pipeline settings for the filter units.
type t_fil_ppf_pipeline is record
-- generic for the taps and coefficients memory
mem_delay : natural; -- = 1
-- generics for the multiplier in in the filter unit
mult_input : natural; -- = 1
mult_product : natural; -- = 1
mult_output : natural; -- = 1
-- generics for the adder tree in in the filter unit
adder_stage : natural; -- = 1
-- generics for the requantizer in the filter unit
requant_remove_lsb : natural; -- = 1
requant_remove_msb : natural; -- = 0
end record;
constant c_fil_ppf_pipeline : t_fil_ppf_pipeline := (1, 1, 1, 1, 1, 1, 0);
end package fil_pkg;
package body fil_pkg is
end fil_pkg;
-------------------------------------------------------------------------------
--
-- Copyright (C) 2009
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-------------------------------------------------------------------------------
-- Purpose: Controlling the data streams for the filter units
--
-- Description: This unit prepairs the data streams for the ppf_filter
-- unit. Incoming data (in_dat) is combined with stored
-- data (taps_in_vec) to generate a new vector that is
-- offered to the filter unit: taps_out_vec.
--
-- It also delays the in_val signal in order to generate
-- the out_val that is proper alligned with the output data
-- that is coming from the filter unit.
--
library IEEE, common_lib;
use IEEE.std_logic_1164.ALL;
use IEEE.numeric_std.ALL;
use common_lib.common_pkg.ALL;
use work.fil_pkg.ALL;
entity fil_ppf_ctrl is
generic (
g_fil_ppf : t_fil_ppf;
g_fil_ppf_pipeline : t_fil_ppf_pipeline
);
port (
rst : in std_logic := '0';
clk : in std_logic;
in_dat : in std_logic_vector;
in_val : in std_logic;
taps_in_vec : in std_logic_vector;
taps_rdaddr : out std_logic_vector;
taps_wraddr : out std_logic_vector;
taps_wren : out std_logic;
taps_out_vec: out std_logic_vector;
out_val : out std_logic
);
end fil_ppf_ctrl;
architecture rtl of fil_ppf_ctrl is
type t_in_dat_delay is array (g_fil_ppf_pipeline.mem_delay downto 0) of std_logic_vector(g_fil_ppf.in_dat_w*g_fil_ppf.nof_streams-1 downto 0);
constant c_addr_w : natural := ceil_log2(g_fil_ppf.nof_bands * (2**g_fil_ppf.nof_chan));
constant c_ctrl_latency : natural := 1; -- due to taps_out_vec register
constant c_mult_latency : natural := g_fil_ppf_pipeline.mult_input + g_fil_ppf_pipeline.mult_product + g_fil_ppf_pipeline.mult_output;
constant c_adder_latency : natural := ceil_log2(g_fil_ppf.nof_taps) * g_fil_ppf_pipeline.adder_stage;
constant c_filter_zdly : natural := g_fil_ppf.nof_bands * (2**g_fil_ppf.nof_chan);
constant c_tot_latency : natural := g_fil_ppf_pipeline.mem_delay + c_ctrl_latency + c_mult_latency +
c_adder_latency + c_filter_zdly + g_fil_ppf_pipeline.requant_remove_lsb +
g_fil_ppf_pipeline.requant_remove_msb;
constant c_single_taps_vec_w : natural := g_fil_ppf.in_dat_w*g_fil_ppf.nof_taps;
constant c_taps_vec_w : natural := c_single_taps_vec_w*g_fil_ppf.nof_streams;
type reg_type is record
in_dat_arr : t_in_dat_delay; -- Input register for the data
val_dly : std_logic_vector(c_tot_latency-1 downto 0); -- Delay register for the valid signal
rd_addr : std_logic_vector(c_addr_w-1 downto 0); -- The read address
wr_addr : std_logic_vector(c_addr_w-1 downto 0); -- The write address
wr_en : std_logic; -- Write enable signal for the taps memory
taps_out_vec : std_logic_vector(c_taps_vec_w-1 downto 0); -- Output register containing the next taps data
end record;
signal r, rin : reg_type;
begin
comb : process(r, rst, in_val, in_dat, taps_in_vec)
variable v : reg_type;
begin
v := r;
v.wr_en := '0';
-- Perform the shifting for the shiftregister for the valid signal and the input data:
v.val_dly(0) := in_val;
v.val_dly(c_tot_latency-1 downto 1) := r.val_dly(c_tot_latency-2 downto 0);
v.in_dat_arr(0) := RESIZE_SVEC(in_dat, r.in_dat_arr(0)'LENGTH);
v.in_dat_arr(g_fil_ppf_pipeline.mem_delay downto 1) := r.in_dat_arr(g_fil_ppf_pipeline.mem_delay-1 downto 0);
if(r.val_dly(0) = '1') then -- Wait for incoming data
v.rd_addr := INCR_UVEC(r.rd_addr, 1);
end if;
if(r.val_dly(g_fil_ppf_pipeline.mem_delay+1) = '1') then
v.wr_addr := INCR_UVEC(r.wr_addr, 1);
end if;
if(r.val_dly(g_fil_ppf_pipeline.mem_delay) = '1') then
for I in 0 to g_fil_ppf.nof_streams-1 loop
v.taps_out_vec((I+1)*c_single_taps_vec_w-1 downto I*c_single_taps_vec_w) := taps_in_vec((I+1)*c_single_taps_vec_w - g_fil_ppf.in_dat_w -1 downto I*c_single_taps_vec_w) & r.in_dat_arr(g_fil_ppf_pipeline.mem_delay)((I+1)*g_fil_ppf.in_dat_w-1 downto I*g_fil_ppf.in_dat_w);
end loop;
--v.taps_out_vec := taps_in_vec(taps_in_vec'HIGH - g_fil_ppf.in_dat_w downto 0) & r.in_dat_arr(g_fil_ppf_pipeline.mem_delay);
v.wr_en := '1';
end if;
if(rst = '1') then
v.in_dat_arr := (others => (others => '0'));
v.val_dly := (others => '0');
v.rd_addr := (others => '0');
v.wr_addr := (others => '0');
v.wr_en := '0';
v.taps_out_vec := (others => '0');
end if;
rin <= v;
end process comb;
regs : process(clk)
begin
if rising_edge(clk) then
r <= rin;
end if;
end process;
taps_rdaddr <= r.rd_addr;
taps_wraddr <= r.wr_addr;
taps_wren <= r.wr_en;
taps_out_vec <= r.taps_out_vec;
out_val <= r.val_dly(c_tot_latency-1);
end rtl;
-------------------------------------------------------------------------------
--
-- Copyright (C) 2012
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-------------------------------------------------------------------------------
-- Purpose: A FIR filter implementation.
--
-- Description: This unit instantiates a multiplier for every tap.
-- All output of the mutipliers are added using an
-- adder-tree structure.
--
-- Remarks: .
--
library IEEE, common_lib;
use IEEE.std_logic_1164.ALL;
use IEEE.numeric_std.ALL;
use common_lib.common_pkg.ALL;
use work.fil_pkg.ALL;
entity fil_ppf_filter is
generic (
g_fil_ppf : t_fil_ppf;
g_fil_ppf_pipeline : t_fil_ppf_pipeline
);
port (
clk : in std_logic;
rst : in std_logic;
taps : in std_logic_vector;
coefs : in std_logic_vector;
result : out std_logic_vector
);
end fil_ppf_filter;
architecture rtl of fil_ppf_filter is
constant c_prod_w : natural := g_fil_ppf.in_dat_w + g_fil_ppf.coef_dat_w - c_sign_w; -- skip double sign bit
constant c_gain_w : natural := 0; -- no need for adder bit growth so fixed 0, because filter coefficients should have DC gain <= 1.
-- The adder tree bit growth depends on DC gain of FIR coefficients, not on ceil_log2(g_fil_ppf.nof_taps).
constant c_sum_w : natural := c_prod_w + c_gain_w;
constant c_ppf_lsb_w : natural := c_sum_w - g_fil_ppf.out_dat_w;
signal prod_vec : std_logic_vector(g_fil_ppf.nof_taps*c_prod_w-1 downto 0);
signal adder_out : std_logic_vector(c_sum_w-1 downto 0) := (others => '0');
signal requant_out : std_logic_vector(g_fil_ppf.out_dat_w-1 downto 0);
signal in_taps : std_logic_vector(g_fil_ppf.in_dat_w*g_fil_ppf.nof_taps-1 downto 0);
begin
in_taps <= taps; -- Use this help signal to create a 'HIGH downto 0 vector again.
---------------------------------------------------------------
-- GENERATE THE MUTIPLIERS
---------------------------------------------------------------
-- For every tap a unique multiplier is instantiated that
-- multiplies the data tap with the corresponding filter coefficient
gen_multipliers : for I in 0 to g_fil_ppf.nof_taps-1 generate
u_multiplier : entity common_lib.common_mult(stratix4)
generic map (
g_in_a_w => g_fil_ppf.in_dat_w,
g_in_b_w => g_fil_ppf.coef_dat_w,
g_out_p_w => c_prod_w,
g_nof_mult => 1,
g_pipeline_input => g_fil_ppf_pipeline.mult_input,
g_pipeline_product => g_fil_ppf_pipeline.mult_product,
g_pipeline_output => g_fil_ppf_pipeline.mult_output,
g_representation => "SIGNED"
)
port map (
rst => rst,
clk => clk,
clken => '1',
in_a => in_taps((I+1)*g_fil_ppf.in_dat_w-1 downto I*g_fil_ppf.in_dat_w),
in_b => coefs((I+1)*g_fil_ppf.coef_dat_w-1 downto I*g_fil_ppf.coef_dat_w),
out_p => prod_vec((I+1)*c_prod_w-1 downto I*c_prod_w)
);
end generate;
---------------------------------------------------------------
-- ADDER TREE
---------------------------------------------------------------
-- The adder tree summarizes the outputs of all multipliers.
u_adder_tree : entity common_lib.common_adder_tree(str)
generic map (
g_representation => "SIGNED",
g_pipeline => g_fil_ppf_pipeline.adder_stage,
g_nof_inputs => g_fil_ppf.nof_taps,
g_dat_w => c_prod_w,
g_sum_w => c_sum_w
)
port map (
clk => clk,
in_dat => prod_vec,
sum => adder_out
);
u_requantize_addeer_output : entity common_lib.common_requantize
generic map (
g_representation => "SIGNED",
g_lsb_w => c_ppf_lsb_w,
g_lsb_round => TRUE,
g_lsb_round_clip => FALSE,
g_msb_clip => FALSE,
g_msb_clip_symmetric => FALSE,
g_pipeline_remove_lsb => g_fil_ppf_pipeline.requant_remove_lsb,
g_pipeline_remove_msb => g_fil_ppf_pipeline.requant_remove_msb,
g_in_dat_w => c_sum_w,
g_out_dat_w => g_fil_ppf.out_dat_w
)
port map (
clk => clk,
clken => '1',
in_dat => adder_out,
out_dat => requant_out,
out_ovr => open
);
result <= RESIZE_SVEC(requant_out, result'LENGTH);
end rtl;
-------------------------------------------------------------------------------
--
-- Copyright (C) 2012
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-------------------------------------------------------------------------------
-- Purpose: Performing a poly phase prefilter function on (multiple) wideband data stream.
--
--
-- Description: The poly phase prefilter function is applied on multiple inputs.
-- The incoming data must be divided over the inputs as shown in
-- the following example where the wideband factor is 4 (4 inputs).
--
-- Stream input 0 : t0, t4, t8, t12, t16...
-- Stream input 1 : t1, t5, t9, t13, t17...
-- Stream input 2 : t2, t6, t10, t14, t18...
-- Stream input 3 : t3, t7, t11, t15, t19...
--
-- Every input stream will be filtered by a single channel poly
-- phase prefilter unit.
-- It is also possible to offer multiple wideband input streams. Those
-- input streams will share the filtercoefficients. For a
-- system with wb_factor=4 and nof_streams=2 the following stream
-- inputs should be offered (s0t0 means stream 0, timestamp 0):
--
-- Stream input 0 : s0t0, s0t4, s0t8 , s0t12, s0t16...
-- Stream input 1 : s1t0, s1t4, s1t8 , s1t12, s1t16...
-- Stream input 2 : s0t1, s0t5, s0t9 , s0t13, s0t17...
-- Stream input 3 : s1t1, s1t5, s1t9 , s1t13, s1t17...
-- Stream input 4 : s0t2, s0t6, s0t10, s0t14, s0t18...
-- Stream input 5 : s1t2, s1t6, s1t10, s1t14, s1t18...
-- Stream input 6 : s0t3, s0t7, s0t11, s0t15, s0t19...
-- Stream input 7 : s1t3, s1t7, s1t11, s1t15, s1t19...
--
-- Remarks: .
--
library IEEE, common_lib;
use IEEE.std_logic_1164.ALL;
use IEEE.numeric_std.ALL;
use common_lib.common_pkg.ALL;
use common_lib.common_mem_pkg.ALL;
use work.fil_pkg.ALL;
entity fil_ppf_wide is
generic (
g_fil_ppf : t_fil_ppf := c_fil_ppf;
g_fil_ppf_pipeline : t_fil_ppf_pipeline := c_fil_ppf_pipeline;
g_file_index_arr : t_nat_natural_arr := array_init(0, 128, 1); -- default use the instance index as file index 0, 1, 2, 3, 4 ...
g_coefs_file_prefix : string := "../../data/coef" -- Relative path to the mif files that contain the initial data for the coefficients memories
); -- The sequence number and ".mif"-extension are added within the entity.
port (
dp_clk : in std_logic;
dp_rst : in std_logic;
mm_clk : in std_logic;
mm_rst : in std_logic;
ram_coefs_mosi : in t_mem_mosi;
ram_coefs_miso : out t_mem_miso := c_mem_miso_rst;
in_dat_arr : in t_fil_slv_arr(g_fil_ppf.nof_streams*g_fil_ppf.wb_factor-1 downto 0);
in_val : in std_logic;
out_dat_arr : out t_fil_slv_arr(g_fil_ppf.nof_streams*g_fil_ppf.wb_factor-1 downto 0);
out_val : out std_logic
);
end fil_ppf_wide;
architecture rtl of fil_ppf_wide is
type t_fil_ppf_arr is array(integer range <> ) of t_fil_ppf; -- An array of t_fil_ppf's generics.
type t_nat_natural_arr2 is array(integer range <> ) of t_nat_natural_arr(127 downto 0); -- An array of arrays, used to point to the right .mif files for the coefficients
type t_out_arr is array(integer range <> ) of std_logic_vector(g_fil_ppf.nof_streams*g_fil_ppf.out_dat_w -1 downto 0);
type t_in_arr is array(integer range <> ) of std_logic_vector(g_fil_ppf.nof_streams*g_fil_ppf.in_dat_w -1 downto 0);
----------------------------------------------------------
-- This function creates an array of t_fil_ppf generics
-- for the single channel poly phase filters that are
-- used to compose the multichannel(wideband) poly phase
-- filter. The array is based on the content of the g_fil_ppf
-- generic that belongs to the fil_ppf_w entity.
-- Only the nof_bands is modified.
----------------------------------------------------------
function func_create_generics_for_ppfs(input: t_fil_ppf) return t_fil_ppf_arr is
variable v_nof_bands : natural := input.nof_bands/input.wb_factor; -- The nof_bands for the single channel poly phase filters
variable v_return : t_fil_ppf_arr(input.wb_factor-1 downto 0) := (others => input); -- Variable that holds the return values
begin
for I in 0 to input.wb_factor-1 loop
v_return(I).nof_bands := v_nof_bands; -- The new number of bands
end loop;
return v_return;
end;
----------------------------------------------------------
-- Function that divids the input file index array into
-- "wb_factor" new file index arrays.
----------------------------------------------------------
function func_create_file_index_array(input: t_nat_natural_arr; wb_factor: natural; nof_taps: natural) return t_nat_natural_arr2 is
variable v_return : t_nat_natural_arr2(wb_factor-1 downto 0) := (others => input); -- Variable that holds the return values
begin
for I in 0 to wb_factor-1 loop
for J in 0 to nof_taps-1 loop
v_return(I)(J) := input(I*nof_taps+J);
end loop;
end loop;
return v_return;
end;
constant c_fil_ppf_arr : t_fil_ppf_arr(g_fil_ppf.wb_factor-1 downto 0) := func_create_generics_for_ppfs(g_fil_ppf);
constant c_file_index_arr2 : t_nat_natural_arr2(g_fil_ppf.wb_factor-1 downto 0) := func_create_file_index_array(g_file_index_arr, g_fil_ppf.wb_factor, g_fil_ppf.nof_taps);
constant c_mem_addr_w : natural := ceil_log2(g_fil_ppf.nof_bands * g_fil_ppf.nof_taps / g_fil_ppf.wb_factor);
signal ram_coefs_mosi_arr : t_mem_mosi_arr(g_fil_ppf.wb_factor-1 downto 0);
signal ram_coefs_miso_arr : t_mem_miso_arr(g_fil_ppf.wb_factor-1 downto 0) := (others => c_mem_miso_rst);
signal out_val_i : std_logic_vector(g_fil_ppf.wb_factor-1 downto 0);
signal out_arr_i : t_out_arr(g_fil_ppf.wb_factor-1 downto 0);
signal in_dat_vect_arr : t_in_arr(g_fil_ppf.wb_factor-1 downto 0);
begin
---------------------------------------------------------------
-- COMBINE MEMORY MAPPED INTERFACES
---------------------------------------------------------------
-- Combine the internal array of mm interfaces for the coefficents
-- memory to one array that is connected to the port of the fil_ppf_w
u_mem_mux_coef : entity common_lib.common_mem_mux
generic map (
g_nof_mosi => g_fil_ppf.wb_factor,
g_mult_addr_w => c_mem_addr_w
)
port map (
mosi => ram_coefs_mosi,
miso => ram_coefs_miso,
mosi_arr => ram_coefs_mosi_arr,
miso_arr => ram_coefs_miso_arr
);
gen_in_vect_wb : for I in 0 to g_fil_ppf.wb_factor-1 generate
gen_in_vect_streams : for J in 0 to g_fil_ppf.nof_streams-1 generate
--in_dat_vect_arr(I)((J+1)*g_fil_ppf.in_dat_w-1 downto J*g_fil_ppf.in_dat_w) <= in_dat_arr(J*g_fil_ppf.wb_factor+I)(g_fil_ppf.in_dat_w-1 downto 0);
in_dat_vect_arr(I)((J+1)*g_fil_ppf.in_dat_w-1 downto J*g_fil_ppf.in_dat_w) <= in_dat_arr(I*g_fil_ppf.nof_streams+J)(g_fil_ppf.in_dat_w-1 downto 0);
end generate;
end generate;
---------------------------------------------------------------
-- INSTANTIATE MULTIPLE SINGLE CHANNEL POLY PHASE FILTERS
---------------------------------------------------------------
gen_ppf_singles : for I in 0 to g_fil_ppf.wb_factor-1 generate
u_single_filter : entity work.fil_ppf_single
generic map (
g_fil_ppf => c_fil_ppf_arr(I),
g_fil_ppf_pipeline => g_fil_ppf_pipeline,
g_file_index_arr => c_file_index_arr2(I),
g_coefs_file_prefix => g_coefs_file_prefix
)
port map (
dp_clk => dp_clk,
dp_rst => dp_rst,
mm_clk => mm_clk,
mm_rst => mm_rst,
ram_coefs_mosi => ram_coefs_mosi_arr(I),
ram_coefs_miso => ram_coefs_miso_arr(I),
in_dat => in_dat_vect_arr(I),
in_val => in_val,
out_dat => out_arr_i(I),
out_val => out_val_i(I)
);
gen_in_vect_streams : for J in 0 to g_fil_ppf.nof_streams-1 generate
out_dat_arr(I*g_fil_ppf.nof_streams+J) <= RESIZE_SVEC(out_arr_i(I)((J+1)*g_fil_ppf.out_dat_w-1 downto J*g_fil_ppf.out_dat_w), out_dat_arr(I)'LENGTH);
end generate;
end generate;
out_val <= out_val_i(0);
end rtl;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment