OpenCores
URL https://opencores.org/ocsvn/astron_filter/astron_filter/trunk

Subversion Repositories astron_filter

[/] [astron_filter/] [trunk/] [fil_ppf_single.vhd] - Rev 2

Compare with Previous | Blame | View Log

-------------------------------------------------------------------------------
--
-- 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 (PPF) function on one or multiple datastreams.
--
-- Description:
--   The poly phase prefilter (PPF) 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 filter coefficients. The
--   filter coefficients can be written and read via the MM interface. 
--
--   The PPF introduces a data valid latency of 1 tap, so nof_bands samples.
--   The nof_bands = nof_points of the FFT that gets the PPF output.
--
--   The following example shows the working for the poly phase prefilter
--   where nof_bands=4 and nof_taps=2. The total number of coefficients 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 nof_taps=2 times.
--                  
--   Time:                t0 t1 ....
--   Incoming datastream: a0 a1 a2 a3 b0 b1 b2 b3 c0 c1 c2 c3 ....
--   Outgoing datastream:             A0 A1 A2 A3 B0 B1 B2 B3 C0 C1 C2 C3 ....
--
--              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
--
-- Remarks:
-- .  See also description tb_fil_ppf_single.vhd for more info.
--
library IEEE, common_pkg_lib, astron_ram_lib, astron_mm_lib;
use IEEE.std_logic_1164.ALL;
use IEEE.numeric_std.ALL;
use common_pkg_lib.common_pkg.ALL; 
use astron_ram_lib.common_ram_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             := "hex/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(g_fil_ppf.nof_streams*g_fil_ppf.in_dat_w-1 downto 0);
    in_val         : in  std_logic;  
    out_dat        : out std_logic_vector(g_fil_ppf.nof_streams*g_fil_ppf.out_dat_w-1 downto 0);
    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 astron_ram_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 astron_mm_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 astron_ram_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;                                                                                
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.