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

Copy

parent a4f13ac0
No related branches found
No related tags found
No related merge requests found
-------------------------------------------------------------------------------
--
-- 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 one or multiple datastreams.
--
-- Description: The poly phase prefilter function is based on a taps memory, a
-- coefficients memory, a filter and a control unit.
-- The control unit writes the incoming data to the taps memory,
-- along with the historical tap data. It also drives the read
-- addresses for both the taps- and the coefficients memory. The
-- output of the taps memory and the coefficients memory are
-- connected to the input of the filter unit that peforms the
-- actual filter function(multiply and accumulate).
-- The prefilter support multiple streams that share the same
-- filtercoefficients.
--
-- The follwing example shows the working for the poly phase prefilter
-- where nof_bands = 4 and nof_taps = 2. The total number of coef-
-- ficients is 8. For the given input stream all the multiplications and
-- additions are given that are required to generate the given output
-- stream. Note that every input sample is used tap=2 times.
--
-- Incoming datastream: a0 a1 a2 a3 b0 b1 b2 b3 c0 c1 c2 c3 d0 d1 d2 d3 ....
--
-- A0 = coef0*a0 + coef1*b0
-- A1 = coef2*a1 + coef3*b1
-- A2 = coef4*a2 + coef5*b2
-- A3 = coef6*a3 + coef7*b3
--
-- B0 = coef0*b0 + coef1*c0
-- B1 = coef2*b1 + coef3*c1
-- B2 = coef4*b2 + coef5*c2
-- B3 = coef6*b3 + coef7*c3
--
-- C0 = coef0*c0 + coef1*d0
-- C1 = coef2*c1 + coef3*d1
-- C2 = coef4*c2 + coef5*d2
-- C3 = coef6*c3 + coef7*d3
--
-- D0 = coef0*d0 + coef1*e0
-- D1 = coef2*d1 + coef3*e1
-- D2 = coef4*d2 + coef5*e2
-- D3 = coef6*d3 + coef7*e3
--
-- Outgoing datastream: A0 A1 A2 A3 B0 B1 B2 B3 C0 C1 C2 C3 D0 D1 D2 D3
--
-- The filter coefficients can be written via the mm interface.
--
--
-- Remarks: .The taps memory introduces a z-delay of nof_bands dp_clk cycles.
--
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_single 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 : in std_logic_vector;
in_val : in std_logic;
out_dat : out std_logic_vector;
out_val : out std_logic
);
end fil_ppf_single;
architecture rtl of fil_ppf_single is
constant c_coefs_postfix : string := ".mif";
constant c_taps_mem_addr_w : natural := ceil_log2(g_fil_ppf.nof_bands * (2**g_fil_ppf.nof_chan));
constant c_coef_mem_addr_w : natural := ceil_log2(g_fil_ppf.nof_bands);
constant c_taps_mem_delay : natural := g_fil_ppf_pipeline.mem_delay;
constant c_coef_mem_delay : natural := g_fil_ppf_pipeline.mem_delay;
constant c_taps_mem_data_w : natural := g_fil_ppf.in_dat_w*g_fil_ppf.nof_taps;
constant c_coef_mem_data_w : natural := g_fil_ppf.coef_dat_w;
constant c_taps_mem : t_c_mem := (latency => c_taps_mem_delay,
adr_w => c_taps_mem_addr_w,
dat_w => c_taps_mem_data_w,
nof_dat => g_fil_ppf.nof_bands * (2**g_fil_ppf.nof_chan),
init_sl => '0'); -- use '0' instead of 'X' to avoid RTL RAM simulation warnings due to read before write
constant c_coef_mem : t_c_mem := (latency => c_coef_mem_delay,
adr_w => c_coef_mem_addr_w,
dat_w => c_coef_mem_data_w,
nof_dat => g_fil_ppf.nof_bands,
init_sl => '0'); -- use '0' instead of 'X' to avoid RTL RAM simulation warnings due to read before write
signal ram_coefs_mosi_arr : t_mem_mosi_arr(g_fil_ppf.nof_taps-1 downto 0);
signal ram_coefs_miso_arr : t_mem_miso_arr(g_fil_ppf.nof_taps-1 downto 0) := (others => c_mem_miso_rst);
signal taps_wren : std_logic;
signal taps_rdaddr : std_logic_vector(c_taps_mem_addr_w-1 downto 0);
signal taps_wraddr : std_logic_vector(c_taps_mem_addr_w-1 downto 0);
signal taps_mem_out_vec : std_logic_vector(c_taps_mem_data_w*g_fil_ppf.nof_streams-1 downto 0);
signal taps_mem_in_vec : std_logic_vector(c_taps_mem_data_w*g_fil_ppf.nof_streams-1 downto 0);
signal coef_rdaddr : std_logic_vector(c_coef_mem_addr_w-1 downto 0);
signal coef_vec : std_logic_vector(c_coef_mem_data_w*g_fil_ppf.nof_taps-1 downto 0);
begin
---------------------------------------------------------------
-- MEMORY FOR THE HISTORICAL TAP DATA
---------------------------------------------------------------
gen_taps_mems : for I in 0 to g_fil_ppf.nof_streams-1 generate
u_taps_mem : entity common_lib.common_ram_r_w
generic map (
g_ram => c_taps_mem,
g_init_file => "UNUSED" -- assume block RAM gets initialized to '0' by default in simulation
)
port map (
rst => dp_rst,
clk => dp_clk,
wr_en => taps_wren,
wr_adr => taps_wraddr,
wr_dat => taps_mem_in_vec((I+1)*c_taps_mem_data_w-1 downto I*c_taps_mem_data_w),
rd_en => '1',
rd_adr => taps_rdaddr,
rd_dat => taps_mem_out_vec((I+1)*c_taps_mem_data_w-1 downto I*c_taps_mem_data_w),
rd_val => open
);
end generate;
---------------------------------------------------------------
-- 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
u_mem_mux_coef : entity common_lib.common_mem_mux
generic map (
g_nof_mosi => g_fil_ppf.nof_taps,
g_mult_addr_w => c_coef_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
);
---------------------------------------------------------------
-- GENERATE THE COEFFICIENT MEMORIES
---------------------------------------------------------------
-- For every tap a unique memory is instantiated that holds
-- the corresponding coefficients for all the bands.
gen_coef_mems : for I in 0 to g_fil_ppf.nof_taps-1 generate
u_coef_mem : entity common_lib.common_ram_crw_crw
generic map (
g_ram => c_coef_mem,
-- Sequence number and ".hex" extensie are added to the relative path in case a ram file is provided.
g_init_file => sel_a_b(g_coefs_file_prefix = "UNUSED", g_coefs_file_prefix, g_coefs_file_prefix & "_" & NATURAL'IMAGE(g_file_index_arr(I)) & c_coefs_postfix)
)
port map (
-- MM side
rst_a => mm_rst,
clk_a => mm_clk,
wr_en_a => ram_coefs_mosi_arr(I).wr,
wr_dat_a => ram_coefs_mosi_arr(I).wrdata(g_fil_ppf.coef_dat_w-1 downto 0),
adr_a => ram_coefs_mosi_arr(I).address(c_coef_mem.adr_w-1 downto 0),
rd_en_a => ram_coefs_mosi_arr(I).rd,
rd_dat_a => ram_coefs_miso_arr(I).rddata(g_fil_ppf.coef_dat_w-1 downto 0),
rd_val_a => ram_coefs_miso_arr(I).rdval,
-- Datapath side
rst_b => dp_rst,
clk_b => dp_clk,
wr_en_b => '0',
wr_dat_b => (others =>'0'),
adr_b => coef_rdaddr,
rd_en_b => '1',
rd_dat_b => coef_vec((I+1)*c_coef_mem_data_w-1 downto I*c_coef_mem_data_w),
rd_val_b => open
);
end generate;
-- Address the coefficients, taking into account the nof_chan. The coefficients will only be
-- updated if all 2**nof_chan time-multiples signals are processed.
coef_rdaddr <= taps_rdaddr(c_taps_mem_addr_w-1 downto (c_taps_mem_addr_w - c_coef_mem_addr_w));
---------------------------------------------------------------
-- FILTER CONTROL UNIT
---------------------------------------------------------------
-- The control unit receives the input data and writes it to
-- the tap memory, along with the historical tap data.
-- It also controls the reading of the coefficients memory.
u_fil_ctrl : entity work.fil_ppf_ctrl
generic map (
g_fil_ppf_pipeline => g_fil_ppf_pipeline,
g_fil_ppf => g_fil_ppf
)
port map (
clk => dp_clk,
rst => dp_rst,
in_dat => in_dat,
in_val => in_val,
taps_rdaddr => taps_rdaddr,
taps_wraddr => taps_wraddr,
taps_wren => taps_wren,
taps_in_vec => taps_mem_out_vec,
taps_out_vec => taps_mem_in_vec,
out_val => out_val
);
---------------------------------------------------------------
-- FILTER UNIT
---------------------------------------------------------------
-- The actual filter unit that performs the filter operations:
-- multiplications and additions.
gen_filter_units : for I in 0 to g_fil_ppf.nof_streams-1 generate
u_filter : entity work.fil_ppf_filter
generic map (
g_fil_ppf_pipeline => g_fil_ppf_pipeline,
g_fil_ppf => g_fil_ppf
)
port map (
clk => dp_clk,
rst => dp_rst,
taps => taps_mem_out_vec((I+1)*c_taps_mem_data_w-1 downto I*c_taps_mem_data_w),
coefs => coef_vec,
result => out_dat((I+1)*g_fil_ppf.out_dat_w-1 downto I*g_fil_ppf.out_dat_w)
);
end generate;
end rtl;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment