URL
https://opencores.org/ocsvn/astron_wpfb/astron_wpfb/trunk
Subversion Repositories astron_wpfb
Compare Revisions
- This comparison shows the changes necessary to convert path
/astron_wpfb
- from Rev 1 to Rev 2
- ↔ Reverse comparison
Rev 1 → Rev 2
/trunk/ASTRON_RP_1390_Wideband_Poly_Phase_Filter_Module_Description.pdf
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
trunk/ASTRON_RP_1390_Wideband_Poly_Phase_Filter_Module_Description.pdf
Property changes :
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: trunk/dp_block_gen_valid_arr.vhd
===================================================================
--- trunk/dp_block_gen_valid_arr.vhd (nonexistent)
+++ trunk/dp_block_gen_valid_arr.vhd (revision 2)
@@ -0,0 +1,352 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2011
+-- ASTRON (Netherlands Institute for Radio Astronomy)
+-- 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 .
+--
+-------------------------------------------------------------------------------
+
+-- Purpose : Generate the sosi control for a block of data based on the
+-- input valid
+-- Description:
+-- All input streams in the snk_in_arr must have the same sosi ctrl and info
+-- fields, such that the valid from snk_in_arr(0) is sufficient. Only the
+-- data, re, im in the snk_in_arr() differs. Therefore default connect snk_in
+-- = snk_in_arr(0).
+--
+-- When enabled (enable='1') then a block of g_nof_data_per_block words is
+-- output via src_out_arr under flow control by the input valid.
+--
+-- The input sync, sop and eop are ignored. For the output the sync, sop and
+-- eop are generated by counting the input valid and using
+-- g_nof_data_per_block for the output sop and eop, and using
+-- g_nof_blk_per_sync for the output sync.
+--
+-- The first active input valid starts the dp_block_gen_valid_arr. The first
+-- output block will have an output sync and every g_nof_blk_per_sync there
+-- is another output sync. Each output block is marked by output sop and
+-- output eop. The output sop also marks the output BSN. The output BSN is
+-- generated such that it increments for every block and that it restarts at
+-- 0 at every output sync.
+--
+-- Typically the size of g_nof_blk_per_sync*g_nof_data_per_block should match
+-- the number of input valids in an input sync interval.
+--
+-- The local BSN restarts at 0 for every new output sync interval, but instead
+-- of BSN = 0 the input BSN will be inserted at the first block in a new
+-- output sync interval. If the first output BSN should remain 0 then simply
+-- keep snk_in.bsn = 0.
+--
+-- g_nof_pages_bsn:
+-- The input BSN is not available in snk_in_arr(0) if the upstream component
+-- does not pass the BSN on. In that case the snk_in.sync and snk_in.bsn can
+-- be connected to some further upstream interface that does have the proper
+-- BSN. The input BSN is then buffered to align it with the local sync that is
+-- recreated for the output. This buffer is set via g_nof_pages_bsn. Typically
+-- g_nof_pages_bsn = 1 is sufficient to align the BSN along some DSP,
+-- components, because the latency in number of blocks of most DSP functions
+-- is much less than a sync interval. For a corner turn that operates per sync
+-- interval choosing g_nof_pages_bsn = 2 seems appropriate.
+--
+-- g_check_input_sync:
+-- When g_check_input_sync=FALSE then the input sync is ignored and the first
+-- input valid that occurs after when enable is active will start the local
+-- sync. When g_check_input_sync=TRUE then the block output for a new sync
+-- interval is only started if the input valid also coincides with a input
+-- sync. Until then all input valid are ignored and there is no output then.
+--
+-- Usage:
+-- * Example 1: Use snk_in.valid to recreate sync, sop, eop, bsn for a DP
+-- function that only passes on the valid.
+--
+-- - g_check_input_sync = False
+-- - g_nof_pages_bsn = 0
+--
+-- |------|
+-- snk_in_arr() ----*--------->| |----> src_out_arr
+-- | | dp |
+-- (0)| | block|
+-- | snk_in | gen |
+-- \--------->| arr |
+-- |------|
+--
+-- * Example 2: Use snk_in.valid to recreate sop, eop, bsn and check that the
+-- local sync is aligned with the snk_in.sync. If the snk_in.sync
+-- does not coincide with the local sync, then stop the output of
+-- blocks until the snk_in.sync occurs again.
+--
+-- - g_check_input_sync = True
+-- - g_nof_pages_bsn = 0
+--
+-- |------|
+-- snk_in_arr() ----*--------->| |----> src_out_arr
+-- | | dp |
+-- (0)| | block|
+-- | snk_in | gen |
+-- \--------->| arr |
+-- |------|
+--
+-- * Example 3: Use snk_in.valid to recreate sop, eop, bsn for a DP
+-- function that only passes on the valid. However use snk_in.sync
+-- to delay the snk_in.bsn by g_nof_pages_bsn to account for the
+-- block latency of the upstream DP components that did not pass
+-- on the snk_in.bsn.
+--
+-- - g_check_input_sync = False
+-- - g_nof_pages_bsn >= 1
+--
+-- |-----| snk_in_arr() |------|
+-- -----*-->| |-------*--------->| |----> src_out_arr
+-- | | DP | | | dp |
+-- | | | (0)| | block|
+-- | | | | snk_in | gen |
+-- | | | \--*------>| arr |
+-- sync| |-----| ^ |------|
+-- bsn | |
+-- \--------------------/
+--
+-- Remarks:
+-- . This dp_block_gen_valid_arr relates to:
+-- - dp_bsn_source.vhd
+-- - dp_block_gen.vhd when snk_in.valid is used for flow control (so when
+-- g_use_src_in=FALSE). This is why thsi dp_block_gen_valid_arr is called
+-- with '_valid' in its name.
+-- - dp_counter.vhd
+-- - dp_paged_sop_eop_reg.vhd
+-- - dp_fifo_info.vhd
+-- - dp_sync_checker.vhd
+-- . This dp_block_gen_valid_arr has no siso flow control, although enable
+-- could be used as siso.xon.
+-- . The channel, empty and err fields are passed on to the output. Typically
+-- these fields are not used with DSP data. However this scheme still
+-- allows setting these fields to a fixed value via snk_in.
+-- . Using g_check_input_sync=True is similar to using a dp_sync_checker in
+-- front of this dp_block_gen_valid_arr. However the advantage of
+-- dp_sync_checker is that it provides monitoring and control via MM.
+
+LIBRARY IEEE, common_pkg_lib, dp_pkg_lib, common_components_lib;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+USE common_pkg_lib.common_pkg.ALL;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+
+ENTITY dp_block_gen_valid_arr IS
+ GENERIC (
+ g_nof_streams : POSITIVE := 1;
+ g_nof_data_per_block : POSITIVE := 1;
+ g_nof_blk_per_sync : POSITIVE := 8;
+ g_check_input_sync : BOOLEAN := FALSE;
+ g_nof_pages_bsn : NATURAL := 0;
+ g_restore_global_bsn : BOOLEAN := FALSE
+ );
+ PORT (
+ rst : IN STD_LOGIC;
+ clk : IN STD_LOGIC;
+ -- Streaming sink
+ snk_in : IN t_dp_sosi; -- = snk_in_arr(0)
+ snk_in_arr : IN t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
+ -- Streaming source
+ src_out_arr : OUT t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
+ -- Control
+ enable : IN STD_LOGIC := '1' -- can connect via MM or could also connect to a src_in.xon
+ );
+END dp_block_gen_valid_arr;
+
+
+ARCHITECTURE rtl OF dp_block_gen_valid_arr IS
+
+ -- Check consistancy of the parameters, the function return value is void, because always true or abort due to failure
+ FUNCTION parameter_asserts(g_check_input_sync : BOOLEAN; g_nof_pages_bsn : NATURAL) return BOOLEAN IS
+ BEGIN
+ IF g_check_input_sync=TRUE THEN
+ ASSERT g_nof_pages_bsn=0 REPORT "When g_check_input_sync=TRUE then g_nof_pages_bsn must be 0." SEVERITY FAILURE;
+ -- because snk_in.sync and snk_in.bsn are then already aligned with the first snk_in.valid
+ END IF;
+ IF g_nof_pages_bsn>0 THEN
+ ASSERT g_check_input_sync=FALSE REPORT "When g_nof_pages_bsn>0 then g_check_input_sync must be FALSE." SEVERITY FAILURE;
+ -- because snk_in.sync and snk_in.bsn are then NOT aligned with the first snk_in.valid
+ END IF;
+ RETURN TRUE;
+ END parameter_asserts;
+
+ CONSTANT c_parameters_ok : BOOLEAN := parameter_asserts(g_check_input_sync, g_nof_pages_bsn);
+
+ TYPE t_state IS (s_sop, s_data, s_eop);
+
+ TYPE t_reg IS RECORD -- local registers
+ state : t_state;
+ data_cnt : NATURAL RANGE 0 TO g_nof_data_per_block;
+ blk_cnt : NATURAL RANGE 0 TO g_nof_blk_per_sync;
+ reg_sosi : t_dp_sosi;
+ END RECORD;
+
+ CONSTANT c_reg_rst : t_reg := (s_sop, 0, 0, c_dp_sosi_rst);
+
+ SIGNAL in_sosi : t_dp_sosi;
+ SIGNAL in_sync_wr_en : STD_LOGIC_VECTOR(g_nof_pages_bsn-1 DOWNTO 0);
+ SIGNAL in_bsn_buffer : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0);
+
+ SIGNAL out_sosi : t_dp_sosi;
+ SIGNAL nxt_src_out_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
+
+ -- Define the local registers in t_reg record
+ SIGNAL r : t_reg;
+ SIGNAL nxt_r : t_reg;
+
+BEGIN
+
+ p_clk : PROCESS(rst, clk)
+ BEGIN
+ IF rst='1' THEN
+ r <= c_reg_rst;
+ src_out_arr <= (OTHERS=>c_dp_sosi_rst);
+ ELSIF rising_edge(clk) THEN
+ r <= nxt_r;
+ src_out_arr <= nxt_src_out_arr;
+ END IF;
+ END PROCESS;
+
+ no_bsn_buffer : IF g_nof_pages_bsn=0 GENERATE
+ in_sosi <= snk_in;
+ END GENERATE;
+
+ gen_bsn_buffer : IF g_nof_pages_bsn>0 GENERATE
+ -- Buffer input BSN at each input sync
+ in_sync_wr_en <= (OTHERS=>snk_in.sync);
+
+ u_paged_bsn : ENTITY common_components_lib.common_paged_reg
+ GENERIC MAP (
+ g_data_w => c_dp_stream_bsn_w,
+ g_nof_pages => g_nof_pages_bsn
+ )
+ PORT MAP (
+ rst => rst,
+ clk => clk,
+ wr_en => in_sync_wr_en,
+ wr_dat => snk_in.bsn,
+ out_dat => in_bsn_buffer
+ );
+
+ p_snk_in : PROCESS(snk_in, in_bsn_buffer)
+ BEGIN
+ in_sosi <= snk_in;
+ in_sosi.sync <= '0';
+ in_sosi.bsn <= in_bsn_buffer;
+ END PROCESS;
+ END GENERATE;
+
+ -- Determine the output info and output ctrl using snk_in and r.reg_sosi
+ p_state : PROCESS(r, enable, in_sosi, snk_in)
+ BEGIN
+ nxt_r <= r;
+
+ -- default output in_sosi, hold output bsn and set the output ctrl to '0'
+ nxt_r.reg_sosi <= in_sosi;
+ nxt_r.reg_sosi.bsn <= r.reg_sosi.bsn;
+ nxt_r.reg_sosi.valid <= '0';
+ nxt_r.reg_sosi.sop <= '0';
+ nxt_r.reg_sosi.eop <= '0';
+ nxt_r.reg_sosi.sync <= '0';
+
+ CASE r.state IS
+ WHEN s_sop =>
+ nxt_r.data_cnt <= 0; -- For clarity init data count to 0 (because it will become 1 anyway at sop)
+ IF enable='0' THEN -- Check enable in state s_sop to ensure that disable cannot happen during a block
+ nxt_r.blk_cnt <= 0; -- If disabled then reset block generator and remain in this state
+ ELSE -- Enabled block generator
+ IF snk_in.valid='1' THEN -- Once enabled the complete block will be output dependent on the input valid
+ -- maintain blk_cnt for output sync interval, the blk_cnt is the local bsn that wraps at every sync
+ IF r.blk_cnt>=g_nof_blk_per_sync-1 THEN
+ nxt_r.blk_cnt <= 0;
+ ELSE
+ nxt_r.blk_cnt <= r.blk_cnt+1;
+ END IF;
+
+ -- create local sync and pass on input bsn at local sync
+ IF r.blk_cnt=0 THEN -- output sync starts at first input valid
+ nxt_r.reg_sosi.sync <= '1'; -- output sync for this block
+ nxt_r.reg_sosi.bsn <= in_sosi.bsn; -- output input bsn at sync
+ ELSE
+ nxt_r.reg_sosi.bsn <= TO_DP_BSN(r.blk_cnt); -- output local bsn for the subsequent blocks
+ END IF;
+
+ nxt_r.reg_sosi.valid <= '1';
+ nxt_r.reg_sosi.sop <= '1';
+
+ IF g_nof_data_per_block=1 THEN
+ nxt_r.reg_sosi.eop <= '1'; -- single word block
+ ELSE
+ nxt_r.data_cnt <= 1; -- start of multi word block
+ nxt_r.state <= s_data;
+ END IF;
+
+ -- if enabled then check input sync and stop the new block output if the local sync does not coincide with the input sync
+ IF g_check_input_sync=TRUE THEN
+ IF r.blk_cnt=0 THEN
+ IF snk_in.sync='0' THEN
+ nxt_r.reg_sosi.valid <= '0'; -- undo all ctrl preparations for the new block
+ nxt_r.reg_sosi.sop <= '0';
+ nxt_r.reg_sosi.eop <= '0';
+ nxt_r.reg_sosi.sync <= '0';
+ nxt_r.blk_cnt <= 0; -- restart blk_cnt
+ nxt_r.state <= s_sop; -- remain in this state and wait for snk_in.sync
+ END IF;
+ END IF;
+ END IF;
+ END IF;
+ END IF;
+ WHEN s_data =>
+ IF snk_in.valid='1' THEN
+ nxt_r.data_cnt <= r.data_cnt+1;
+ nxt_r.reg_sosi.valid <= '1';
+ IF r.data_cnt=g_nof_data_per_block-2 THEN
+ nxt_r.state <= s_eop;
+ END IF;
+ END IF;
+ WHEN OTHERS => -- s_eop
+ IF snk_in.valid='1' THEN
+ nxt_r.reg_sosi.valid <= '1';
+ nxt_r.reg_sosi.eop <= '1';
+ nxt_r.state <= s_sop;
+ END IF;
+ END CASE;
+ END PROCESS;
+
+ -- Use local BSN that counts from 0 during sync interval, or restore global BSN between syncs
+ use_local_bsn : IF g_restore_global_bsn=FALSE GENERATE
+ out_sosi <= nxt_r.reg_sosi;
+ END GENERATE;
+
+ use_global_bsn : IF g_restore_global_bsn=TRUE GENERATE
+ u_dp_bsn_restore_global : ENTITY work.dp_bsn_restore_global
+ GENERIC MAP (
+ g_bsn_w => c_dp_stream_bsn_w,
+ g_pipeline => 0 -- pipeline registering is done via nxt_src_out_arr
+ )
+ PORT MAP (
+ rst => rst,
+ clk => clk,
+ -- ST sink
+ snk_in => nxt_r.reg_sosi,
+ -- ST source
+ src_out => out_sosi
+ );
+ END GENERATE;
+
+ -- Combine input data with the same out_put info and output ctrl for all streams
+ nxt_src_out_arr <= func_dp_stream_arr_combine_data_info_ctrl(snk_in_arr, out_sosi, out_sosi);
+
+END rtl;
Index: trunk/dp_bsn_restore_global.vhd
===================================================================
--- trunk/dp_bsn_restore_global.vhd (nonexistent)
+++ trunk/dp_bsn_restore_global.vhd (revision 2)
@@ -0,0 +1,121 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2017
+-- ASTRON (Netherlands Institute for Radio Astronomy)
+-- JIVE (Joint Institute for VLBI in Europe)
+-- 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 .
+--
+-------------------------------------------------------------------------------
+
+LIBRARY IEEE, common_pkg_lib, common_components_lib, dp_pkg_lib, astron_pipeline_lib;
+USE IEEE.std_logic_1164.all;
+USE common_pkg_lib.common_pkg.ALL;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+
+-- Author: Eric Kooistra, 17 nov 2017
+-- Purpose:
+-- Restore global BSN.
+-- Description:
+-- The input global BSN is active at the sync. In between sync the other BSN
+-- BSN at the sop may count a local BSN that restarted at 0 for every sync.
+-- This dp_bsn_restore_global takes the BSN at the sync and starts counting
+-- from there for every sop, so in this way it restores the global BSN count
+-- for the blocks in between syncs.
+-- The increment for each restored BSN is 1. The assumption is that the
+-- number of blocks between syncs equals the difference in global BSN values
+-- between syncs. In this way the restored BSN counts without gaps or
+-- duplicates.
+-- Remarks:
+
+ENTITY dp_bsn_restore_global IS
+ GENERIC (
+ g_bsn_w : NATURAL := c_dp_stream_bsn_w;
+ g_pipeline : NATURAL := 1 -- 0 for wires, > 0 for registers
+ );
+ PORT (
+ rst : IN STD_LOGIC;
+ clk : IN STD_LOGIC;
+ -- ST sink
+ snk_out : OUT t_dp_siso;
+ snk_in : IN t_dp_sosi;
+ -- ST source
+ src_in : IN t_dp_siso := c_dp_siso_rdy;
+ src_out : OUT t_dp_sosi
+ );
+END dp_bsn_restore_global;
+
+
+ARCHITECTURE str OF dp_bsn_restore_global IS
+
+ SIGNAL blk_sync : STD_LOGIC;
+ SIGNAL bsn_at_sync : STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0);
+ SIGNAL nxt_bsn_at_sync : STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0);
+ SIGNAL bsn_restored : STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0);
+ SIGNAL snk_in_restored : t_dp_sosi;
+
+BEGIN
+
+ -- keep BSN at sync
+ p_clk : PROCESS(clk, rst)
+ BEGIN
+ IF rst='1' THEN
+ bsn_at_sync <= (OTHERS=>'0');
+ ELSIF rising_edge(clk) THEN
+ bsn_at_sync <= nxt_bsn_at_sync;
+ END IF;
+ END PROCESS;
+
+ -- Store global BSN at sync
+ nxt_bsn_at_sync <= snk_in.bsn(g_bsn_w-1 DOWNTO 0) WHEN snk_in.sync='1' ELSE bsn_at_sync;
+
+ -- Create block sync from snk_in.sync, this blk_sync is active during entire first sop-eop block of sync interval
+ u_common_switch : ENTITY common_components_lib.common_switch
+ GENERIC MAP (
+ g_rst_level => '0', -- Defines the output level at reset.
+ g_priority_lo => FALSE, -- When TRUE then input switch_low has priority, else switch_high. Don't care when switch_high and switch_low are pulses that do not occur simultaneously.
+ g_or_high => TRUE, -- When TRUE and priority hi then the registered switch_level is OR-ed with the input switch_high to get out_level, else out_level is the registered switch_level
+ g_and_low => FALSE -- When TRUE and priority lo then the registered switch_level is AND-ed with the input switch_low to get out_level, else out_level is the registered switch_level
+ )
+ PORT MAP (
+ rst => rst,
+ clk => clk,
+ switch_high => snk_in.sync, -- A pulse on switch_high makes the out_level go high
+ switch_low => snk_in.eop, -- A pulse on switch_low makes the out_level go low
+ out_level => blk_sync
+ );
+
+ -- Use stored global BSN at sync and add local BSN to restore the global BSN for every next sop
+ bsn_restored <= snk_in.bsn WHEN blk_sync='1' ELSE ADD_UVEC(bsn_at_sync, snk_in.bsn, g_bsn_w);
+
+ snk_in_restored <= func_dp_stream_bsn_set(snk_in, bsn_restored);
+
+ -- Add pipeline to ensure timing closure for the restored BSN summation
+ u_pipeline : ENTITY astron_pipeline_lib.dp_pipeline
+ GENERIC MAP (
+ g_pipeline => g_pipeline -- 0 for wires, > 0 for registers
+ )
+ PORT MAP (
+ rst => rst,
+ clk => clk,
+ -- ST sink
+ snk_out => snk_out,
+ snk_in => snk_in_restored,
+ -- ST source
+ src_in => src_in,
+ src_out => src_out
+ );
+
+END str;
Index: trunk/hdllib.cfg
===================================================================
--- trunk/hdllib.cfg (nonexistent)
+++ trunk/hdllib.cfg (revision 2)
@@ -0,0 +1,34 @@
+hdl_lib_name = astron_wpfb
+hdl_library_clause_name = astron_wpfb_lib
+hdl_lib_uses_synth = common_pkg astron_mm astron_diagnostics dp_pkg astron_r2sdf_fft astron_statistics astron_wb_fft astron_filter astron_ram astron_pipeline
+hdl_lib_uses_sim =
+hdl_lib_technology =
+
+synth_files =
+ wpfb_pkg.vhd
+ wpfb_unit.vhd
+ dp_bsn_restore_global.vhd
+ dp_block_gen_valid_arr.vhd
+ wpfb_unit_dev.vhd
+
+test_bench_files =
+ tb_wpfb_unit.vhd
+ tb_wpfb_unit_dev.vhd
+ tb_mmf_wpfb_unit.vhd
+ tb_wpfb_unit_wide.vhd
+ tb_tb_wpfb_unit_wide.vhd
+
+regression_test_vhdl =
+ #tb_wpfb_unit.vhd -- self checking golden result is not up to date
+ tb_tb_wpfb_unit_wide.vhd
+
+
+[modelsim_project_file]
+modelsim_copy_files =
+ modelsim/wave_tb_mmf_wpfb_unit.do .
+ ../filter/src/hex data
+ tb/data data
+
+
+[quartus_project_file]
+
Index: trunk/tb_mmf_wpfb_unit.vhd
===================================================================
--- trunk/tb_mmf_wpfb_unit.vhd (nonexistent)
+++ trunk/tb_mmf_wpfb_unit.vhd (revision 2)
@@ -0,0 +1,448 @@
+
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2012
+-- ASTRON (Netherlands Institute for Radio Astronomy)
+-- 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 .
+--
+-------------------------------------------------------------------------------
+--
+-- Purpose: Test bench for the wideband poly phase filterbank.
+--
+-- The testbech uses blockgenerators to generate data for
+-- every input of the wideband poly phase filterbank.
+-- The output of the WPFB is stored in databuffers.
+-- Both the block generators and databuffers are controlled
+-- via a mm interface.
+-- Use this testbench in conjunction with:
+--
+-- ../python/tc_mmf_wpfb_unit.py
+-- For verifying the complete wideband polyphase filter bank: g_use_bg = FALSE
+--
+-- ../python/tc_mmf_wpfb_unit_functional.py
+-- For verifying the different wide- and narrowband configurationss
+-- of the wpfb_unit.
+--
+-- (Automated) Usage:
+-- > Be sure that the c_start_modelsim variable is set to 1 in the script.
+-- > Run python script in separate terminal: "python tc_mmf_wpfb_unit.py --unb 0 --bn 0 --sim"
+--
+-- (Manual) Usage:
+-- > run -all
+-- > Be sure that the c_start_modelsim variable is set to 0 in the script.
+-- > Run python script in separate terminal: "python tc_mmf_wpfb_unit.py --unb 0 --bn 0 --sim"
+-- > Check the results of the python script.
+-- > Stop the simulation manually in Modelsim by pressing the stop-button.
+-- > For fractional frequencies set g_nof_blocks=32 to be able to simulate a sufficent number of periods without transition.
+
+
+LIBRARY IEEE, common_pkg_lib, astron_mm_lib, astron_diagnostics_lib, dp_pkg_lib, astron_r2sdf_fft_lib, astron_wb_fft_lib, astron_filter_lib, astron_ram_lib, astron_sim_tools_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE IEEE.math_real.ALL;
+USE common_pkg_lib.common_pkg.ALL;
+USE astron_ram_lib.common_ram_pkg.ALL;
+USE common_pkg_lib.common_str_pkg.ALL;
+USE common_pkg_lib.tb_common_pkg.ALL;
+USE astron_mm_lib.tb_common_mem_pkg.ALL;
+USE astron_mm_lib.mm_file_unb_pkg.ALL;
+USE astron_mm_lib.mm_file_pkg.ALL;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+USE astron_diagnostics_lib.diag_pkg.ALL;
+USE astron_r2sdf_fft_lib.twiddlesPkg.all;
+USE astron_r2sdf_fft_lib.rTwoSDFPkg.all;
+USE astron_wb_fft_lib.tb_fft_pkg.all;
+USE astron_wb_fft_lib.fft_pkg.all;
+USE astron_filter_lib.fil_pkg.all;
+USE work.wpfb_pkg.all;
+
+
+ENTITY tb_mmf_wpfb_unit IS
+ GENERIC(
+ g_wb_factor : natural := 1; -- = default 1, wideband factor
+ g_nof_wb_streams : natural := 1; -- = 1, the number of parallel wideband streams. The filter coefficients are shared on every wb-stream.
+ g_nof_chan : natural := 0; -- = default 0, defines the number of channels (=time-multiplexed input signals): nof channels = 2**nof_chan
+ g_nof_points : natural := 64; -- = 1024, N point FFT
+ g_nof_taps : natural := 16; -- = 8 nof taps n the filter
+ g_nof_blocks : natural := 4; -- = 4, the number of blocks of g_nof_points each in the BG waveform (must be power of 2 due to that BG c_bg_block_len must be power of 2)
+ g_in_dat_w : natural := 8; -- = 8, number of input bits
+ g_out_dat_w : natural := 16; -- = 14, number of output bits: in_dat_w + natural((ceil_log2(nof_points))/2)
+ g_use_separate : boolean := FALSE; -- = false for complex input, true for two real inputs
+ g_use_bg : boolean := FALSE;
+ g_coefs_file_prefix : string := "data/coefs_wide"
+ );
+END tb_mmf_wpfb_unit;
+
+ARCHITECTURE tb OF tb_mmf_wpfb_unit IS
+
+ CONSTANT c_in_backoff_w : natural := 0; -- = 0, number of bits for input backoff to avoid FIR output overflow
+ CONSTANT c_nof_blk_per_sync : natural := 20;
+
+ CONSTANT c_wpfb : t_wpfb := (g_wb_factor, g_nof_points, g_nof_chan, g_nof_wb_streams,
+ g_nof_taps, c_in_backoff_w, g_in_dat_w, 16, 16,
+ true, false, g_use_separate, 16, g_out_dat_w, 0, 18, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+
+ -- type t_wpfb is record
+ -- -- General parameters for the wideband poly phase filter
+ -- wb_factor : natural; -- = default 4, wideband factor
+ -- nof_points : natural; -- = 1024, N point FFT (Also the number of subbands for the filetr part)
+ -- nof_chan : natural; -- = default 0, defines the number of channels (=time-multiplexed input signals): nof channels = 2**nof_chan
+ -- nof_wb_streams : natural; -- = 1, the number of parallel wideband streams. The filter coefficients are shared on every stream.
+ --
+ -- -- Parameters for the poly phase filter
+ -- nof_taps : natural; -- = 16, the number of FIR taps per subband
+ -- fil_backoff_w : natural; -- = 0, number of bits for input backoff to avoid output overflow
+ -- fil_in_dat_w : natural; -- = 8, number of input bits
+ -- fil_out_dat_w : natural; -- = 16, number of output bits
+ -- coef_dat_w : natural; -- = 16, data width of the FIR coefficients
+ --
+ -- -- Parameters for the FFT
+ -- use_reorder : boolean; -- = false for bit-reversed output, true for normal output
+ -- use_fft_shift : boolean; -- = false for [0, pos, neg] bin frequencies order, true for [neg, 0, pos] bin frequencies order in case of complex input
+ -- use_separate : boolean; -- = false for complex input, true for two real inputs
+ -- fft_in_dat_w : natural; -- = 16, number of input bits
+ -- fft_out_dat_w : natural; -- = 13, number of output bits
+ -- fft_out_gain_w : natural; -- = 0, output gain factor applied after the last stage output, before requantization to out_dat_w
+ -- stage_dat_w : natural; -- = 18, number of bits that are used inter-stage
+ -- guard_w : natural; -- = 2
+ -- guard_enable : boolean; -- = true
+ --
+ -- -- Parameters for the statistics
+ -- stat_data_w : positive; -- = 56
+ -- stat_data_sz : positive; -- = 2
+ -- nof_blk_per_sync : natural; -- = 800000, number of FFT output blocks per sync interval
+ --
+ -- -- Pipeline parameters for both poly phase filter and FFT. These are heritaged from the filter and fft libraries.
+ -- pft_pipeline : t_fft_pipeline; -- Pipeline settings for the pipelined FFT
+ -- fft_pipeline : t_fft_pipeline; -- Pipeline settings for the parallel FFT
+ -- fil_pipeline : t_fil_ppf_pipeline; -- Pipeline settings for the filter units
+ --
+ -- end record;
+
+ ----------------------------------------------------------------------------
+ -- Clocks and resets
+ ----------------------------------------------------------------------------
+ CONSTANT c_mm_clk_period : TIME := 100 ps;
+ CONSTANT c_dp_clk_period : TIME := 5 ns;
+ CONSTANT c_sclk_period : TIME := c_dp_clk_period / c_wpfb.wb_factor;
+ CONSTANT c_dp_pps_period : NATURAL := 64;
+
+ SIGNAL dp_pps : STD_LOGIC;
+
+ SIGNAL mm_rst : STD_LOGIC;
+ SIGNAL mm_clk : STD_LOGIC := '0';
+
+ SIGNAL dp_rst : STD_LOGIC;
+ SIGNAL dp_clk : STD_LOGIC := '0';
+
+ SIGNAL SCLK : STD_LOGIC := '0';
+
+ ----------------------------------------------------------------------------
+ -- MM buses
+ ----------------------------------------------------------------------------
+ SIGNAL reg_diag_bg_mosi : t_mem_mosi;
+ SIGNAL reg_diag_bg_miso : t_mem_miso;
+
+ SIGNAL ram_diag_bg_mosi : t_mem_mosi;
+ SIGNAL ram_diag_bg_miso : t_mem_miso;
+
+ SIGNAL ram_diag_data_buf_re_mosi : t_mem_mosi;
+ SIGNAL ram_diag_data_buf_re_miso : t_mem_miso;
+
+ SIGNAL reg_diag_data_buf_re_mosi : t_mem_mosi;
+ SIGNAL reg_diag_data_buf_re_miso : t_mem_miso;
+
+ SIGNAL ram_diag_data_buf_im_mosi : t_mem_mosi;
+ SIGNAL ram_diag_data_buf_im_miso : t_mem_miso;
+
+ SIGNAL reg_diag_data_buf_im_mosi : t_mem_mosi;
+ SIGNAL reg_diag_data_buf_im_miso : t_mem_miso;
+
+ SIGNAL ram_st_sst_mosi : t_mem_mosi := c_mem_mosi_rst;
+ SIGNAL ram_st_sst_miso : t_mem_miso := c_mem_miso_rst;
+
+ SIGNAL ram_fil_coefs_mosi : t_mem_mosi := c_mem_mosi_rst;
+ SIGNAL ram_fil_coefs_miso : t_mem_miso := c_mem_miso_rst;
+
+ SIGNAL reg_diag_bg_pfb_mosi : t_mem_mosi := c_mem_mosi_rst;
+ SIGNAL reg_diag_bg_pfb_miso : t_mem_miso := c_mem_miso_rst;
+
+ SIGNAL ram_diag_bg_pfb_mosi : t_mem_mosi := c_mem_mosi_rst;
+ SIGNAL ram_diag_bg_pfb_miso : t_mem_miso := c_mem_miso_rst;
+
+ CONSTANT c_coefs_file_prefix : STRING := g_coefs_file_prefix & NATURAL'IMAGE(c_wpfb.wb_factor) & "_p"& NATURAL'IMAGE(c_wpfb.nof_points) & "_t"& NATURAL'IMAGE(c_wpfb.nof_taps);
+
+ CONSTANT c_nof_streams : POSITIVE := c_wpfb.nof_wb_streams*c_wpfb.wb_factor;
+ CONSTANT c_nof_channels : NATURAL := 2**c_wpfb.nof_chan;
+ CONSTANT c_bg_block_len : NATURAL := c_wpfb.nof_points*g_nof_blocks*c_nof_channels/c_wpfb.wb_factor;
+
+ CONSTANT c_bg_buf_adr_w : NATURAL := ceil_log2(c_bg_block_len);
+ CONSTANT c_bg_data_file_index_arr : t_nat_natural_arr := array_init(0, c_nof_streams, 1);
+ CONSTANT c_bg_data_file_prefix : STRING := "UNUSED";
+
+ SIGNAL bg_siso_arr : t_dp_siso_arr(c_nof_streams-1 DOWNTO 0) := (OTHERS=>c_dp_siso_rdy);
+ SIGNAL bg_sosi_arr : t_dp_sosi_arr(c_nof_streams-1 DOWNTO 0);
+ SIGNAL out_sosi_arr : t_dp_sosi_arr(c_nof_streams-1 DOWNTO 0);
+
+ SIGNAL scope_in_sosi : t_dp_sosi_integer_arr(c_wpfb.nof_wb_streams-1 DOWNTO 0);
+ SIGNAL scope_out_sosi : t_dp_sosi_integer_arr(c_wpfb.nof_wb_streams-1 DOWNTO 0);
+ SIGNAL scope_out_power : REAL := 0.0;
+ SIGNAL scope_out_ampl : REAL := 0.0;
+ SIGNAL scope_out_index : NATURAL;
+ SIGNAL scope_out_bin : NATURAL;
+ SIGNAL scope_out_band : NATURAL;
+ SIGNAL scope_out_ampl_x : REAL := 0.0;
+ SIGNAL scope_out_ampl_y : REAL := 0.0;
+
+BEGIN
+
+ ----------------------------------------------------------------------------
+ -- Clock and reset generation
+ ----------------------------------------------------------------------------
+ mm_clk <= NOT mm_clk AFTER c_mm_clk_period/2;
+ mm_rst <= '1', '0' AFTER c_mm_clk_period*5;
+
+ dp_clk <= NOT dp_clk AFTER c_dp_clk_period/2;
+ dp_rst <= '1', '0' AFTER c_dp_clk_period*5;
+
+ SCLK <= NOT SCLK AFTER c_sclk_period/2;
+
+ ------------------------------------------------------------------------------
+ -- External PPS
+ ------------------------------------------------------------------------------
+ proc_common_gen_pulse(1, c_dp_pps_period, '1', dp_clk, dp_pps);
+
+ ----------------------------------------------------------------------------
+ -- Procedure that polls a sim control file that can be used to e.g. get
+ -- the simulation time in ns
+ ----------------------------------------------------------------------------
+ mmf_poll_sim_ctrl_file(c_mmf_unb_file_path & "sim.ctrl", c_mmf_unb_file_path & "sim.stat");
+
+ ----------------------------------------------------------------------------
+ -- MM buses
+ ----------------------------------------------------------------------------
+ u_mm_file_reg_diag_bg : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "REG_DIAG_BG")
+ PORT MAP(mm_rst, mm_clk, reg_diag_bg_mosi, reg_diag_bg_miso);
+
+ u_mm_file_ram_diag_bg : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "RAM_DIAG_BG")
+ PORT MAP(mm_rst, mm_clk, ram_diag_bg_mosi, ram_diag_bg_miso);
+
+ u_mm_file_ram_diag_data_buf_re : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "RAM_DIAG_DATA_BUFFER_REAL")
+ PORT MAP(mm_rst, mm_clk, ram_diag_data_buf_re_mosi, ram_diag_data_buf_re_miso);
+
+ u_mm_file_reg_diag_data_buf_re : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "REG_DIAG_DATA_BUFFER_REAL")
+ PORT MAP(mm_rst, mm_clk, reg_diag_data_buf_re_mosi, reg_diag_data_buf_re_miso);
+
+ u_mm_file_ram_diag_data_buf_im : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "RAM_DIAG_DATA_BUFFER_IMAG")
+ PORT MAP(mm_rst, mm_clk, ram_diag_data_buf_im_mosi, ram_diag_data_buf_im_miso);
+
+ u_mm_file_reg_diag_data_buf_im : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "REG_DIAG_DATA_BUFFER_IMAG")
+ PORT MAP(mm_rst, mm_clk, reg_diag_data_buf_im_mosi, reg_diag_data_buf_im_miso);
+
+ u_mm_file_ram_fil_coefs : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "RAM_FIL_COEFS")
+ PORT MAP(mm_rst, mm_clk, ram_fil_coefs_mosi, ram_fil_coefs_miso);
+
+ u_mm_file_ram_st_sst : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "RAM_ST_SST")
+ PORT MAP(mm_rst, mm_clk, ram_st_sst_mosi, ram_st_sst_miso);
+
+ u_mm_file_reg_diag_pfb_bg : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "REG_DIAG_BG_PFB")
+ PORT MAP(mm_rst, mm_clk, reg_diag_bg_pfb_mosi, reg_diag_bg_pfb_miso);
+
+ u_mm_file_ram_diag_pfb_bg : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "RAM_DIAG_BG_PFB")
+ PORT MAP(mm_rst, mm_clk, ram_diag_bg_pfb_mosi, ram_diag_bg_pfb_miso);
+
+ ----------------------------------------------------------------------------
+ -- Source: block generator
+ ----------------------------------------------------------------------------
+ u_bg : ENTITY astron_diagnostics_lib.mms_diag_block_gen
+ GENERIC MAP(
+ g_nof_streams => c_nof_streams,
+ g_buf_dat_w => c_nof_complex*c_wpfb.fil_in_dat_w,
+ g_buf_addr_w => c_bg_buf_adr_w, -- Waveform buffer size 2**g_buf_addr_w nof samples
+ g_file_index_arr => c_bg_data_file_index_arr,
+ g_file_name_prefix => c_bg_data_file_prefix
+ )
+ PORT MAP(
+ -- System
+ mm_rst => mm_rst,
+ mm_clk => mm_clk,
+ dp_rst => dp_rst,
+ dp_clk => dp_clk,
+ en_sync => dp_pps,
+ -- MM interface
+ reg_bg_ctrl_mosi => reg_diag_bg_mosi,
+ reg_bg_ctrl_miso => reg_diag_bg_miso,
+ ram_bg_data_mosi => ram_diag_bg_mosi,
+ ram_bg_data_miso => ram_diag_bg_miso,
+ -- ST interface
+ out_siso_arr => bg_siso_arr,
+ out_sosi_arr => bg_sosi_arr
+ );
+
+ ----------------------------------------------------------------------------
+ -- Source: DUT input scope
+ ----------------------------------------------------------------------------
+ gen_input_scopes : FOR I IN 0 TO c_wpfb.nof_wb_streams-1 GENERATE
+ u_in_scope : ENTITY astron_sim_tools_lib.dp_wideband_wb_arr_scope
+ GENERIC MAP (
+ g_sim => TRUE,
+ g_wideband_factor => c_wpfb.wb_factor,
+ g_wideband_big_endian => FALSE,
+ g_dat_w => c_wpfb.fil_in_dat_w
+ )
+ PORT MAP (
+ SCLK => SCLK,
+ wb_sosi_arr => bg_sosi_arr((I+1)*c_wpfb.wb_factor-1 DOWNTO I*c_wpfb.wb_factor),
+ scope_sosi => scope_in_sosi(I)
+ );
+ END GENERATE;
+ ----------------------------------------------------------------------------
+ -- DUT = Device Under Test
+ ----------------------------------------------------------------------------
+ u_dut : ENTITY work.wpfb_unit
+ GENERIC MAP(
+ g_wpfb => c_wpfb,
+ g_use_bg => g_use_bg,
+ g_coefs_file_prefix => c_coefs_file_prefix
+ )
+ PORT MAP(
+ dp_rst => dp_rst,
+ dp_clk => dp_clk,
+ mm_rst => mm_rst,
+ mm_clk => mm_clk,
+ ram_fil_coefs_mosi => ram_fil_coefs_mosi,
+ ram_fil_coefs_miso => ram_fil_coefs_miso,
+ ram_st_sst_mosi => ram_st_sst_mosi,
+ ram_st_sst_miso => ram_st_sst_miso,
+ reg_bg_ctrl_mosi => reg_diag_bg_pfb_mosi,
+ reg_bg_ctrl_miso => reg_diag_bg_pfb_miso,
+ ram_bg_data_mosi => ram_diag_bg_pfb_mosi,
+ ram_bg_data_miso => ram_diag_bg_pfb_miso,
+ in_sosi_arr => bg_sosi_arr,
+ out_sosi_arr => out_sosi_arr
+ );
+
+ time_map : process is
+ variable sim_time_str_v : string(1 to 30); -- 30 chars should be enough
+ variable sim_time_len_v : natural;
+ begin
+ wait for 1000 ns;
+ sim_time_len_v := time'image(now)'length;
+ sim_time_str_v := (others => ' ');
+ sim_time_str_v(1 to sim_time_len_v) := time'image(now);
+ report "Sim time string length: " & integer'image(sim_time_len_v);
+ report "Sim time string.......:'" & sim_time_str_v & "'";
+ end process;
+
+ ----------------------------------------------------------------------------
+ -- Sink: DUT output scope
+ ----------------------------------------------------------------------------
+ gen_output_scopes : FOR I IN 0 TO c_wpfb.nof_wb_streams-1 GENERATE
+ u_out_scope : ENTITY astron_sim_tools_lib.dp_wideband_wb_arr_scope
+ GENERIC MAP (
+ g_sim => TRUE,
+ g_wideband_factor => c_wpfb.wb_factor,
+ g_wideband_big_endian => FALSE,
+ g_dat_w => c_wpfb.fft_out_dat_w
+ )
+ PORT MAP (
+ SCLK => SCLK,
+ wb_sosi_arr => out_sosi_arr((I+1)*c_wpfb.wb_factor-1 DOWNTO I*c_wpfb.wb_factor),
+ scope_sosi => scope_out_sosi(I)
+ );
+ END GENERATE;
+
+ p_scope_out_index : PROCESS(SCLK)
+ BEGIN
+ IF rising_edge(SCLK) THEN
+ IF scope_out_sosi(0).valid='1' THEN
+ scope_out_index <= scope_out_index+1;
+ IF scope_out_index>=g_nof_points-1 THEN
+ scope_out_index <= 0;
+ END IF;
+ END IF;
+ END IF;
+ END PROCESS;
+ scope_out_bin <= fft_index_to_bin_frequency(c_wpfb.wb_factor, c_wpfb.nof_points, scope_out_index, TRUE, FALSE, TRUE); -- complex bin
+ scope_out_band <= fft_index_to_bin_frequency(c_wpfb.wb_factor, c_wpfb.nof_points, scope_out_index, TRUE, TRUE, TRUE); -- two real bin
+
+ scope_out_power <= REAL(scope_out_sosi(0).re)**2 + REAL(scope_out_sosi(0).im)**2;
+ scope_out_ampl <= SQRT(scope_out_power);
+ scope_out_ampl_x <= scope_out_ampl WHEN (scope_out_bin MOD 2)=0 ELSE 0.0;
+ scope_out_ampl_y <= scope_out_ampl WHEN (scope_out_bin MOD 2)=1 ELSE 0.0;
+
+ ----------------------------------------------------------------------------
+ -- Sink: data buffer real
+ ----------------------------------------------------------------------------
+ u_data_buf_re : ENTITY astron_diagnostics_lib.mms_diag_data_buffer
+ GENERIC MAP (
+ g_nof_streams => c_nof_streams,
+ g_data_type => e_real,
+ g_data_w => c_wpfb.fft_out_dat_w,
+ g_buf_nof_data => c_bg_block_len,
+ g_buf_use_sync => TRUE
+ )
+ PORT MAP (
+ -- System
+ mm_rst => mm_rst,
+ mm_clk => mm_clk,
+ dp_rst => dp_rst,
+ dp_clk => dp_clk,
+
+ -- MM interface
+ ram_data_buf_mosi => ram_diag_data_buf_re_mosi,
+ ram_data_buf_miso => ram_diag_data_buf_re_miso,
+
+ reg_data_buf_mosi => reg_diag_data_buf_re_mosi,
+ reg_data_buf_miso => reg_diag_data_buf_re_miso,
+
+ -- ST interface
+ in_sync => out_sosi_arr(0).sync,
+ in_sosi_arr => out_sosi_arr
+ );
+
+ ----------------------------------------------------------------------------
+ -- Sink: data buffer imag
+ ----------------------------------------------------------------------------
+ u_data_buf_im : ENTITY astron_diagnostics_lib.mms_diag_data_buffer
+ GENERIC MAP (
+ g_nof_streams => c_nof_streams,
+ g_data_type => e_imag,
+ g_data_w => c_wpfb.fft_out_dat_w,
+ g_buf_nof_data => c_bg_block_len,
+ g_buf_use_sync => TRUE
+ )
+ PORT MAP (
+ -- System
+ mm_rst => mm_rst,
+ mm_clk => mm_clk,
+ dp_rst => dp_rst,
+ dp_clk => dp_clk,
+
+ -- MM interface
+ ram_data_buf_mosi => ram_diag_data_buf_im_mosi,
+ ram_data_buf_miso => ram_diag_data_buf_im_miso,
+
+ reg_data_buf_mosi => reg_diag_data_buf_im_mosi,
+ reg_data_buf_miso => reg_diag_data_buf_im_miso,
+
+ -- ST interface
+ in_sync => out_sosi_arr(0).sync,
+ in_sosi_arr => out_sosi_arr
+ );
+
+END tb;
Index: trunk/tb_tb_wpfb_unit_wide.vhd
===================================================================
--- trunk/tb_tb_wpfb_unit_wide.vhd (nonexistent)
+++ trunk/tb_tb_wpfb_unit_wide.vhd (revision 2)
@@ -0,0 +1,346 @@
+--------------------------------------------------------------------------------
+--
+-- Copyright (C) 2016
+-- ASTRON (Netherlands Institute for Radio Astronomy)
+-- 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 .
+--
+--------------------------------------------------------------------------------
+
+-- Purpose: Multi-testbench for wpfb_unit_wide using file data
+-- Description:
+-- Verify wpfb_unit_wide using and data generated by Matlab scripts:
+--
+-- - $RADIOHDL_WORK/applications/apertif/matlab/run_pfb.m
+-- - $RADIOHDL_WORK/applications/apertif/matlab/run_pfb_complex.m
+--
+-- Usage:
+-- > as 4
+-- > run -all
+
+LIBRARY IEEE, common_pkg_lib, astron_filter_lib, astron_r2sdf_fft_lib;
+USE IEEE.std_logic_1164.ALL;
+USE common_pkg_lib.common_pkg.all;
+USE astron_filter_lib.fil_pkg.all;
+USE astron_r2sdf_fft_lib.rTwoSDFPkg.all;
+USE work.wpfb_pkg.all;
+
+ENTITY tb_tb_wpfb_unit_wide IS
+END tb_tb_wpfb_unit_wide;
+
+ARCHITECTURE tb OF tb_tb_wpfb_unit_wide IS
+
+ constant c_stage_dat_extra_w : natural := c_dsp_mult_w + 10;
+ constant c_nof_blk_per_sync : natural := 20;
+
+ -- wb 1, two real
+ CONSTANT c_wb1_two_real_1024 : t_wpfb := (1, 1024, 0, 1,
+ 16, 1, 8, 16, 16,
+ true, false, true, 16, 16, 1, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+ CONSTANT c_wb1_two_real : t_wpfb := (1, 32, 0, 1,
+ 16, 1, 8, 16, 16,
+ true, false, true, 16, 16, 1, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+
+ CONSTANT c_wb1_two_real_4streams : t_wpfb := (1, 32, 0, 4,
+ 16, 1, 8, 16, 16,
+ true, false, true, 16, 16, 1, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+
+ CONSTANT c_wb1_two_real_4channels : t_wpfb := (1, 32, 2, 1,
+ 16, 1, 8, 16, 16,
+ true, false, true, 16, 16, 1, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+
+ -- wb 4, two real
+ CONSTANT c_wb4_two_real_1024 : t_wpfb := (4, 1024, 0, 1,
+ 16, 1, 8, 16, 16,
+ true, false, true, 16, 16, 1, c_stage_dat_extra_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+ CONSTANT c_wb4_two_real : t_wpfb := (4, 32, 0, 1,
+ 16, 1, 8, 16, 16,
+ true, false, true, 16, 16, 1, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+
+ CONSTANT c_wb4_two_real_4streams : t_wpfb := (4, 32, 0, 4,
+ 16, 1, 8, 16, 16,
+ true, false, true, 16, 16, 1, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+
+ CONSTANT c_wb4_two_real_4channels : t_wpfb := (4, 32, 2, 1,
+ 16, 1, 8, 16, 16,
+ true, false, true, 16, 16, 1, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+
+ -- wb 1, complex reordered
+ CONSTANT c_wb1_complex_1024 : t_wpfb := (1, 1024, 0, 1,
+ 16, 1, 8, 16, 16,
+ true, false, false, 16, 16, 0, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+ CONSTANT c_wb1_complex_64 : t_wpfb := (1, 64, 0, 1,
+ 16, 1, 8, 16, 16,
+ true, false, false, 16, 16, 0, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+ CONSTANT c_wb1_complex : t_wpfb := (1, 32, 0, 1,
+ 16, 1, 8, 16, 16,
+ true, false, false, 16, 16, 0, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+ CONSTANT c_wb1_complex_4streams : t_wpfb := (1, 32, 0, 4,
+ 16, 1, 8, 16, 16,
+ true, false, false, 16, 16, 0, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+
+ CONSTANT c_wb1_complex_4channels : t_wpfb := (1, 32, 2, 1,
+ 16, 1, 8, 16, 16,
+ true, false, false, 16, 16, 0, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+
+ -- wb 1, complex fft_shift
+ CONSTANT c_wb1_complex_fft_shift : t_wpfb := (1, 32, 0, 1,
+ 16, 1, 8, 16, 16,
+ true, true, false, 16, 16, 0, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+
+ -- wb 1, complex without reorder
+ CONSTANT c_wb1_complex_flipped_1024 : t_wpfb := (1, 1024, 0, 1,
+ 16, 1, 8, 16, 16,
+ false, false, false, 16, 16, 0, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+ CONSTANT c_wb1_complex_flipped_64 : t_wpfb := (1, 64, 0, 1,
+ 16, 1, 8, 16, 16,
+ false, false, false, 16, 16, 0, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+ CONSTANT c_wb1_complex_flipped : t_wpfb := (1, 32, 0, 1,
+ 16, 1, 8, 16, 16,
+ false, false, false, 16, 16, 0, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+
+ -- wb 4, complex reordered
+ CONSTANT c_wb4_complex_1024 : t_wpfb := (4, 1024, 0, 1,
+ 16, 1, 8, 16, 16,
+ true, false, false, 16, 16, 0, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+ CONSTANT c_wb4_complex_64 : t_wpfb := (4, 64, 0, 1,
+ 16, 1, 8, 16, 16,
+ true, false, false, 16, 16, 0, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+ CONSTANT c_wb4_complex : t_wpfb := (4, 32, 0, 1,
+ 16, 1, 8, 16, 16,
+ true, false, false, 16, 16, 0, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+ CONSTANT c_wb4_complex_4streams : t_wpfb := (4, 32, 0, 4,
+ 16, 1, 8, 16, 16,
+ true, false, false, 16, 16, 0, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+
+ CONSTANT c_wb4_complex_4channels : t_wpfb := (4, 32, 2, 1,
+ 16, 1, 8, 16, 16,
+ true, false, false, 16, 16, 0, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+
+ -- wb 4, complex fft_shift
+ CONSTANT c_wb4_complex_fft_shift : t_wpfb := (4, 32, 0, 1,
+ 16, 1, 8, 16, 16,
+ true, true, false, 16, 16, 0, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+
+ -- wb 4, complex without reorder
+ CONSTANT c_wb4_complex_flipped_1024 : t_wpfb := (4, 1024, 0, 1,
+ 16, 1, 8, 16, 16,
+ false, false, false, 16, 16, 0, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+ CONSTANT c_wb4_complex_flipped_64 : t_wpfb := (4, 64, 0, 1,
+ 16, 1, 8, 16, 16,
+ false, false, false, 16, 16, 0, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+ CONSTANT c_wb4_complex_flipped : t_wpfb := (4, 32, 0, 1,
+ 16, 1, 8, 16, 16,
+ false, false, false, 16, 16, 0, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+
+ CONSTANT c_wb4_complex_flipped_channels : t_wpfb := (4, 32, 2, 1,
+ 16, 1, 8, 16, 16,
+ false, false, false, 16, 16, 0, c_dsp_mult_w, 2, true, 56, 2, c_nof_blk_per_sync,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+
+ CONSTANT c_dm_1 : natural := 1; -- diff margin (for stage_dat_w >> c_dsp_mult_w)
+ CONSTANT c_dm_3 : natural := 3; -- diff margin (for 32 point dm=2 appears sufficient, for 1024 point dm=3 is sufficient)
+ CONSTANT c_dm_5 : natural := 5; -- diff margin (for 32 point dm=2 appears sufficient, for 1024 point dm=3 is sufficient)
+
+ CONSTANT c_pre_ab : string := "data/run_pfb_m_pfir_coeff_fircls1"; -- original version
+ CONSTANT c_pre_ab_v2 : string := "data/run_pfb_m_v2_pfir_coeff_fircls1"; -- next version
+ CONSTANT c_pre_c : string := "data/run_pfb_complex_m_pfir_coeff_fircls1";
+
+ -- Real input
+ CONSTANT c_sinusoid_chirp_1024 : string := "data/run_pfb_m_sinusoid_chirp_8b_16taps_1024points_16b_16b.dat"; -- 204800 lines
+ CONSTANT c_sinusoid_chirp : string := "data/run_pfb_m_sinusoid_chirp_8b_16taps_32points_16b_16b.dat"; -- 6400 lines
+ CONSTANT c_sinusoid_1024 : string := "data/run_pfb_m_sinusoid_8b_16taps_1024points_16b_16b.dat"; -- 51200 lines
+ CONSTANT c_sinusoid_1024_v2 : string := "data/run_pfb_m_v2_sinusoid_8b_16taps_1024points_16b_16b.dat"; -- 51200 lines
+ CONSTANT c_sinusoid : string := "data/run_pfb_m_sinusoid_8b_16taps_32points_16b_16b.dat"; -- 1600 lines
+ CONSTANT c_impulse_chirp : string := "data/run_pfb_m_impulse_chirp_8b_16taps_32points_16b_16b.dat"; -- 6400 lines
+ CONSTANT c_noise_1024 : string := "data/run_pfb_m_noise_8b_16taps_1024points_16b_16b.dat"; -- 51200 lines
+ CONSTANT c_noise : string := "data/run_pfb_m_noise_8b_16taps_32points_16b_16b.dat"; -- 1600 lines
+ CONSTANT c_dc_agwn : string := "data/run_pfb_m_dc_agwn_8b_16taps_32points_16b_16b.dat"; -- 1600 lines
+ -- Complex input
+ CONSTANT c_phasor_chirp_1024 : string := "data/run_pfb_complex_m_phasor_chirp_8b_16taps_1024points_16b_16b.dat"; -- 204800 lines
+ CONSTANT c_phasor_chirp_128 : string := "data/run_pfb_complex_m_phasor_chirp_8b_16taps_128points_16b_16b.dat"; -- 25600 lines
+ CONSTANT c_phasor_chirp_64 : string := "data/run_pfb_complex_m_phasor_chirp_8b_16taps_64points_16b_16b.dat"; -- 12800 lines
+ CONSTANT c_phasor_chirp : string := "data/run_pfb_complex_m_phasor_chirp_8b_16taps_32points_16b_16b.dat"; -- 6400 lines
+ CONSTANT c_phasor : string := "data/run_pfb_complex_m_phasor_8b_16taps_32points_16b_16b.dat"; -- 1600 lines
+ CONSTANT c_noise_complex_1024 : string := "data/run_pfb_complex_m_noise_complex_8b_16taps_1024points_16b_16b.dat"; -- 51200 lines
+ CONSTANT c_noise_complex_128 : string := "data/run_pfb_complex_m_noise_complex_8b_16taps_128points_16b_16b.dat"; -- 6400 lines
+ CONSTANT c_noise_complex_64 : string := "data/run_pfb_complex_m_noise_complex_8b_16taps_64points_16b_16b.dat"; -- 3200 lines
+ CONSTANT c_noise_complex : string := "data/run_pfb_complex_m_noise_complex_8b_16taps_32points_16b_16b.dat"; -- 1600 lines
+ -- Zero input
+ CONSTANT c_zero : string := "UNUSED"; -- zero's data
+ CONSTANT c_un : string := "UNUSED"; -- zero's data
+
+ SIGNAL tb_end : STD_LOGIC := '0'; -- declare tb_end to avoid 'No objects found' error on 'when -label tb_end'
+
+BEGIN
+
+-- -- DUT generics
+-- g_wpfb : t_wpfb := (4, 32, 0, 1,
+-- 16, 1, 8, 16, 16,
+-- false, false, false, 16, 16, 0, c_dsp_mult_w, 2, true, 56, 2, 800000,
+-- c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+-- -- type t_wpfb is record
+-- -- -- General parameters for the wideband poly phase filter
+-- -- wb_factor : natural; -- = default 4, wideband factor
+-- -- nof_points : natural; -- = 1024, N point FFT (Also the number of subbands for the filter part)
+-- -- nof_chan : natural; -- = default 0, defines the number of channels (=time-multiplexed input signals): nof channels = 2**nof_chan
+-- -- nof_wb_streams : natural; -- = 1, the number of parallel wideband streams. The filter coefficients are shared on every wb-stream.
+-- --
+-- -- -- Parameters for the poly phase filter
+-- -- nof_taps : natural; -- = 16, the number of FIR taps per subband
+-- -- fil_backoff_w : natural; -- = 0, number of bits for input backoff to avoid output overflow
+-- -- fil_in_dat_w : natural; -- = 8, number of input bits
+-- -- fil_out_dat_w : natural; -- = 16, number of output bits
+-- -- coef_dat_w : natural; -- = 16, data width of the FIR coefficients
+-- --
+-- -- -- Parameters for the FFT
+-- -- use_reorder : boolean; -- = false for bit-reversed output, true for normal output
+-- -- use_fft_shift : boolean; -- = false for [0, pos, neg] bin frequencies order, true for [neg, 0, pos] bin frequencies order in case of complex input
+-- -- use_separate : boolean; -- = false for complex input, true for two real inputs
+-- -- fft_in_dat_w : natural; -- = 16, number of input bits
+-- -- fft_out_dat_w : natural; -- = 13, number of output bits
+-- -- fft_out_gain_w : natural; -- = 0, output gain factor applied after the last stage output, before requantization to out_dat_w
+-- -- stage_dat_w : natural; -- = 18, number of bits that are used inter-stage
+-- -- guard_w : natural; -- = 2
+-- -- guard_enable : boolean; -- = true
+-- --
+-- -- -- Parameters for the statistics
+-- -- stat_data_w : positive; -- = 56
+-- -- stat_data_sz : positive; -- = 2
+-- -- nof_blk_per_sync : natural; -- = 800000, number of FFT output blocks per sync interval
+-- --
+-- -- -- Pipeline parameters for both poly phase filter and FFT. These are heritaged from the filter and fft libraries.
+-- -- pft_pipeline : t_fft_pipeline; -- Pipeline settings for the pipelined FFT
+-- -- fft_pipeline : t_fft_pipeline; -- Pipeline settings for the parallel FFT
+-- -- fil_pipeline : t_fil_ppf_pipeline; -- Pipeline settings for the filter units
+-- -- end record;
+--
+-- -- TB generics
+-- g_diff_margin : integer := 2; -- maximum difference between HDL output and expected output (> 0 to allow minor rounding differences)
+--
+-- -- PFIR coefficients
+-- g_coefs_file_prefix_ab : string := "data/run_pfb_m_pfir_coeff_fircls1";
+-- g_coefs_file_prefix_c : string := "data/run_pfb_complex_m_pfir_coeff_fircls1";
+--
+-- -- Two real input data files A and B used when g_fft.use_separate = true
+-- -- * 1024 points = 512 subbands
+-- --g_data_file_a : string := "data/run_pfb_m_sinusoid_chirp_8b_16taps_1024points_16b_16b.dat";
+-- --g_data_file_a_nof_lines : natural := 204800;
+-- --g_data_file_b : string := "data/run_pfb_m_noise_8b_16taps_1024points_16b_16b.dat";
+-- --g_data_file_b_nof_lines : natural := 51200;
+-- --g_data_file_b : string := "UNUSED";
+-- --g_data_file_b_nof_lines : natural := 0;
+--
+-- -- * 32 points = 16 subbands
+-- g_data_file_a : string := "data/run_pfb_m_sinusoid_chirp_8b_16taps_32points_16b_16b.dat";
+-- g_data_file_a_nof_lines : natural := 6400;
+-- --g_data_file_a : string := "data/run_pfb_m_sinusoid_8b_16taps_32points_16b_16b.dat";
+-- --g_data_file_a_nof_lines : natural := 160;
+--
+-- --g_data_file_b : string := "data/run_pfb_m_impulse_chirp_8b_16taps_32points_16b_16b.dat";
+-- --g_data_file_b_nof_lines : natural := 6400;
+-- g_data_file_b : string := "UNUSED";
+-- g_data_file_b_nof_lines : natural := 0;
+--
+-- -- One complex input data file C used when g_fft.use_separate = false
+-- -- * 64 points = 64 channels
+-- --g_data_file_c : string := "data/run_pfb_complex_m_phasor_chirp_8b_16taps_64points_16b_16b.dat";
+-- --g_data_file_c_nof_lines : natural := 12800;
+-- --g_data_file_c : string := "data/run_pfb_complex_m_phasor_8b_16taps_64points_16b_16b.dat";
+-- --g_data_file_c_nof_lines : natural := 320;
+-- --g_data_file_c : string := "data/run_pfb_complex_m_noise_8b_16taps_64points_16b_16b.dat";
+-- --g_data_file_c_nof_lines : natural := 640;
+--
+-- -- * 32 points = 32 channels
+-- --g_data_file_c : string := "data/run_pfb_complex_m_phasor_chirp_8b_16taps_32points_16b_16b.dat";
+-- --g_data_file_c_nof_lines : natural := 6400;
+-- --g_data_file_c : string := "data/run_pfb_complex_m_phasor_8b_16taps_32points_16b_16b.dat";
+-- --g_data_file_c_nof_lines : natural := 1600;
+-- g_data_file_c : string := "data/run_pfb_complex_m_noise_complex_8b_16taps_32points_16b_16b.dat";
+-- g_data_file_c_nof_lines : natural := 1600;
+--
+-- g_data_file_nof_lines : natural := 1600; -- actual number of lines with input data to simulate from the data files, must be <= g_data_file_*_nof_lines
+-- g_enable_in_val_gaps : boolean := FALSE -- when false then in_val flow control active continuously, else with random inactive gaps
+
+ -- Two real input data A and B
+ -- * 1024 point (as in Apertif subband filterbank)
+ u_act_wb4_two_real_a0_1024 : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb4_two_real_1024, c_dm_1, c_pre_ab_v2, c_pre_c, c_sinusoid_1024_v2, 51200, c_zero, 51200, c_un, 0, 51200, FALSE);
+ u_act_wb4_two_real_ab_1024 : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb4_two_real_1024, c_dm_1, c_pre_ab, c_pre_c, c_sinusoid_chirp_1024, 204800, c_noise_1024, 51200, c_un, 0, 51200, FALSE);
+ u_act_wb1_two_real_ab_1024 : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb1_two_real_1024, c_dm_5, c_pre_ab, c_pre_c, c_sinusoid_chirp_1024, 204800, c_noise_1024, 51200, c_un, 0, 51200, FALSE);
+ u_act_wb1_two_real_chirp_1024 : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb1_two_real_1024, c_dm_5, c_pre_ab, c_pre_c, c_sinusoid_chirp_1024, 204800, c_zero, 51200, c_un, 0, 51200, FALSE);
+
+ -- * 32 point
+ u_act_wb1_two_real_chirp : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb1_two_real, c_dm_5, c_pre_ab, c_pre_c, c_sinusoid_chirp, 6400, c_impulse_chirp, 6400, c_un, 0, 6400, FALSE);
+ u_act_wb1_two_real_a0 : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb1_two_real, c_dm_5, c_pre_ab, c_pre_c, c_zero, 6400, c_impulse_chirp, 6400, c_un, 0, 6400, FALSE);
+ u_act_wb1_two_real_b0 : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb1_two_real, c_dm_5, c_pre_ab, c_pre_c, c_sinusoid_chirp, 6400, c_zero, 6400, c_un, 0, 6400, FALSE);
+ u_rnd_wb4_two_real_noise : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb4_two_real, c_dm_5, c_pre_ab, c_pre_c, c_noise, 1600, c_dc_agwn, 1600, c_un, 0, 1600, TRUE);
+ u_rnd_wb4_two_real_noise_channels : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb4_two_real_4channels, c_dm_5, c_pre_ab, c_pre_c, c_noise, 1600, c_dc_agwn, 1600, c_un, 0, 1600, TRUE);
+ u_rnd_wb4_two_real_noise_streams : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb4_two_real_4streams, c_dm_5, c_pre_ab, c_pre_c, c_noise, 1600, c_dc_agwn, 1600, c_un, 0, 1600, TRUE);
+ u_rnd_wb1_two_real_noise : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb1_two_real, c_dm_5, c_pre_ab, c_pre_c, c_noise, 1600, c_dc_agwn, 1600, c_un, 0, 1600, TRUE);
+ u_rnd_wb1_two_real_noise_channels : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb1_two_real_4channels, c_dm_5, c_pre_ab, c_pre_c, c_noise, 1600, c_dc_agwn, 1600, c_un, 0, 1600, TRUE);
+ u_rnd_wb1_two_real_noise_streams : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb1_two_real_4streams, c_dm_5, c_pre_ab, c_pre_c, c_noise, 1600, c_dc_agwn, 1600, c_un, 0, 1600, TRUE);
+
+ -- Complex input data
+ -- * 1024 point
+ u_act_wb1_complex_chirp_1024 : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb1_complex_1024, c_dm_3, c_pre_ab, c_pre_c, c_un, 0, c_un, 0, c_phasor_chirp_1024, 204800, 51200, FALSE);
+ u_act_wb4_complex_chirp_1024 : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb4_complex_1024, c_dm_3, c_pre_ab, c_pre_c, c_un, 0, c_un, 0, c_phasor_chirp_1024, 204800, 51200, FALSE);
+
+ -- * 64 point (as in Apertif channel filterbank)
+ u_act_wb1_complex_chirp_64 : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb1_complex_64, c_dm_3, c_pre_ab, c_pre_c, c_un, 0, c_un, 0, c_phasor_chirp_64, 12800, 12800, FALSE);
+ u_act_wb4_complex_chirp_64 : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb4_complex_64, c_dm_3, c_pre_ab, c_pre_c, c_un, 0, c_un, 0, c_phasor_chirp_64, 12800, 12800, FALSE);
+ u_act_wb1_complex_flipped_noise_64 : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb1_complex_flipped_64, c_dm_3, c_pre_ab, c_pre_c, c_un, 0, c_un, 0, c_noise_complex_64, 3200, 3200, FALSE);
+ u_act_wb4_complex_flipped_noise_64 : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb4_complex_flipped_64, c_dm_3, c_pre_ab, c_pre_c, c_un, 0, c_un, 0, c_noise_complex_64, 3200, 3200, FALSE);
+
+ -- * 32 point
+ u_act_wb4_complex_chirp : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb4_complex, c_dm_3, c_pre_ab, c_pre_c, c_un, 0, c_un, 0, c_phasor_chirp, 6400, 6400, FALSE);
+ u_act_wb4_complex_flipped : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb4_complex_flipped, c_dm_3, c_pre_ab, c_pre_c, c_un, 0, c_un, 0, c_phasor_chirp, 6400, 6400, FALSE);
+ u_rnd_wb4_complex_flipped_channels : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb4_complex_flipped_channels, c_dm_3, c_pre_ab, c_pre_c, c_un, 0, c_un, 0, c_phasor_chirp, 6400, 6400, FALSE);
+ u_rnd_wb1_complex_phasor : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb1_complex, c_dm_3, c_pre_ab, c_pre_c, c_un, 0, c_un, 0, c_phasor, 1600, 1600, TRUE);
+ u_rnd_wb4_complex_phasor : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb4_complex, c_dm_3, c_pre_ab, c_pre_c, c_un, 0, c_un, 0, c_phasor, 1600, 1600, TRUE);
+ u_rnd_wb1_complex_fft_shift_phasor : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb1_complex_fft_shift, c_dm_3, c_pre_ab, c_pre_c, c_un, 0, c_un, 0, c_phasor, 1600, 1600, TRUE);
+ u_rnd_wb4_complex_fft_shift_phasor : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb4_complex_fft_shift, c_dm_3, c_pre_ab, c_pre_c, c_un, 0, c_un, 0, c_phasor, 1600, 1600, TRUE);
+ u_rnd_wb1_complex_noise : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb1_complex, c_dm_3, c_pre_ab, c_pre_c, c_un, 0, c_un, 0, c_noise_complex, 1600, 1600, TRUE);
+ u_rnd_wb1_complex_noise_channels : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb1_complex_4channels, c_dm_3, c_pre_ab, c_pre_c, c_un, 0, c_un, 0, c_noise_complex, 1600, 1600, TRUE);
+ u_rnd_wb1_complex_noise_streams : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb1_complex_4streams, c_dm_3, c_pre_ab, c_pre_c, c_un, 0, c_un, 0, c_noise_complex, 1600, 1600, TRUE);
+ u_rnd_wb4_complex_noise : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb4_complex, c_dm_3, c_pre_ab, c_pre_c, c_un, 0, c_un, 0, c_noise_complex, 1600, 1600, TRUE);
+ u_rnd_wb4_complex_noise_channels : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb4_complex_4channels, c_dm_3, c_pre_ab, c_pre_c, c_un, 0, c_un, 0, c_noise_complex, 1600, 1600, TRUE);
+ u_rnd_wb4_complex_noise_streams : ENTITY work.tb_wpfb_unit_wide GENERIC MAP (c_wb4_complex_4streams, c_dm_3, c_pre_ab, c_pre_c, c_un, 0, c_un, 0, c_noise_complex, 1600, 1600, TRUE);
+END tb;
Index: trunk/tb_wpfb_unit.vhd
===================================================================
--- trunk/tb_wpfb_unit.vhd (nonexistent)
+++ trunk/tb_wpfb_unit.vhd (revision 2)
@@ -0,0 +1,594 @@
+-- Author: Harm Jan Pepping : HJP at astron.nl: April 2012
+--------------------------------------------------------------------------------
+--
+-- Copyright (C) 2012
+-- ASTRON (Netherlands Institute for Radio Astronomy)
+-- 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 .
+--
+--------------------------------------------------------------------------------
+
+--
+-- Purpose: Test bench for the Wideband Poly Phase Filter Bank
+--
+--
+-- Usage:
+-- > run -all
+-- > testbench is selftesting.
+--
+-- Remarks:
+-- . The first c_nof_spectra_in_file(= 8) spectrums are verified.
+-- . The statistics are verified, based on the raw output of the DUT.
+-- . Currently only the Noise file is tested.
+--
+--!!!NOTE!!! This testbench has become obsolete since the quantization of
+-- the FFT algorithm is changed. The testbench still works, but
+-- the goldenfiles are not valid anymore and therefor the test-
+-- bench will report that the output contains errors.
+-- The tb_wpfb_unit testbench is replaced by the tb_mmf_wpfb_unit
+-- testbench, which is a co-simulation between modelsim and python.
+--
+--
+
+library ieee, common_pkg_lib, dp_pkg_lib, astron_diagnostics_lib, astron_r2sdf_fft_lib, astron_wb_fft_lib, astron_filter_lib, astron_ram_lib, astron_mm_lib;
+use IEEE.std_logic_1164.all;
+use IEEE.numeric_std.all;
+use IEEE.std_logic_textio.all;
+use STD.textio.all;
+use common_pkg_lib.common_pkg.all;
+use astron_ram_lib.common_ram_pkg.ALL;
+use common_pkg_lib.common_lfsr_sequences_pkg.all;
+use common_pkg_lib.tb_common_pkg.all;
+use astron_mm_lib.tb_common_mem_pkg.ALL;
+use dp_pkg_lib.dp_stream_pkg.ALL;
+use astron_r2sdf_fft_lib.twiddlesPkg.all;
+use astron_r2sdf_fft_lib.rTwoSDFPkg.all;
+use astron_wb_fft_lib.tb_fft_pkg.all;
+use astron_wb_fft_lib.fft_pkg.all;
+use astron_filter_lib.fil_pkg.all;
+use work.wpfb_pkg.all;
+
+entity tb_wpfb_unit is
+ generic(
+ -- generics for tb
+ g_use_uniNoise_file : boolean := true;
+ g_use_sinus_file : boolean := false;
+ g_use_sinNoise_file : boolean := false;
+ g_use_impulse_file : boolean := false;
+
+ -- type t_wpfb is record
+ -- -- General parameters for the wideband poly phase filter
+ -- wb_factor : natural; -- = default 4, wideband factor
+ -- nof_points : natural; -- = 1024, N point FFT (Also the number of subbands for the filetr part)
+ -- nof_chan : natural; -- = default 0, defines the number of channels (=time-multiplexed input signals): nof channels = 2**nof_chan
+ -- nof_streams : natural; -- = 1, the number of parallel streams. The filter coefficients are shared on every stream.
+ --
+ -- -- Parameters for the poly phase filter
+ -- nof_taps : natural; -- = 16, the number of FIR taps per subband
+ -- fil_backoff_w : natural; -- = 0, number of bits for input backoff to avoid output overflow
+ -- fil_in_dat_w : natural; -- = 8, number of input bits
+ -- fil_out_dat_w : natural; -- = 16, number of output bits
+ -- coef_dat_w : natural; -- = 16, data width of the FIR coefficients
+ --
+ -- -- Parameters for the FFT
+ -- use_reorder : boolean; -- = false for bit-reversed output, true for normal output
+ -- use_fft_shift : boolean; -- = false for [0, pos, neg] bin frequencies order, true for [neg, 0, pos] bin frequencies order in case of complex input
+ -- use_separate : boolean; -- = false for complex input, true for two real inputs
+ -- fft_in_dat_w : natural; -- = 16, number of input bits
+ -- fft_out_dat_w : natural; -- = 13, number of output bits
+ -- fft_out_gain_w : natural; -- = 0, output gain factor applied after the last stage output, before requantization to out_dat_w
+ -- stage_dat_w : natural; -- = 18, number of bits that are used inter-stage
+ -- guard_w : natural; -- = 2
+ -- guard_enable : boolean; -- = true
+ --
+ -- -- Parameters for the statistics
+ -- stat_data_w : positive; -- = 56
+ -- stat_data_sz : positive; -- = 2
+ -- nof_blk_per_sync : natural; -- = 800000, number of FFT output blocks per sync interval
+ --
+ -- -- Pipeline parameters for both poly phase filter and FFT. These are heritaged from the filter and fft libraries.
+ -- pft_pipeline : t_fft_pipeline; -- Pipeline settings for the pipelined FFT
+ -- fft_pipeline : t_fft_pipeline; -- Pipeline settings for the parallel FFT
+ -- fil_pipeline : t_fil_ppf_pipeline; -- Pipeline settings for the filter units
+ --
+ -- end record;
+
+ g_wpfb : t_wpfb := (4, 1024, 0, 1,
+ 16, 0, 8, 16, 16,
+ true, false, true, 16, 16, 0, 18, 2, true, 56, 2, 10,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+
+ g_coefs_file_prefix : string := "data/coefs_wide"
+
+ );
+
+end entity tb_wpfb_unit;
+
+architecture tb of tb_wpfb_unit is
+
+ constant c_clk_period : time := 100 ns;
+
+ constant c_fft : t_fft := (g_wpfb.use_reorder,
+ g_wpfb.use_fft_shift,
+ g_wpfb.use_separate,
+ 0,
+ g_wpfb.wb_factor,
+ 0,
+ g_wpfb.nof_points,
+ g_wpfb.fft_in_dat_w,
+ g_wpfb.fft_out_dat_w,
+ g_wpfb.fft_out_gain_w,
+ g_wpfb.stage_dat_w,
+ g_wpfb.guard_w,
+ g_wpfb.guard_enable,
+ g_wpfb.stat_data_w,
+ g_wpfb.stat_data_sz);
+
+ -- input/output data width
+ constant c_in_dat_w : natural := g_wpfb.fil_in_dat_w;
+ constant c_twiddle_w : natural := 16;
+ constant c_out_dat_w : natural := g_wpfb.fft_out_dat_w; -- g_rtwo_fft.in_dat_w + natural((ceil_log2(g_rtwo_fft.nof_points))/2 + 2); -- bit growth
+
+ -- input/output files
+ constant c_nof_spectra_in_file : natural := 8;
+ constant c_file_len : natural := c_nof_spectra_in_file*g_wpfb.nof_points;
+ constant c_nof_spectra_to_output_file : natural := 8;
+
+ -- block generator
+ constant c_bg_mem_size : natural := g_wpfb.nof_points/g_wpfb.wb_factor;
+ constant c_bg_addr_w : natural := ceil_log2(c_bg_mem_size);
+ constant c_nof_samples_in_packet : natural := c_bg_mem_size;
+ constant c_gap : natural := 0; -- Gapsize is set to 0 in order to generate a continuous stream of packets.
+ constant c_nof_accum_per_sync : natural := g_wpfb.nof_blk_per_sync;
+ constant c_bsn_init : natural := 32;
+ constant c_bg_prefix : string := "UNUSED";
+ constant c_nof_sync_periods : natural := 10;
+ constant c_bst_skip_nof_sync : natural := 3;
+
+ constant c_nof_bands_per_chn : natural := g_wpfb.nof_points/g_wpfb.wb_factor;
+ constant c_normal : boolean := true;
+
+ -- input from uniform noise file created automatically by MATLAB testFFT_input.m
+ constant c_noiseInputFile : string := "data/uniNoise_in.txt";
+ constant c_noiseGoldenFile : string := "data/uniNoise_p" & natural'image(g_wpfb.nof_points)& "_t"& natural'image(g_wpfb.nof_taps) & "_gold.txt";
+ constant c_noiseOutputFile : string := "data/uniNoise_out.txt";
+
+ constant c_inputFile : string := c_noiseInputFile;
+
+ constant c_goldenFile : string := c_noiseGoldenFile;
+
+ constant c_outputFile : string := c_noiseOutputFile;
+
+ constant c_coefs_file_prefix : string := g_coefs_file_prefix & natural'image(g_wpfb.wb_factor) & "_p"& natural'image(g_wpfb.nof_points) & "_t"& natural'image(g_wpfb.nof_taps);
+
+ -- signal definitions
+ signal tb_end : std_logic := '0';
+ signal clk : std_logic := '0';
+ signal rst : std_logic := '0';
+
+ signal out_sync : std_logic:= '0';
+ signal out_val : std_logic:= '0';
+ signal out_re_arr : t_fft_slv_arr(g_wpfb.wb_factor-1 downto 0);
+ signal out_im_arr : t_fft_slv_arr(g_wpfb.wb_factor-1 downto 0);
+
+ signal in_file_data : t_integer_matrix(0 to c_file_len-1, 1 to 2) := (others=>(others=>0)); -- [re, im]
+ signal in_file_sync : std_logic_vector(0 to c_file_len-1):= (others=>'0');
+ signal in_file_val : std_logic_vector(0 to c_file_len-1):= (others=>'0');
+
+ signal gold_file_data : t_integer_matrix(0 to c_file_len-1, 1 to 2) := (others=>(others=>0)); -- [re, im]
+ signal gold_file_sync : std_logic_vector(0 to c_file_len-1):= (others=>'0');
+ signal gold_file_val : std_logic_vector(0 to c_file_len-1):= (others=>'0');
+
+ signal gold_sync : std_logic;
+ signal gold_re_arr : t_integer_arr(g_wpfb.wb_factor-1 downto 0);
+ signal gold_im_arr : t_integer_arr(g_wpfb.wb_factor-1 downto 0);
+
+ signal init_waveforms_done : std_logic;
+
+ signal in_sosi_arr : t_dp_sosi_arr(g_wpfb.wb_factor-1 downto 0);
+ signal in_siso_arr : t_dp_siso_arr(g_wpfb.wb_factor-1 downto 0);
+
+ type t_dp_sosi_matrix is array (integer range <>) of t_dp_sosi_arr(0 downto 0);
+ type t_dp_siso_matrix is array (integer range <>) of t_dp_siso_arr(0 downto 0);
+
+ signal in_sosi_matrix : t_dp_sosi_matrix(g_wpfb.wb_factor-1 downto 0);
+ signal in_siso_matrix : t_dp_siso_matrix(g_wpfb.wb_factor-1 downto 0);
+
+ signal result_sosi_arr : t_dp_sosi_arr(g_wpfb.wb_factor-1 downto 0);
+
+ signal ram_sst_mosi : t_mem_mosi := c_mem_mosi_rst;
+ signal ram_sst_miso : t_mem_miso := c_mem_miso_rst;
+
+ signal ram_coefs_mosi : t_mem_mosi := c_mem_mosi_rst;
+ signal ram_coefs_miso : t_mem_miso := c_mem_miso_rst;
+ signal coefs_arr : t_integer_arr (c_nof_bands_per_chn-1 downto 0);
+
+ signal ram_bg_data_mosi_arr : t_mem_mosi_arr(g_wpfb.wb_factor-1 downto 0) := (others => c_mem_mosi_rst );
+ signal reg_bg_ctrl_mosi : t_mem_mosi;
+
+ signal reg_diag_bg_dut_mosi : t_mem_mosi := c_mem_mosi_rst;
+ signal reg_diag_bg_dut_miso : t_mem_miso := c_mem_miso_rst;
+
+ signal ram_diag_bg_dut_mosi : t_mem_mosi := c_mem_mosi_rst;
+ signal ram_diag_bg_dut_miso : t_mem_miso := c_mem_miso_rst;
+
+ -- Subband Statistics output
+ -- . DUT result
+ signal result_sst_arr_temp : t_slv_64_arr(c_nof_samples_in_packet-1 downto 0);
+ signal result_sst_arr : t_slv_64_arr(g_wpfb.nof_points-1 downto 0);
+ -- . Expected result
+ signal expected_sst_arr : t_slv_64_arr(g_wpfb.nof_points-1 downto 0) := (others => (others => '0'));
+
+ signal coefs_mem_write : boolean := FALSE;
+ signal temp_reg : integer;
+
+begin
+
+ clk <= (not clk) or tb_end after c_clk_period/2;
+ rst <= '1', '0' after c_clk_period*7;
+
+ ---------------------------------------------------------------
+ -- WRITE AND READ THE COEFFICIENTS TO THE COEFS MEMORY
+ ---------------------------------------------------------------
+ p_coefs_memory_write : process
+ begin
+ coefs_mem_write <= FALSE;
+ ram_coefs_mosi <= c_mem_mosi_rst; -- Reset the master out interface
+ -- Write the coefficients
+ for L in 0 to c_nof_complex loop -- There are two filters in the DUT: real and imaginary
+ for K in 0 to g_wpfb.wb_factor-1 loop
+ for J in 0 to g_wpfb.nof_taps-1 loop
+ proc_common_read_mif_file(c_coefs_file_prefix & "_" & integer'image(k*g_wpfb.nof_taps+J) & ".mif", coefs_arr);
+ wait for 1 ns;
+ for I in 0 to c_nof_bands_per_chn-1 loop
+ proc_mem_mm_bus_wr(L*g_wpfb.nof_points*g_wpfb.nof_taps + K*c_nof_bands_per_chn*g_wpfb.nof_taps + J*c_nof_bands_per_chn + I, coefs_arr(I), clk, ram_coefs_mosi); -- Write the coefficient to the memory
+ end loop;
+ end loop;
+ end loop;
+ end loop;
+ -- Read the coefficients back and verify
+ for L in 0 to c_nof_complex loop -- There are two filters in the DUT: real and imaginary
+ for K in 0 to g_wpfb.wb_factor-1 loop
+ for J in 0 to g_wpfb.nof_taps-1 loop
+ proc_common_read_mif_file(c_coefs_file_prefix & "_" & integer'image(k*g_wpfb.nof_taps+J) & ".mif", coefs_arr);
+ wait for 1 ns;
+ for I in 0 to c_nof_bands_per_chn-1 loop
+ proc_mem_mm_bus_rd(L*g_wpfb.nof_points*g_wpfb.nof_taps + K*c_nof_bands_per_chn*g_wpfb.nof_taps + J*c_nof_bands_per_chn + I, clk, ram_coefs_miso, ram_coefs_mosi); -- Read the coefficient from the memory
+ temp_reg <= coefs_arr(I);
+ if(ram_coefs_miso.rdval = '1') then
+ assert temp_reg = TO_UINT(ram_coefs_miso.rddata(g_wpfb.coef_dat_w-1 downto 0)) report "Read data from memory error" severity error;
+ end if;
+ end loop;
+ proc_common_wait_some_cycles(clk, 1);
+ end loop;
+ end loop;
+ end loop;
+
+ coefs_mem_write <= TRUE;
+ wait;
+ end process;
+
+ ---------------------------------------------------------------
+ -- READ STIMULI DATA FROM INPUT FILE
+ ---------------------------------------------------------------
+ proc_read_input_file(clk, in_file_data, c_inputFile);
+
+ ------------------------------------------------------------------------------
+ -- WRITE THE WAVEFORMS INTO MEMORY FOR EACH INPUT STREAM.
+ ------------------------------------------------------------------------------
+ gen_init_waveforms : for I in 0 to g_wpfb.wb_factor-1 generate
+ p_init_waveforms_memory : process
+ variable v_mem_data : std_logic_vector(c_nof_complex*g_wpfb.fil_in_dat_w-1 downto 0);
+ begin
+ init_waveforms_done <= '0';
+
+ proc_common_wait_until_low(clk, rst); -- Wait until reset has finished
+ proc_common_wait_some_cycles(clk, 10); -- Wait an additional amount of cycles
+
+ for J in 0 to c_bg_mem_size-1 loop
+ v_mem_data := (others => '0');
+ v_mem_data := TO_SVEC(in_file_data(I+J*g_wpfb.wb_factor, 2), g_wpfb.fil_in_dat_w) & TO_SVEC(in_file_data(I+J*g_wpfb.wb_factor, 1), g_wpfb.fil_in_dat_w);
+ proc_mem_mm_bus_wr(J, v_mem_data, clk, ram_bg_data_mosi_arr(I));
+ end loop;
+
+ init_waveforms_done <= '1';
+ wait;
+ end process;
+ end generate;
+
+ ------------------------------------------------------------------------------
+ -- CONFIGURE AND ENABLE THE BLOCK GENERATORS (Start Stimuli)
+ ------------------------------------------------------------------------------
+ p_control_input_stream : process
+ begin
+ reg_bg_ctrl_mosi <= c_mem_mosi_rst;
+
+ -- Wait until reset is done
+ proc_common_wait_until_high(clk, rst);
+ proc_common_wait_some_cycles(clk, 10);
+ wait until init_waveforms_done = '1'; -- Wait until the waveform data is written.
+ wait until coefs_mem_write = TRUE; -- Wait until the coefficients are written.
+
+ -- Set and enable the waveform generators. All generators are controlled by the same registers
+ proc_mem_mm_bus_wr(1, c_nof_samples_in_packet, clk, reg_bg_ctrl_mosi); -- Set the number of samples per block
+ proc_mem_mm_bus_wr(2, c_nof_accum_per_sync, clk, reg_bg_ctrl_mosi); -- Set the number of blocks per sync
+ proc_mem_mm_bus_wr(3, c_gap, clk, reg_bg_ctrl_mosi); -- Set the gapsize
+ proc_mem_mm_bus_wr(4, 0, clk, reg_bg_ctrl_mosi); -- Set the start address of the memory
+ proc_mem_mm_bus_wr(5, c_bg_mem_size-1, clk, reg_bg_ctrl_mosi); -- Set the end address of the memory
+ proc_mem_mm_bus_wr(6, c_bsn_init, clk, reg_bg_ctrl_mosi); -- Set the BSNInit low value
+ proc_mem_mm_bus_wr(7, 0, clk, reg_bg_ctrl_mosi); -- Set the BSNInit high value
+ proc_mem_mm_bus_wr(0, 1, clk, reg_bg_ctrl_mosi); -- Enable the BG
+
+ -- Run time is defined by:
+ -- * the number of sync periods
+ -- * the number of packets in a sync period (c_nof_accum_per_sync)
+ -- * the number of samples in a packet
+ -- * the gap size
+ proc_common_wait_some_cycles(clk, c_nof_sync_periods*c_nof_accum_per_sync*(c_nof_samples_in_packet+c_gap));
+
+ -- Disable the BG
+ proc_mem_mm_bus_wr(0, 0, clk, reg_bg_ctrl_mosi);
+
+ -- Wait some additional time in order to let release the pipline stages of the FFT.
+ proc_common_wait_some_cycles(clk, 4*g_wpfb.nof_points);
+ tb_end <= '1';
+
+ wait;
+ end process;
+
+ ---------------------------------------------------------------
+ -- GENERATE BLOCK GENERATORS FOR STIMULI GENERATION
+ ---------------------------------------------------------------
+ gen_block_gen : for I in 0 to g_wpfb.wb_factor-1 generate
+ u_block_generator : entity astron_diagnostics_lib.mms_diag_block_gen
+ generic map(
+ g_nof_streams => 1,
+ g_buf_dat_w => c_nof_complex*g_wpfb.fil_in_dat_w,
+ g_buf_addr_w => c_bg_addr_w,
+ g_file_name_prefix => c_bg_prefix
+ )
+ port map(
+ -- Clocks and Reset
+ mm_rst => rst,
+ mm_clk => clk,
+ dp_rst => rst,
+ dp_clk => clk,
+ en_sync => '1',
+ ram_bg_data_mosi => ram_bg_data_mosi_arr(I),
+ ram_bg_data_miso => open,
+ reg_bg_ctrl_mosi => reg_bg_ctrl_mosi,
+ reg_bg_ctrl_miso => open,
+ out_siso_arr => in_siso_matrix(I),
+ out_sosi_arr => in_sosi_matrix(I)
+ );
+ in_sosi_arr(I) <= in_sosi_matrix(I)(0);
+ in_siso_matrix(I)(0) <= c_dp_siso_rdy;
+ end generate;
+
+ ------------------------------------------------------------------------------
+ -- READ THE BEAMLET STATISTICS AND VERIFY
+ ------------------------------------------------------------------------------
+ -- Read statistics from the memory interface once every sync interval.
+ p_read_sst_memory : process
+ variable c_sync_cnt : natural;
+ begin
+ proc_common_wait_until_low(clk, rst); -- Wait until reset has finished
+
+ -- Skip reading for the initial syncs to save simulation time
+ for J in 0 to c_bst_skip_nof_sync-2 loop
+ wait until result_sosi_arr(0).sync = '1';
+ wait until result_sosi_arr(0).sync = '0';
+ end loop;
+
+ while(true) loop
+ wait until result_sosi_arr(0).sync = '1';
+ proc_common_wait_some_cycles(clk, c_nof_samples_in_packet+6);
+
+ for I in 0 to g_wpfb.wb_factor-1 loop
+ proc_fft_read_subband_statistics_memory(I, c_fft, clk, ram_sst_mosi, ram_sst_miso, result_sst_arr_temp);
+ result_sst_arr((I+1)*c_nof_samples_in_packet-1 downto I*c_nof_samples_in_packet) <= result_sst_arr_temp; -- can not use result_bst_arr2(I) directly as argument in proc_bf_read_beamlet_statistics_memory()
+ end loop;
+
+ proc_common_wait_some_cycles(clk, 10);
+
+ assert expected_sst_arr = result_sst_arr report "Output statistics error" severity error;
+ assert expected_sst_arr /= result_sst_arr report "Output statistics OK!!!!" severity note;
+
+ end loop;
+ end process;
+
+ ---------------------------------------------------------------
+ -- DUT = Device Under Test
+ ---------------------------------------------------------------
+ u_dut : entity work.wpfb_unit
+ generic map (
+ g_wpfb => g_wpfb,
+ g_use_bg => FALSE,
+ g_coefs_file_prefix => c_coefs_file_prefix
+ )
+ port map (
+ dp_rst => rst,
+ dp_clk => clk,
+ mm_rst => rst,
+ mm_clk => clk,
+ ram_fil_coefs_mosi => ram_coefs_mosi,
+ ram_fil_coefs_miso => ram_coefs_miso,
+ ram_st_sst_mosi => ram_sst_mosi,
+ ram_st_sst_miso => ram_sst_miso,
+ reg_bg_ctrl_mosi => reg_diag_bg_dut_mosi,
+ reg_bg_ctrl_miso => reg_diag_bg_dut_miso,
+ ram_bg_data_mosi => ram_diag_bg_dut_mosi,
+ ram_bg_data_miso => ram_diag_bg_dut_miso,
+ in_sosi_arr => in_sosi_arr,
+ out_sosi_arr => result_sosi_arr
+ );
+
+ ---------------------------------------------------------------
+ -- REARRANGE THE OUTPUT-DATA FOR VERIFICATION
+ ---------------------------------------------------------------
+ gen_extract_data : for I in 0 to g_wpfb.wb_factor-1 generate
+ out_re_arr(I) <= RESIZE_SVEC(result_sosi_arr(I).re, out_re_arr(I)'length);
+ out_im_arr(I) <= RESIZE_SVEC(result_sosi_arr(I).im, out_im_arr(I)'length);
+ end generate;
+ out_val <= result_sosi_arr(0).valid;
+
+ ---------------------------------------------------------------
+ -- READ GOLDEN FILE WITH THE EXPECTED DUT OUTPUT
+ ---------------------------------------------------------------
+ proc_read_input_file(clk, gold_file_data, c_goldenFile);
+
+ ---------------------------------------------------------------
+ -- CALCULATE THE STATISTICS, BASED ON THE RAW OUTPUT DATA
+ -- OF THE DUT
+ ---------------------------------------------------------------
+ p_calculate_stats_reference_array : process
+ constant c_sst_in_w : natural := 18;
+ variable v_nof_outs : natural := g_wpfb.nof_points/g_wpfb.wb_factor;
+ variable v_int_time : integer := 0;
+ variable v_subband_cnt : integer := 0;
+
+ variable v_sum_re : std_logic_vector(c_sst_in_w-1 downto 0);
+ variable v_sum_im : std_logic_vector(c_sst_in_w-1 downto 0);
+
+ variable v_sum_pwr : std_logic_vector(g_wpfb.stat_data_w-1 downto 0) := (others => '0');
+ variable v_acc_pwr_arr : t_slv_64_arr(g_wpfb.nof_points-1 downto 0) := (others => (others => '0'));
+ begin
+ wait until rising_edge(clk);
+ if(out_val = '1') then
+ for I in 0 to g_wpfb.wb_factor-1 loop
+ -- Calculate the auto correlation power:
+ v_sum_re := RESIZE_SVEC(SHIFT_SVEC(out_re_arr(I), g_wpfb.fft_out_dat_w-c_sst_in_w), v_sum_re'length);
+ v_sum_im := RESIZE_SVEC(SHIFT_SVEC(out_im_arr(I), g_wpfb.fft_out_dat_w-c_sst_in_w), v_sum_im'length);
+ v_sum_pwr(32 downto 0) := func_complex_multiply(v_sum_re, v_sum_im, v_sum_re, v_sum_im, c_normal, "RE", 33);
+ v_acc_pwr_arr(I*v_nof_outs + v_subband_cnt) := ADD_UVEC(v_acc_pwr_arr(I*v_nof_outs + v_subband_cnt), v_sum_pwr);
+ end loop;
+
+ if(v_subband_cnt = v_nof_outs-1) then
+ v_subband_cnt := 0;
+ else
+ v_subband_cnt := v_subband_cnt + 1;
+ end if;
+
+ ------------------------------------------------------------------------
+ -- Latch the expected accumulated statistics to the output at the sync
+ ------------------------------------------------------------------------
+ if(v_int_time = c_nof_accum_per_sync*v_nof_outs-1) then
+ v_int_time := 0;
+ -- Output the expected BST array
+ expected_sst_arr <= v_acc_pwr_arr;
+ v_acc_pwr_arr :=(others => (others => '0'));
+ else
+ v_int_time := v_int_time + 1;
+ end if;
+ end if;
+
+ end process;
+
+ ---------------------------------------------------------------
+ -- CREATE THE GOLDEN ARRAY FOR VERIFICATION
+ ---------------------------------------------------------------
+ p_create_golden_array : process
+ constant c_sst_in_w : natural := 16;
+ variable v_nof_outs : natural := g_wpfb.nof_points/g_wpfb.wb_factor;
+ variable v_bin_index : natural := 0;
+ variable v_spectrum_index : natural := 0;
+ variable v_list_index : natural := 0;
+ begin
+ wait until rising_edge(clk);
+ if(out_val = '1') then
+ if(v_spectrum_index = v_nof_outs - 1) then
+ v_spectrum_index := 0;
+ v_bin_index := v_bin_index + g_wpfb.nof_points - v_nof_outs;
+ else
+ v_spectrum_index := v_spectrum_index + 1;
+ end if;
+ v_bin_index := v_bin_index + 1;
+
+ if(v_list_index = c_file_len/g_wpfb.wb_factor-1) then
+ v_bin_index := 0;
+ v_list_index := 0;
+ else
+ v_list_index := v_list_index + 1;
+ end if;
+
+ end if;
+
+ for I in 0 to g_wpfb.wb_factor-1 loop
+ gold_re_arr(I) <= gold_file_data(v_bin_index + I*v_nof_outs, 1);
+ gold_im_arr(I) <= gold_file_data(v_bin_index + I*v_nof_outs, 2);
+ end loop;
+
+ gold_sync <= gold_file_sync(v_bin_index);
+
+ end process;
+
+ -- Verify the output of the DUT with the expected output from the golden reference file
+ p_verify_output : process(clk)
+ variable v_output_cnt : integer := 0;
+ begin
+ -- Compare
+ if rising_edge(clk) then
+ if (out_val='1' and v_output_cnt < (c_nof_spectra_in_file*g_wpfb.nof_points/g_wpfb.wb_factor)) then
+ -- only write when out_val='1', because then the file is independent of cycles with invalid out_dat
+ -- only check the first c_nof_spectra_in_file spectrums.
+ assert out_sync = gold_sync report "Output sync error" severity error;
+ for I in 0 to g_wpfb.wb_factor-1 loop
+ assert TO_SINT(out_re_arr(I)) = gold_re_arr(I) report "Output real data error" severity error;
+ assert TO_SINT(out_im_arr(I)) = gold_im_arr(I) report "Output imag data error" severity error;
+ end loop;
+ v_output_cnt := v_output_cnt + 1;
+ end if;
+ end if;
+ end process;
+
+ -- Write to default output file, this allows using command line diff or graphical diff viewer to compare it with the golden result file
+ p_write_output_file : process(clk)
+ file v_output : text open WRITE_MODE is c_outputFile;
+ variable v_line : line;
+ constant c_nof_bins : natural := g_wpfb.nof_points/g_wpfb.wb_factor;
+ variable v_out_re_matrix : t_integer_matrix(g_wpfb.wb_factor-1 downto 0, c_nof_bins-1 downto 0);
+ variable v_out_im_matrix : t_integer_matrix(g_wpfb.wb_factor-1 downto 0, c_nof_bins-1 downto 0);
+ variable v_bin_cnt : integer := 0;
+ variable v_spectra_cnt : integer := 0;
+ begin
+ if rising_edge(clk) then
+ if out_val='1' then
+ -- only write when out_val='1', because then the file is independent of cycles with invalid out_dat
+ for I in 0 to g_wpfb.wb_factor-1 loop
+ v_out_re_matrix(I, v_bin_cnt) := TO_SINT(out_re_arr(I));
+ v_out_im_matrix(I, v_bin_cnt) := TO_SINT(out_im_arr(I));
+ end loop;
+
+ if(v_bin_cnt = c_nof_bins-1) then
+ if (v_spectra_cnt < c_nof_spectra_to_output_file) then
+ for K in 0 to g_wpfb.wb_factor-1 loop
+ for L in 0 to c_nof_bins-1 loop
+ write(v_line, v_out_re_matrix(K,L));
+ write(v_line, string'(","));
+ write(v_line, v_out_im_matrix(K,L));
+ writeline(v_output, v_line);
+ end loop;
+ end loop;
+ end if;
+ v_spectra_cnt := v_spectra_cnt + 1;
+ v_bin_cnt := 0;
+ else
+ v_bin_cnt := v_bin_cnt + 1;
+ end if;
+ end if;
+ end if;
+ end process;
+
+end tb;
Index: trunk/tb_wpfb_unit_dev.vhd
===================================================================
--- trunk/tb_wpfb_unit_dev.vhd (nonexistent)
+++ trunk/tb_wpfb_unit_dev.vhd (revision 2)
@@ -0,0 +1,445 @@
+
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2012
+-- ASTRON (Netherlands Institute for Radio Astronomy)
+-- 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 .
+--
+-------------------------------------------------------------------------------
+--
+-- Purpose: Test bench for the wideband poly phase filterbank.
+--
+-- The testbech uses blockgenerators to generate data for
+-- every input of the wideband poly phase filterbank.
+-- The output of the WPFB is stored in databuffers.
+-- Both the block generators and databuffers are controlled
+-- via a mm interface.
+-- Use this testbench in conjunction with:
+--
+-- ../python/tc_mmf_wpfb_unit.py
+-- For verifying the complete wideband polyphase filter bank: g_use_bg = FALSE
+--
+-- ../python/tc_mmf_wpfb_unit_functional.py
+-- For verifying the different wide- and narrowband configurationss
+-- of the wpfb_unit.
+--
+-- (Automated) Usage:
+-- > Be sure that the c_start_modelsim variable is set to 1 in the script.
+-- > Run python script in separate terminal: "python tc_mmf_wpfb_unit.py --unb 0 --bn 0 --sim"
+--
+-- (Manual) Usage:
+-- > run -all
+-- > Be sure that the c_start_modelsim variable is set to 0 in the script.
+-- > Run python script in separate terminal: "python tc_mmf_wpfb_unit.py --unb 0 --bn 0 --sim"
+-- > Check the results of the python script.
+-- > Stop the simulation manually in Modelsim by pressing the stop-button.
+-- > For fractional frequencies set g_nof_blocks=32 to be able to simulate a sufficent number of periods without transition.
+
+
+LIBRARY IEEE, common_pkg_lib, astron_mm_lib, astron_diagnostics_lib, dp_pkg_lib, astron_r2sdf_fft_lib, astron_wb_fft_lib, astron_filter_lib, astron_ram_lib, astron_sim_tools_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE IEEE.math_real.ALL;
+USE common_pkg_lib.common_pkg.ALL;
+USE astron_ram_lib.common_ram_pkg.ALL;
+USE common_pkg_lib.common_str_pkg.ALL;
+USE common_pkg_lib.tb_common_pkg.ALL;
+USE astron_mm_lib.tb_common_mem_pkg.ALL;
+USE astron_mm_lib.mm_file_unb_pkg.ALL;
+USE astron_mm_lib.mm_file_pkg.ALL;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+USE astron_diagnostics_lib.diag_pkg.ALL;
+USE astron_r2sdf_fft_lib.twiddlesPkg.all;
+USE astron_r2sdf_fft_lib.rTwoSDFPkg.all;
+USE astron_wb_fft_lib.tb_fft_pkg.all;
+USE astron_wb_fft_lib.fft_pkg.all;
+USE astron_filter_lib.fil_pkg.all;
+USE work.wpfb_pkg.all;
+
+
+ENTITY tb_wpfb_unit_dev IS
+ GENERIC(
+ g_wb_factor : NATURAL := 1; -- = default 1, wideband factor
+ g_nof_wb_streams : NATURAL := 1; -- = 1, the number of parallel wideband streams. The filter coefficients are shared on every wb-stream.
+ g_nof_chan : NATURAL := 0; -- = default 0, defines the number of channels (=time-multiplexed input signals): nof channels = 2**nof_chan
+ g_nof_points : NATURAL := 64; -- = 1024, N point FFT
+ g_nof_taps : NATURAL := 8; -- = 8 nof taps n the filter
+ g_nof_blocks : NATURAL := 4; -- = 4, the number of blocks of g_nof_points each in the BG waveform (must be power of 2 due to that BG c_bg_block_len must be power of 2)
+ g_in_dat_w : NATURAL := 8; -- = 8, number of input bits
+ g_out_dat_w : NATURAL := 16; -- = 14, number of output bits: in_dat_w + natural((ceil_log2(nof_points))/2)
+ g_use_prefilter : BOOLEAN := FALSE; --TRUE;
+ g_use_separate : BOOLEAN := FALSE; -- = false for complex input, true for two real inputs
+ g_use_bg : BOOLEAN := FALSE;
+ g_coefs_file_prefix : STRING := "hex/chan_fil_coefs_wide"
+ );
+END tb_wpfb_unit_dev;
+
+ARCHITECTURE tb OF tb_wpfb_unit_dev IS
+
+ CONSTANT c_wpfb : t_wpfb := (g_wb_factor, g_nof_points, g_nof_chan, g_nof_wb_streams,
+ g_nof_taps, 0, g_in_dat_w, 16, 16,
+ true, false, g_use_separate, 16, g_out_dat_w, 0, 18, 2, true, 56, 2, 20,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+
+ -- type t_wpfb is record
+ -- -- General parameters for the wideband poly phase filter
+ -- wb_factor : natural; -- = default 4, wideband factor
+ -- nof_points : natural; -- = 1024, N point FFT (Also the number of subbands for the filetr part)
+ -- nof_chan : natural; -- = default 0, defines the number of channels (=time-multiplexed input signals): nof channels = 2**nof_chan
+ -- nof_wb_streams : natural; -- = 1, the number of parallel wideband streams. The filter coefficients are shared on every stream.
+ --
+ -- -- Parameters for the poly phase filter
+ -- nof_taps : natural; -- = 16, the number of FIR taps per subband
+ -- fil_backoff_w : natural; -- = 0, number of bits for input backoff to avoid output overflow
+ -- fil_in_dat_w : natural; -- = 8, number of input bits
+ -- fil_out_dat_w : natural; -- = 16, number of output bits
+ -- coef_dat_w : natural; -- = 16, data width of the FIR coefficients
+ --
+ -- -- Parameters for the FFT
+ -- use_reorder : boolean; -- = false for bit-reversed output, true for normal output
+ -- use_fft_shift : boolean; -- = false for [0, pos, neg] bin frequencies order, true for [neg, 0, pos] bin frequencies order in case of complex input
+ -- use_separate : boolean; -- = false for complex input, true for two real inputs
+ -- fft_in_dat_w : natural; -- = 16, number of input bits
+ -- fft_out_dat_w : natural; -- = 13, number of output bits
+ -- fft_out_gain_w : natural; -- = 0, output gain factor applied after the last stage output, before requantization to out_dat_w
+ -- stage_dat_w : natural; -- = 18, number of bits that are used inter-stage
+ --
+ -- -- Parameters for the statistics
+ -- stat_data_w : positive; -- = 56
+ -- stat_data_sz : positive; -- = 2
+ -- nof_blk_per_sync : natural; -- = 800000, number of FFT output blocks per sync interval
+ --
+ -- -- Pipeline parameters for both poly phase filter and FFT. These are heritaged from the filter and fft libraries.
+ -- pft_pipeline : t_fft_pipeline; -- Pipeline settings for the pipelined FFT
+ -- fft_pipeline : t_fft_pipeline; -- Pipeline settings for the parallel FFT
+ -- fil_pipeline : t_fil_ppf_pipeline; -- Pipeline settings for the filter units
+ --
+ -- end record;
+
+ ----------------------------------------------------------------------------
+ -- Clocks and resets
+ ----------------------------------------------------------------------------
+ CONSTANT c_mm_clk_period : TIME := 100 ps;
+ CONSTANT c_dp_clk_period : TIME := 5 ns;
+ CONSTANT c_sclk_period : TIME := c_dp_clk_period / c_wpfb.wb_factor;
+ CONSTANT c_dp_pps_period : NATURAL := 64;
+
+ SIGNAL dp_pps : STD_LOGIC;
+
+ SIGNAL mm_rst : STD_LOGIC;
+ SIGNAL mm_clk : STD_LOGIC := '0';
+
+ SIGNAL dp_rst : STD_LOGIC;
+ SIGNAL dp_clk : STD_LOGIC := '0';
+
+ SIGNAL SCLK : STD_LOGIC := '0';
+
+ ----------------------------------------------------------------------------
+ -- MM buses
+ ----------------------------------------------------------------------------
+ SIGNAL reg_diag_bg_mosi : t_mem_mosi;
+ SIGNAL reg_diag_bg_miso : t_mem_miso;
+
+ SIGNAL ram_diag_bg_mosi : t_mem_mosi;
+ SIGNAL ram_diag_bg_miso : t_mem_miso;
+
+ SIGNAL ram_diag_data_buf_re_mosi : t_mem_mosi;
+ SIGNAL ram_diag_data_buf_re_miso : t_mem_miso;
+
+ SIGNAL reg_diag_data_buf_re_mosi : t_mem_mosi;
+ SIGNAL reg_diag_data_buf_re_miso : t_mem_miso;
+
+ SIGNAL ram_diag_data_buf_im_mosi : t_mem_mosi;
+ SIGNAL ram_diag_data_buf_im_miso : t_mem_miso;
+
+ SIGNAL reg_diag_data_buf_im_mosi : t_mem_mosi;
+ SIGNAL reg_diag_data_buf_im_miso : t_mem_miso;
+
+ SIGNAL ram_st_sst_mosi : t_mem_mosi := c_mem_mosi_rst;
+ SIGNAL ram_st_sst_miso : t_mem_miso := c_mem_miso_rst;
+
+ SIGNAL ram_fil_coefs_mosi : t_mem_mosi := c_mem_mosi_rst;
+ SIGNAL ram_fil_coefs_miso : t_mem_miso := c_mem_miso_rst;
+
+ SIGNAL reg_diag_bg_pfb_mosi : t_mem_mosi := c_mem_mosi_rst;
+ SIGNAL reg_diag_bg_pfb_miso : t_mem_miso := c_mem_miso_rst;
+
+ SIGNAL ram_diag_bg_pfb_mosi : t_mem_mosi := c_mem_mosi_rst;
+ SIGNAL ram_diag_bg_pfb_miso : t_mem_miso := c_mem_miso_rst;
+
+ CONSTANT c_coefs_file_prefix : STRING := g_coefs_file_prefix & NATURAL'IMAGE(c_wpfb.wb_factor) & "_p"& NATURAL'IMAGE(c_wpfb.nof_points) & "_t"& NATURAL'IMAGE(c_wpfb.nof_taps);
+
+ CONSTANT c_nof_streams : POSITIVE := c_wpfb.nof_wb_streams*c_wpfb.wb_factor;
+ CONSTANT c_nof_channels : NATURAL := 2**c_wpfb.nof_chan;
+ CONSTANT c_bg_block_len : NATURAL := c_wpfb.nof_points*g_nof_blocks*c_nof_channels/c_wpfb.wb_factor;
+
+ CONSTANT c_bg_buf_adr_w : NATURAL := ceil_log2(c_bg_block_len);
+ CONSTANT c_bg_data_file_index_arr : t_nat_natural_arr := array_init(0, c_nof_streams, 1);
+ CONSTANT c_bg_data_file_prefix : STRING := "UNUSED";
+
+ SIGNAL bg_siso_arr : t_dp_siso_arr(c_nof_streams-1 DOWNTO 0) := (OTHERS=>c_dp_siso_rdy);
+ SIGNAL bg_sosi_arr : t_dp_sosi_arr(c_nof_streams-1 DOWNTO 0);
+ SIGNAL out_sosi_arr : t_dp_sosi_arr(c_nof_streams-1 DOWNTO 0);
+
+ SIGNAL scope_in_sosi : t_dp_sosi_integer_arr(c_wpfb.nof_wb_streams-1 DOWNTO 0);
+ SIGNAL scope_out_sosi : t_dp_sosi_integer_arr(c_wpfb.nof_wb_streams-1 DOWNTO 0);
+ SIGNAL scope_out_power : REAL := 0.0;
+ SIGNAL scope_out_ampl : REAL := 0.0;
+ SIGNAL scope_out_index : NATURAL;
+ SIGNAL scope_out_bin : NATURAL;
+ SIGNAL scope_out_band : NATURAL;
+ SIGNAL scope_out_ampl_x : REAL := 0.0;
+ SIGNAL scope_out_ampl_y : REAL := 0.0;
+
+BEGIN
+
+ ----------------------------------------------------------------------------
+ -- Clock and reset generation
+ ----------------------------------------------------------------------------
+ mm_clk <= NOT mm_clk AFTER c_mm_clk_period/2;
+ mm_rst <= '1', '0' AFTER c_mm_clk_period*5;
+
+ dp_clk <= NOT dp_clk AFTER c_dp_clk_period/2;
+ dp_rst <= '1', '0' AFTER c_dp_clk_period*5;
+
+ SCLK <= NOT SCLK AFTER c_sclk_period/2;
+
+ ------------------------------------------------------------------------------
+ -- External PPS
+ ------------------------------------------------------------------------------
+ proc_common_gen_pulse(1, c_dp_pps_period, '1', dp_clk, dp_pps);
+
+ ----------------------------------------------------------------------------
+ -- Procedure that polls a sim control file that can be used to e.g. get
+ -- the simulation time in ns
+ ----------------------------------------------------------------------------
+ mmf_poll_sim_ctrl_file(c_mmf_unb_file_path & "sim.ctrl", c_mmf_unb_file_path & "sim.stat");
+
+ ----------------------------------------------------------------------------
+ -- MM buses
+ ----------------------------------------------------------------------------
+ u_mm_file_reg_diag_bg : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "REG_DIAG_BG")
+ PORT MAP(mm_rst, mm_clk, reg_diag_bg_mosi, reg_diag_bg_miso);
+
+ u_mm_file_ram_diag_bg : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "RAM_DIAG_BG")
+ PORT MAP(mm_rst, mm_clk, ram_diag_bg_mosi, ram_diag_bg_miso);
+
+ u_mm_file_ram_diag_data_buf_re : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "RAM_DIAG_DATA_BUFFER_REAL")
+ PORT MAP(mm_rst, mm_clk, ram_diag_data_buf_re_mosi, ram_diag_data_buf_re_miso);
+
+ u_mm_file_reg_diag_data_buf_re : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "REG_DIAG_DATA_BUFFER_REAL")
+ PORT MAP(mm_rst, mm_clk, reg_diag_data_buf_re_mosi, reg_diag_data_buf_re_miso);
+
+ u_mm_file_ram_diag_data_buf_im : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "RAM_DIAG_DATA_BUFFER_IMAG")
+ PORT MAP(mm_rst, mm_clk, ram_diag_data_buf_im_mosi, ram_diag_data_buf_im_miso);
+
+ u_mm_file_reg_diag_data_buf_im : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "REG_DIAG_DATA_BUFFER_IMAG")
+ PORT MAP(mm_rst, mm_clk, reg_diag_data_buf_im_mosi, reg_diag_data_buf_im_miso);
+
+ u_mm_file_ram_fil_coefs : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "RAM_FIL_COEFS")
+ PORT MAP(mm_rst, mm_clk, ram_fil_coefs_mosi, ram_fil_coefs_miso);
+
+ u_mm_file_ram_st_sst : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "RAM_ST_SST")
+ PORT MAP(mm_rst, mm_clk, ram_st_sst_mosi, ram_st_sst_miso);
+
+ u_mm_file_reg_diag_pfb_bg : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "REG_DIAG_BG_PFB")
+ PORT MAP(mm_rst, mm_clk, reg_diag_bg_pfb_mosi, reg_diag_bg_pfb_miso);
+
+ u_mm_file_ram_diag_pfb_bg : mm_file GENERIC MAP(mmf_unb_file_prefix(0, 0, "BN") & "RAM_DIAG_BG_PFB")
+ PORT MAP(mm_rst, mm_clk, ram_diag_bg_pfb_mosi, ram_diag_bg_pfb_miso);
+
+ ----------------------------------------------------------------------------
+ -- Source: block generator
+ ----------------------------------------------------------------------------
+ u_bg : ENTITY astron_diagnostics_lib.mms_diag_block_gen
+ GENERIC MAP(
+ g_nof_streams => c_nof_streams,
+ g_buf_dat_w => c_nof_complex*c_wpfb.fil_in_dat_w,
+ g_buf_addr_w => c_bg_buf_adr_w, -- Waveform buffer size 2**g_buf_addr_w nof samples
+ g_file_index_arr => c_bg_data_file_index_arr,
+ g_file_name_prefix => c_bg_data_file_prefix
+ )
+ PORT MAP(
+ -- System
+ mm_rst => mm_rst,
+ mm_clk => mm_clk,
+ dp_rst => dp_rst,
+ dp_clk => dp_clk,
+ en_sync => dp_pps,
+ -- MM interface
+ reg_bg_ctrl_mosi => reg_diag_bg_mosi,
+ reg_bg_ctrl_miso => reg_diag_bg_miso,
+ ram_bg_data_mosi => ram_diag_bg_mosi,
+ ram_bg_data_miso => ram_diag_bg_miso,
+ -- ST interface
+ out_siso_arr => bg_siso_arr,
+ out_sosi_arr => bg_sosi_arr
+ );
+
+ ----------------------------------------------------------------------------
+ -- Source: DUT input scope
+ ----------------------------------------------------------------------------
+ gen_input_scopes : FOR I IN 0 TO c_wpfb.nof_wb_streams-1 GENERATE
+ u_in_scope : ENTITY astron_sim_tools_lib.dp_wideband_wb_arr_scope
+ GENERIC MAP (
+ g_sim => TRUE,
+ g_wideband_factor => c_wpfb.wb_factor,
+ g_wideband_big_endian => FALSE,
+ g_dat_w => c_wpfb.fil_in_dat_w
+ )
+ PORT MAP (
+ SCLK => SCLK,
+ wb_sosi_arr => bg_sosi_arr((I+1)*c_wpfb.wb_factor-1 DOWNTO I*c_wpfb.wb_factor),
+ scope_sosi => scope_in_sosi(I)
+ );
+ END GENERATE;
+ ----------------------------------------------------------------------------
+ -- DUT = Device Under Test
+ ----------------------------------------------------------------------------
+ u_dut : ENTITY work.wpfb_unit_dev
+ GENERIC MAP(
+ g_wpfb => c_wpfb,
+ g_use_bg => g_use_bg,
+ g_use_prefilter => g_use_prefilter,
+ g_coefs_file_prefix => c_coefs_file_prefix
+ )
+ PORT MAP(
+ dp_rst => dp_rst,
+ dp_clk => dp_clk,
+ mm_rst => mm_rst,
+ mm_clk => mm_clk,
+ ram_fil_coefs_mosi => ram_fil_coefs_mosi,
+ ram_fil_coefs_miso => ram_fil_coefs_miso,
+ ram_st_sst_mosi => ram_st_sst_mosi,
+ ram_st_sst_miso => ram_st_sst_miso,
+ reg_bg_ctrl_mosi => reg_diag_bg_pfb_mosi,
+ reg_bg_ctrl_miso => reg_diag_bg_pfb_miso,
+ ram_bg_data_mosi => ram_diag_bg_pfb_mosi,
+ ram_bg_data_miso => ram_diag_bg_pfb_miso,
+ in_sosi_arr => bg_sosi_arr,
+ out_sosi_arr => out_sosi_arr
+ );
+
+ time_map : process is
+ variable sim_time_str_v : string(1 to 30); -- 30 chars should be enough
+ variable sim_time_len_v : natural;
+ begin
+ wait for 1000 ns;
+ sim_time_len_v := time'image(now)'length;
+ sim_time_str_v := (others => ' ');
+ sim_time_str_v(1 to sim_time_len_v) := time'image(now);
+ report "Sim time string length: " & integer'image(sim_time_len_v);
+ report "Sim time string.......:'" & sim_time_str_v & "'";
+ end process;
+
+ ----------------------------------------------------------------------------
+ -- Sink: DUT output scope
+ ----------------------------------------------------------------------------
+ gen_output_scopes : FOR I IN 0 TO c_wpfb.nof_wb_streams-1 GENERATE
+ u_out_scope : ENTITY astron_sim_tools_lib.dp_wideband_wb_arr_scope
+ GENERIC MAP (
+ g_sim => TRUE,
+ g_wideband_factor => c_wpfb.wb_factor,
+ g_wideband_big_endian => FALSE,
+ g_dat_w => c_wpfb.fft_out_dat_w
+ )
+ PORT MAP (
+ SCLK => SCLK,
+ wb_sosi_arr => out_sosi_arr((I+1)*c_wpfb.wb_factor-1 DOWNTO I*c_wpfb.wb_factor),
+ scope_sosi => scope_out_sosi(I)
+ );
+ END GENERATE;
+
+ p_scope_out_index : PROCESS(SCLK)
+ BEGIN
+ IF rising_edge(SCLK) THEN
+ IF scope_out_sosi(0).valid='1' THEN
+ scope_out_index <= scope_out_index+1;
+ IF scope_out_index>=g_nof_points-1 THEN
+ scope_out_index <= 0;
+ END IF;
+ END IF;
+ END IF;
+ END PROCESS;
+ scope_out_bin <= fft_index_to_bin_frequency(c_wpfb.wb_factor, c_wpfb.nof_points, scope_out_index, TRUE, FALSE, TRUE); -- complex bin
+ scope_out_band <= fft_index_to_bin_frequency(c_wpfb.wb_factor, c_wpfb.nof_points, scope_out_index, TRUE, TRUE, TRUE); -- two real bin
+
+ scope_out_power <= REAL(scope_out_sosi(0).re)**2 + REAL(scope_out_sosi(0).im)**2;
+ scope_out_ampl <= SQRT(scope_out_power);
+ scope_out_ampl_x <= scope_out_ampl WHEN (scope_out_bin MOD 2)=0 ELSE 0.0;
+ scope_out_ampl_y <= scope_out_ampl WHEN (scope_out_bin MOD 2)=1 ELSE 0.0;
+
+ ----------------------------------------------------------------------------
+ -- Sink: data buffer real
+ ----------------------------------------------------------------------------
+ u_data_buf_re : ENTITY astron_diagnostics_lib.mms_diag_data_buffer
+ GENERIC MAP (
+ g_nof_streams => c_nof_streams,
+ g_data_type => e_real,
+ g_data_w => c_wpfb.fft_out_dat_w,
+ g_buf_nof_data => c_bg_block_len,
+ g_buf_use_sync => TRUE
+ )
+ PORT MAP (
+ -- System
+ mm_rst => mm_rst,
+ mm_clk => mm_clk,
+ dp_rst => dp_rst,
+ dp_clk => dp_clk,
+
+ -- MM interface
+ ram_data_buf_mosi => ram_diag_data_buf_re_mosi,
+ ram_data_buf_miso => ram_diag_data_buf_re_miso,
+
+ reg_data_buf_mosi => reg_diag_data_buf_re_mosi,
+ reg_data_buf_miso => reg_diag_data_buf_re_miso,
+
+ -- ST interface
+ in_sync => out_sosi_arr(0).sync,
+ in_sosi_arr => out_sosi_arr
+ );
+
+ ----------------------------------------------------------------------------
+ -- Sink: data buffer imag
+ ----------------------------------------------------------------------------
+ u_data_buf_im : ENTITY astron_diagnostics_lib.mms_diag_data_buffer
+ GENERIC MAP (
+ g_nof_streams => c_nof_streams,
+ g_data_type => e_imag,
+ g_data_w => c_wpfb.fft_out_dat_w,
+ g_buf_nof_data => c_bg_block_len,
+ g_buf_use_sync => TRUE
+ )
+ PORT MAP (
+ -- System
+ mm_rst => mm_rst,
+ mm_clk => mm_clk,
+ dp_rst => dp_rst,
+ dp_clk => dp_clk,
+
+ -- MM interface
+ ram_data_buf_mosi => ram_diag_data_buf_im_mosi,
+ ram_data_buf_miso => ram_diag_data_buf_im_miso,
+
+ reg_data_buf_mosi => reg_diag_data_buf_im_mosi,
+ reg_data_buf_miso => reg_diag_data_buf_im_miso,
+
+ -- ST interface
+ in_sync => out_sosi_arr(0).sync,
+ in_sosi_arr => out_sosi_arr
+ );
+
+END tb;
Index: trunk/tb_wpfb_unit_wide.vhd
===================================================================
--- trunk/tb_wpfb_unit_wide.vhd (nonexistent)
+++ trunk/tb_wpfb_unit_wide.vhd (revision 2)
@@ -0,0 +1,807 @@
+-- Author: Eric Kooistra : kooistra at astron.nl: july 2016
+--------------------------------------------------------------------------------
+--
+-- Copyright (C) 2016
+-- ASTRON (Netherlands Institute for Radio Astronomy)
+-- 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 .
+--
+--------------------------------------------------------------------------------
+--
+-- Purpose: Test bench for wpfb_unit_dev.vhd using file data
+--
+-- Description:
+-- This tb uses the Matlab stimuli and expected results obtained with:
+--
+-- $RADIOHDL_WORK/applications/apertif/matlab/run_pfb.m
+-- $RADIOHDL_WORK/applications/apertif/matlab/run_pfb_complex.m
+--
+-- For more description see:
+-- . tb_fil_ppf_wide_file_data.vhd
+-- . tb_fft_r2_wide.vhd
+--
+-- Remark:
+-- . tb supports wb_factor = 1 and wb_factor > 1
+-- . tb supports use_separate for complex and two real input
+-- . tb supports use_reorder for complex input with flipped or reordered output
+-- . tb supports use_reorder for two real input with reordered output
+-- . tb does support nof_wb_streams > 1
+-- . tb does support nof_chan > 0
+--
+-- Usage:
+-- > run -all
+-- > testbench is selftesting.
+-- > observe the *_scope signals as radix decimal, format analogue format
+-- signals in the Wave window
+--
+library ieee, common_pkg_lib, dp_pkg_lib, astron_filter_lib, astron_r2sdf_fft_lib, astron_wb_fft_lib, astron_ram_lib, astron_mm_lib, dp_components_lib, astron_sim_tools_lib;
+use IEEE.std_logic_1164.all;
+use IEEE.numeric_std.all;
+use IEEE.std_logic_textio.all;
+use std.textio.all;
+use common_pkg_lib.common_pkg.all;
+use astron_ram_lib.common_ram_pkg.ALL;
+use common_pkg_lib.common_lfsr_sequences_pkg.ALL;
+use common_pkg_lib.tb_common_pkg.all;
+use astron_mm_lib.tb_common_mem_pkg.ALL;
+use dp_pkg_lib.dp_stream_pkg.all;
+use astron_filter_lib.fil_pkg.all;
+use astron_r2sdf_fft_lib.rTwoSDFPkg.all;
+use astron_wb_fft_lib.fft_pkg.all;
+use astron_wb_fft_lib.tb_fft_pkg.all;
+use work.wpfb_pkg.all;
+
+entity tb_wpfb_unit_wide is
+ generic(
+ -- DUT generics
+ g_wpfb : t_wpfb := (4, 32, 0, 1,
+ 16, 1, 8, 16, 16,
+ true, false, true, 16, 16, 1, c_dsp_mult_w, 2, true, 56, 2, 20,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+ -- type t_wpfb is record
+ -- -- General parameters for the wideband poly phase filter
+ -- wb_factor : natural; -- = default 4, wideband factor
+ -- nof_points : natural; -- = 1024, N point FFT (Also the number of subbands for the filter part)
+ -- nof_chan : natural; -- = default 0, defines the number of channels (=time-multiplexed input signals): nof channels = 2**nof_chan
+ -- nof_wb_streams : natural; -- = 1, the number of parallel wideband streams. The filter coefficients are shared on every wb-stream.
+ --
+ -- -- Parameters for the poly phase filter
+ -- nof_taps : natural; -- = 16, the number of FIR taps per subband
+ -- fil_backoff_w : natural; -- = 0, number of bits for input backoff to avoid output overflow
+ -- fil_in_dat_w : natural; -- = 8, number of input bits
+ -- fil_out_dat_w : natural; -- = 16, number of output bits
+ -- coef_dat_w : natural; -- = 16, data width of the FIR coefficients
+ --
+ -- -- Parameters for the FFT
+ -- use_reorder : boolean; -- = false for bit-reversed output, true for normal output
+ -- use_fft_shift : boolean; -- = false for [0, pos, neg] bin frequencies order, true for [neg, 0, pos] bin frequencies order in case of complex input
+ -- use_separate : boolean; -- = false for complex input, true for two real inputs
+ -- fft_in_dat_w : natural; -- = 16, number of input bits
+ -- fft_out_dat_w : natural; -- = 13, number of output bits
+ -- fft_out_gain_w : natural; -- = 0, output gain factor applied after the last stage output, before requantization to out_dat_w
+ -- stage_dat_w : natural; -- = 18, number of bits that are used inter-stage
+ -- guard_w : natural; -- = 2
+ -- guard_enable : boolean; -- = true
+ --
+ -- -- Parameters for the statistics
+ -- stat_data_w : positive; -- = 56
+ -- stat_data_sz : positive; -- = 2
+ -- nof_blk_per_sync : natural; -- = 800000, number of FFT output blocks per sync interval
+ --
+ -- -- Pipeline parameters for both poly phase filter and FFT. These are heritaged from the filter and fft libraries.
+ -- pft_pipeline : t_fft_pipeline; -- Pipeline settings for the pipelined FFT
+ -- fft_pipeline : t_fft_pipeline; -- Pipeline settings for the parallel FFT
+ -- fil_pipeline : t_fil_ppf_pipeline; -- Pipeline settings for the filter units
+ -- end record;
+
+ -- TB generics
+ g_diff_margin : integer := 5; -- maximum difference between HDL output and expected output (> 0 to allow minor rounding differences)
+ -- for complex diff margin = 3 appears sufficient
+ -- for two_real diff margin = 5 appears sufficient
+ -- if stage_dat_w >> 18 >= fft_out_dat_w then g_diff_margin = 1 is sufficient
+
+ -- PFIR coefficients
+ g_coefs_file_prefix_ab : string := "data/run_pfb_m_pfir_coeff_fircls1";
+ g_coefs_file_prefix_c : string := "data/run_pfb_complex_m_pfir_coeff_fircls1";
+
+ -- Two real input data files A and B used when g_fft.use_separate = true
+ -- * 1024 points = 512 subbands
+ --g_data_file_a : string := "data/run_pfb_m_sinusoid_chirp_8b_16taps_1024points_16b_16b.dat";
+ --g_data_file_a_nof_lines : natural := 204800;
+ --g_data_file_b : string := "UNUSED";
+ --g_data_file_b_nof_lines : natural := 0;
+
+ -- * 32 points = 16 subbands
+ --g_data_file_a : string := "data/run_pfb_m_sinusoid_chirp_8b_16taps_32points_16b_16b.dat";
+ --g_data_file_a_nof_lines : natural := 6400;
+ g_data_file_a : string := "data/run_pfb_m_sinusoid_8b_16taps_32points_16b_16b.dat";
+ g_data_file_a_nof_lines : natural := 1600;
+
+ --g_data_file_b : string := "data/run_pfb_m_impulse_chirp_8b_16taps_32points_16b_16b.dat";
+ --g_data_file_b_nof_lines : natural := 6400;
+ g_data_file_b : string := "UNUSED";
+ g_data_file_b_nof_lines : natural := 0;
+
+ -- One complex input data file C used when g_fft.use_separate = false
+ -- * 64 points = 64 channels
+ --g_data_file_c : string := "data/run_pfb_complex_m_phasor_chirp_8b_16taps_64points_16b_16b.dat";
+ --g_data_file_c_nof_lines : natural := 12800;
+ --g_data_file_c : string := "data/run_pfb_complex_m_phasor_8b_16taps_64points_16b_16b.dat";
+ --g_data_file_c_nof_lines : natural := 320;
+ --g_data_file_c : string := "data/run_pfb_complex_m_noise_8b_16taps_64points_16b_16b.dat";
+ --g_data_file_c_nof_lines : natural := 640;
+
+ -- * 32 points = 32 channels
+ --g_data_file_c : string := "data/run_pfb_complex_m_phasor_chirp_8b_16taps_32points_16b_16b.dat";
+ --g_data_file_c_nof_lines : natural := 6400;
+ --g_data_file_c : string := "data/run_pfb_complex_m_phasor_8b_16taps_32points_16b_16b.dat";
+ --g_data_file_c_nof_lines : natural := 1600;
+ g_data_file_c : string := "data/run_pfb_complex_m_noise_complex_8b_16taps_32points_16b_16b.dat";
+ g_data_file_c_nof_lines : natural := 1600;
+
+ g_data_file_nof_lines : natural := 1600; -- actual number of lines with input data to simulate from the data files, must be <= g_data_file_*_nof_lines
+ g_enable_in_val_gaps : boolean := FALSE -- when false then in_val flow control active continuously, else with random inactive gaps
+ );
+end entity tb_wpfb_unit_wide;
+
+architecture tb of tb_wpfb_unit_wide is
+
+ constant c_big_endian_wb_in : boolean := true;
+
+ constant c_clk_period : time := 10 ns;
+ constant c_sclk_period : time := c_clk_period / g_wpfb.wb_factor;
+
+ constant c_in_complex : boolean := not g_wpfb.use_separate;
+
+ constant c_nof_channels : natural := 2**g_wpfb.nof_chan;
+ constant c_nof_coefs : natural := g_wpfb.nof_taps * g_wpfb.nof_points; -- nof PFIR coef
+
+ constant c_nof_data_per_block : natural := g_wpfb.nof_points * c_nof_channels;
+ constant c_nof_valid_per_block : natural := c_nof_data_per_block / g_wpfb.wb_factor;
+
+ constant c_rnd_factor : natural := sel_a_b(g_enable_in_val_gaps, 3, 1);
+ constant c_dut_block_latency : natural := func_wpfb_maximum_sop_latency(g_wpfb); -- choose large enough for output to have become available
+ constant c_dut_clk_latency : natural := c_nof_valid_per_block * c_dut_block_latency * c_rnd_factor; -- worst case
+
+ -- PFIR coefficients file access
+ constant c_coefs_dat_file_prefix : string := sel_a_b(c_in_complex, g_coefs_file_prefix_c, g_coefs_file_prefix_ab) &
+ "_" & integer'image(g_wpfb.nof_taps) & "taps" &
+ "_" & integer'image(g_wpfb.nof_points) & "points" &
+ "_" & integer'image(g_wpfb.coef_dat_w) & "b";
+ constant c_coefs_mif_file_prefix : string := c_coefs_dat_file_prefix & "_" & integer'image(g_wpfb.wb_factor) & "wb";
+
+ -- input/output data width
+ constant c_in_dat_w : natural := g_wpfb.fil_in_dat_w;
+ constant c_fil_dat_w : natural := g_wpfb.fil_out_dat_w;
+ constant c_out_dat_w : natural := g_wpfb.fft_out_dat_w;
+
+ -- Data file access (Header + PFIR coefficients + WG data + PFIR data + PFFT data)
+ constant c_nof_lines_header : natural := 4;
+ constant c_nof_lines_pfir_coefs : natural := c_nof_coefs; -- PFIR coefficients
+ constant c_nof_lines_a_wg_dat : natural := g_data_file_a_nof_lines; -- Real input A via in_re, one value per line
+ constant c_nof_lines_a_pfir_dat : natural := g_data_file_a_nof_lines; -- Real pfir A, one value per line
+ constant c_nof_lines_a_pfft_dat : natural := g_data_file_a_nof_lines/c_nof_complex; -- Half spectrum, two values per line (re, im)
+ constant c_nof_lines_a_wg_header : natural := c_nof_lines_header + c_nof_lines_pfir_coefs;
+ constant c_nof_lines_a_pfir_header : natural := c_nof_lines_header + c_nof_lines_pfir_coefs + c_nof_lines_a_wg_dat;
+ constant c_nof_lines_a_pfft_header : natural := c_nof_lines_header + c_nof_lines_pfir_coefs + c_nof_lines_a_wg_dat + c_nof_lines_a_pfir_dat;
+ constant c_nof_lines_b_wg_dat : natural := g_data_file_b_nof_lines; -- Real input A via in_re, one value per line
+ constant c_nof_lines_b_pfir_dat : natural := g_data_file_b_nof_lines; -- Real pfir A, one value per line
+ constant c_nof_lines_b_pfft_dat : natural := g_data_file_b_nof_lines/c_nof_complex; -- Half spectrum, two values per line (re, im)
+ constant c_nof_lines_b_wg_header : natural := c_nof_lines_header + c_nof_lines_pfir_coefs;
+ constant c_nof_lines_b_pfir_header : natural := c_nof_lines_header + c_nof_lines_pfir_coefs + c_nof_lines_b_wg_dat;
+ constant c_nof_lines_b_pfft_header : natural := c_nof_lines_header + c_nof_lines_pfir_coefs + c_nof_lines_b_wg_dat + c_nof_lines_b_pfir_dat;
+ constant c_nof_lines_c_wg_dat : natural := g_data_file_c_nof_lines; -- Complex input, two values per line (re, im)
+ constant c_nof_lines_c_pfir_dat : natural := g_data_file_c_nof_lines; -- Complex pfir, two values per line (re, im)
+ constant c_nof_lines_c_pfft_dat : natural := g_data_file_c_nof_lines; -- Full spectrum, two values per line (re, im)
+ constant c_nof_lines_c_wg_header : natural := c_nof_lines_header + c_nof_lines_pfir_coefs;
+ constant c_nof_lines_c_pfir_header : natural := c_nof_lines_header + c_nof_lines_pfir_coefs + c_nof_lines_c_wg_dat;
+ constant c_nof_lines_c_pfft_header : natural := c_nof_lines_header + c_nof_lines_pfir_coefs + c_nof_lines_c_wg_dat + c_nof_lines_c_pfir_dat;
+
+ -- signal definitions
+ signal tb_end : std_logic := '0';
+ signal tb_end_almost : std_logic := '0';
+ signal clk : std_logic := '0';
+ signal sclk : std_logic := '0';
+ signal rst : std_logic := '0';
+ signal random : std_logic_vector(15 DOWNTO 0) := (OTHERS=>'0'); -- use different lengths to have different random sequences
+
+ signal coefs_dat_arr : t_integer_arr(c_nof_coefs-1 downto 0) := (OTHERS=>0); -- = PFIR coef for all taps as read from via c_coefs_dat_file_prefix
+ signal coefs_ref_c_arr : t_integer_arr(c_nof_coefs-1 downto 0) := (OTHERS=>0); -- = PFIR coef for all taps as read from via g_data_file_c
+ signal coefs_ref_a_arr : t_integer_arr(c_nof_coefs-1 downto 0) := (OTHERS=>0); -- = PFIR coef for all taps as read from via g_data_file_a
+ signal coefs_ref_b_arr : t_integer_arr(c_nof_coefs-1 downto 0) := (OTHERS=>0); -- = PFIR coef for all taps as read from via g_data_file_b
+
+ signal input_data_a_arr : t_integer_arr(0 to g_data_file_nof_lines-1) := (OTHERS=>0); -- one value per line (A via re input)
+ signal input_data_b_arr : t_integer_arr(0 to g_data_file_nof_lines-1) := (OTHERS=>0); -- one value per line (B via im input)
+ signal input_data_c_arr : t_integer_arr(0 to g_data_file_nof_lines*c_nof_complex-1) := (OTHERS=>0); -- two values per line (re, im)
+
+ signal exp_filter_data_a_arr : t_integer_arr(0 to g_data_file_nof_lines-1) := (OTHERS=>0); -- one value per line (A via re input)
+ signal exp_filter_data_b_arr : t_integer_arr(0 to g_data_file_nof_lines-1) := (OTHERS=>0); -- one value per line (B via im input)
+ signal exp_filter_data_c_arr : t_integer_arr(0 to g_data_file_nof_lines*c_nof_complex-1) := (OTHERS=>0); -- two values per line (re, im)
+ signal exp_filter_data_c_re_arr : t_integer_arr(0 to g_data_file_nof_lines-1) := (OTHERS=>0); -- one value per line (re input)
+ signal exp_filter_data_c_im_arr : t_integer_arr(0 to g_data_file_nof_lines-1) := (OTHERS=>0); -- one value per line (im input)
+
+ signal output_data_a_re_arr : t_integer_arr(0 to g_data_file_nof_lines/c_nof_complex-1) := (OTHERS=>0); -- half spectrum, re
+ signal output_data_a_im_arr : t_integer_arr(0 to g_data_file_nof_lines/c_nof_complex-1) := (OTHERS=>0); -- half spectrum, im
+ signal output_data_b_re_arr : t_integer_arr(0 to g_data_file_nof_lines/c_nof_complex-1) := (OTHERS=>0); -- half spectrum, re
+ signal output_data_b_im_arr : t_integer_arr(0 to g_data_file_nof_lines/c_nof_complex-1) := (OTHERS=>0); -- half spectrum, im
+ signal output_data_c_re_arr : t_integer_arr(0 to g_data_file_nof_lines-1) := (OTHERS=>0); -- full spectrum, re
+ signal output_data_c_im_arr : t_integer_arr(0 to g_data_file_nof_lines-1) := (OTHERS=>0); -- full spectrum, im
+
+ signal exp_output_data_a_arr : t_integer_arr(0 to g_data_file_nof_lines-1) := (OTHERS=>0); -- half spectrum, two values per line (re, im)
+ signal exp_output_data_a_re_arr : t_integer_arr(0 to g_data_file_nof_lines/c_nof_complex-1) := (OTHERS=>0); -- half spectrum, re
+ signal exp_output_data_a_im_arr : t_integer_arr(0 to g_data_file_nof_lines/c_nof_complex-1) := (OTHERS=>0); -- half spectrum, im
+ signal exp_output_data_b_arr : t_integer_arr(0 to g_data_file_nof_lines-1) := (OTHERS=>0); -- half spectrum, two values per line (re, im)
+ signal exp_output_data_b_re_arr : t_integer_arr(0 to g_data_file_nof_lines/c_nof_complex-1) := (OTHERS=>0); -- half spectrum, re
+ signal exp_output_data_b_im_arr : t_integer_arr(0 to g_data_file_nof_lines/c_nof_complex-1) := (OTHERS=>0); -- half spectrum, im
+ signal exp_output_data_c_arr : t_integer_arr(0 to g_data_file_nof_lines*c_nof_complex-1) := (OTHERS=>0); -- full spectrum, two values per line (re, im)
+ signal exp_output_data_c_re_arr : t_integer_arr(0 to g_data_file_nof_lines-1) := (OTHERS=>0); -- full spectrum, re
+ signal exp_output_data_c_im_arr : t_integer_arr(0 to g_data_file_nof_lines-1) := (OTHERS=>0); -- full spectrum, im
+
+ -- Input
+ signal in_re_arr : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal in_im_arr : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal in_re_data : std_logic_vector(g_wpfb.wb_factor*c_in_dat_w-1 DOWNTO 0); -- scope data only for stream 0
+ signal in_im_data : std_logic_vector(g_wpfb.wb_factor*c_in_dat_w-1 DOWNTO 0); -- scope data only for stream 0
+ signal in_val : std_logic:= '0';
+ signal in_val_cnt : natural := 0;
+ signal in_blk_val : std_logic;
+ signal in_blk_val_cnt : natural := 0;
+ signal in_gap : std_logic := '0';
+ signal in_sosi_arr : t_dp_sosi_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0) := (others=>c_dp_sosi_rst);
+ signal in_blk_time : integer := 0; -- input block time counter
+
+ signal in_sosi_val : t_dp_sosi;
+ signal ref_sosi_ctrl : t_dp_sosi;
+ signal ref_re_arr : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal ref_im_arr : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+
+ -- Input in sclk domain
+ signal in_re_scope : integer;
+ signal in_im_scope : integer;
+ signal in_val_scope : std_logic:= '0';
+
+ -- Filter output
+ signal fil_sosi_arr : t_dp_sosi_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal fil_re_arr : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal fil_im_arr : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal fil_re_data : std_logic_vector(g_wpfb.wb_factor*c_fil_dat_w-1 DOWNTO 0); -- scope data only for stream 0
+ signal fil_im_data : std_logic_vector(g_wpfb.wb_factor*c_fil_dat_w-1 DOWNTO 0); -- scope data only for stream 0
+ signal fil_val : std_logic:= '0'; -- for parallel output
+
+ -- Filter in sclk domain
+ signal fil_re_scope : integer;
+ signal fil_im_scope : integer;
+ signal fil_val_scope : std_logic:= '0';
+ signal exp_fil_re_scope : integer;
+ signal exp_fil_im_scope : integer;
+
+ -- Observe common sosi fields via sosi_arr(0)
+ signal in_sosi_0 : t_dp_sosi;
+ signal out_sosi_0 : t_dp_sosi;
+
+ -- Output
+ signal out_sosi_arr : t_dp_sosi_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0) := (others=>c_dp_sosi_rst);
+ signal out_re_arr : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal out_im_arr : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal out_re_data : std_logic_vector(g_wpfb.wb_factor*c_out_dat_w-1 DOWNTO 0); -- scope data only for stream 0
+ signal out_im_data : std_logic_vector(g_wpfb.wb_factor*c_out_dat_w-1 DOWNTO 0); -- scope data only for stream 0
+ signal out_val : std_logic:= '0'; -- for parallel output
+ signal out_val_cnt : natural := 0;
+ signal out_blk_time : integer := 0; -- output block time counter
+
+ -- Output in sclk domain
+ signal out_re_scope : integer := 0;
+ signal out_im_scope : integer := 0;
+ signal out_val_a : std_logic:= '0'; -- for real A
+ signal out_val_b : std_logic:= '0'; -- for real B
+ signal out_val_c : std_logic:= '0'; -- for complex(A,B)
+ signal out_channel : natural := 0;
+ signal out_cnt : natural := 0;
+ signal out_bin_cnt : natural := 0;
+ signal out_bin : natural;
+
+ -- Output data for complex input data
+ signal out_re_c_scope : integer := 0;
+ signal exp_re_c_scope : integer := 0;
+ signal out_im_c_scope : integer := 0;
+ signal exp_im_c_scope : integer := 0;
+ signal diff_re_c_scope : integer := 0;
+ signal diff_im_c_scope : integer := 0;
+
+ -- register control signals to account for sclk register in output scope signals
+ signal reg_out_val_a : std_logic;
+ signal reg_out_val_b : std_logic;
+ signal reg_out_val_c : std_logic;
+ signal reg_out_channel : natural := 0;
+ signal reg_out_cnt : natural := 0;
+ signal reg_out_bin_cnt : natural := 0;
+ signal reg_out_bin : natural;
+ signal reg_out_blk_time : integer := 0;
+
+ -- Output data two real input data A and B
+ signal out_re_a_scope : integer := 0;
+ signal exp_re_a_scope : integer := 0;
+ signal out_im_a_scope : integer := 0;
+ signal exp_im_a_scope : integer := 0;
+ signal out_re_b_scope : integer := 0;
+ signal exp_re_b_scope : integer := 0;
+ signal out_im_b_scope : integer := 0;
+ signal exp_im_b_scope : integer := 0;
+ signal diff_re_a_scope : integer := 0;
+ signal diff_im_a_scope : integer := 0;
+ signal diff_re_b_scope : integer := 0;
+ signal diff_im_b_scope : integer := 0;
+
+begin
+
+ sclk <= (not sclk) or tb_end after c_sclk_period/2;
+ clk <= (not clk) or tb_end after c_clk_period/2;
+ rst <= '1', '0' after c_clk_period*7;
+ random <= func_common_random(random) WHEN rising_edge(clk);
+ in_gap <= random(random'HIGH) WHEN g_enable_in_val_gaps=TRUE ELSE '0';
+
+ in_sosi_0 <= in_sosi_arr(0);
+ out_sosi_0 <= out_sosi_arr(0);
+
+ ---------------------------------------------------------------
+ -- DATA INPUT
+ ---------------------------------------------------------------
+ p_input_stimuli : process
+ variable vP : natural;
+ begin
+ -- read input data from file
+ if c_in_complex then
+ proc_common_read_integer_file(g_data_file_c, c_nof_lines_c_wg_header, g_data_file_nof_lines, c_nof_complex, input_data_c_arr);
+ else
+ proc_common_read_integer_file(g_data_file_a, c_nof_lines_a_wg_header, g_data_file_nof_lines, 1, input_data_a_arr);
+ proc_common_read_integer_file(g_data_file_b, c_nof_lines_b_wg_header, g_data_file_nof_lines, 1, input_data_b_arr);
+ end if;
+ wait for 1 ns;
+ in_re_arr <= (others=>(others=>'0'));
+ in_im_arr <= (others=>(others=>'0'));
+ in_val <= '0';
+ proc_common_wait_until_low(clk, rst); -- Wait until reset has finished
+ proc_common_wait_some_cycles(clk, 10); -- Wait an additional amount of cycles
+
+ -- apply stimuli
+ for I in 0 to g_data_file_nof_lines/g_wpfb.wb_factor-1 loop -- serial
+ for K in 0 to c_nof_channels-1 loop -- serial
+ for S in 0 to g_wpfb.nof_wb_streams-1 loop -- parallel
+ for P in 0 to g_wpfb.wb_factor-1 loop -- parallel
+ if c_big_endian_wb_in=TRUE then
+ vP := g_wpfb.wb_factor-1-P; -- time to big endian
+ else
+ vP := P; -- time in little endian
+ end if;
+ if K=1 or S=1 then
+ -- if present then serial channel 1 carries zero data to be able to recognize the serial channel order in the wave window
+ -- if present then parallel stream 1 carries zero data to be able to recognize the parallel stream order in the wave window
+ in_re_arr(S*g_wpfb.wb_factor + vP) <= (OTHERS=>'0');
+ in_im_arr(S*g_wpfb.wb_factor + vP) <= (OTHERS=>'0');
+ else
+ -- stream 0 and if present the other streams >= 2 carry the same input reference data to verify the filter function
+ if c_in_complex then
+ in_re_arr(S*g_wpfb.wb_factor + vP) <= TO_SVEC_32(input_data_c_arr((I*g_wpfb.wb_factor+P)*c_nof_complex));
+ in_im_arr(S*g_wpfb.wb_factor + vP) <= TO_SVEC_32(input_data_c_arr((I*g_wpfb.wb_factor+P)*c_nof_complex+1));
+ else
+ in_re_arr(S*g_wpfb.wb_factor + vP) <= TO_SVEC_32(input_data_a_arr(I*g_wpfb.wb_factor+P));
+ in_im_arr(S*g_wpfb.wb_factor + vP) <= TO_SVEC_32(input_data_b_arr(I*g_wpfb.wb_factor+P));
+ end if;
+ end if;
+ end loop;
+ end loop;
+ in_val <= '1'; -- serial
+ proc_common_wait_some_cycles(clk, 1);
+ if in_gap='1' then
+ in_val <= '0'; -- serial
+ proc_common_wait_some_cycles(clk, 1);
+ end if;
+ end loop;
+ end loop;
+
+ -- Wait until done
+ in_val <= '0';
+ proc_common_wait_some_cycles(clk, c_dut_clk_latency); -- wait for DUT latency
+ tb_end_almost <= '1';
+ proc_common_wait_some_cycles(clk, 100);
+ tb_end <= '1';
+ wait;
+ end process;
+
+ in_sosi_val.valid <= in_val;
+
+ u_ref_sosi_ctrl : entity dp_components_lib.dp_block_gen
+ generic map (
+ g_use_src_in => false, -- when true use src_in.ready else use snk_in.valid for flow control
+ g_nof_data => c_nof_valid_per_block, -- nof data per block
+ g_nof_blk_per_sync => g_wpfb.nof_blk_per_sync,
+ g_empty => 0,
+ g_channel => 0,
+ g_error => 0,
+ g_bsn => 12,
+ g_preserve_sync => false,
+ g_preserve_bsn => false
+ )
+ port map (
+ rst => rst,
+ clk => clk,
+ -- Streaming sink
+ snk_in => in_sosi_val,
+ -- Streaming source
+ src_in => c_dp_siso_rdy,
+ src_out => ref_sosi_ctrl,
+ -- MM control
+ en => '1'
+ );
+
+ ref_re_arr <= in_re_arr when rising_edge(clk);
+ ref_im_arr <= in_im_arr when rising_edge(clk);
+
+ ---------------------------------------------------------------
+ -- DUT = Device Under Test
+ ---------------------------------------------------------------
+ p_in_sosi_arr : process(ref_re_arr, ref_im_arr, ref_sosi_ctrl)
+ begin
+ for I in 0 to g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 loop
+ -- DUT input
+ in_sosi_arr(I) <= ref_sosi_ctrl;
+ in_sosi_arr(I).re <= RESIZE_DP_DSP_DATA(ref_re_arr(I));
+ in_sosi_arr(I).im <= RESIZE_DP_DSP_DATA(ref_im_arr(I));
+ end loop;
+ end process;
+
+ u_dut : entity work.wpfb_unit_dev
+ generic map (
+ g_big_endian_wb_in => c_big_endian_wb_in,
+ g_wpfb => g_wpfb,
+ g_use_prefilter => TRUE,
+ g_stats_ena => TRUE,
+ g_use_bg => FALSE,
+ g_coefs_file_prefix => c_coefs_mif_file_prefix
+ )
+ port map (
+ dp_rst => rst,
+ dp_clk => clk,
+ mm_rst => rst,
+ mm_clk => clk,
+ ram_fil_coefs_mosi => c_mem_mosi_rst,
+ ram_fil_coefs_miso => open,
+ ram_st_sst_mosi => c_mem_mosi_rst,
+ ram_st_sst_miso => open,
+ reg_bg_ctrl_mosi => c_mem_mosi_rst,
+ reg_bg_ctrl_miso => open,
+ ram_bg_data_mosi => c_mem_mosi_rst,
+ ram_bg_data_miso => open,
+ in_sosi_arr => in_sosi_arr,
+ fil_sosi_arr => fil_sosi_arr,
+ out_sosi_arr => out_sosi_arr
+ );
+
+ p_fil_sosi_arr : process(fil_sosi_arr)
+ begin
+ for I in 0 to g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 loop
+ fil_re_arr(I) <= RESIZE_SVEC_32(fil_sosi_arr(I).re);
+ fil_im_arr(I) <= RESIZE_SVEC_32(fil_sosi_arr(I).im);
+ end loop;
+ end process;
+ fil_val <= fil_sosi_arr(0).valid;
+
+ p_out_sosi_arr : process(out_sosi_arr)
+ begin
+ for I in 0 to g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 loop
+ out_re_arr(I) <= RESIZE_SVEC_32(out_sosi_arr(I).re);
+ out_im_arr(I) <= resize_fft_svec(out_sosi_arr(I).im);
+ end loop;
+ end process;
+ out_val <= out_sosi_arr(0).valid;
+
+ -- Data valid count
+ in_val_cnt <= in_val_cnt+1 when rising_edge(clk) and in_val='1' else in_val_cnt;
+ out_val_cnt <= out_val_cnt+1 when rising_edge(clk) and out_val='1' else out_val_cnt;
+
+ -- Block count blocks for c_nof_channels>=1 channels per block
+ in_blk_val <= '1' when in_val='1' and (in_val_cnt mod c_nof_channels)=0 else '0';
+ in_blk_val_cnt <= in_val_cnt/c_nof_channels;
+
+ -- Block count time axis
+ in_blk_time <= in_blk_val_cnt / (g_wpfb.nof_points/g_wpfb.wb_factor);
+
+ -- Verify nof valid counts
+ p_verify_out_val_cnt : process
+ begin
+ -- Wait until tb_end_almost
+ proc_common_wait_until_high(clk, tb_end_almost);
+ assert in_val_cnt > 0 report "Test did not run, no valid input data" severity error;
+ -- The WPFB has a memory of 2 block, independent of use_reorder and use_separate, but without the
+ -- reorder buffer it outputs 1 sample more, because that is immediately available in a new block.
+ -- Ensure g_data_file_nof_lines is multiple of g_wpfb.nof_points.
+ if g_wpfb.use_reorder=true then
+ assert out_val_cnt = in_val_cnt-2*c_nof_valid_per_block report "Unexpected number of valid output data" severity error;
+ else
+ assert out_val_cnt = in_val_cnt-2*c_nof_valid_per_block+c_nof_channels report "Unexpected number of valid output data" severity error;
+ end if;
+ wait;
+ end process;
+
+ ---------------------------------------------------------------
+ -- DATA OUTPUT CONTROL IN SCLK DOMAIN
+ ---------------------------------------------------------------
+ out_cnt <= out_cnt + 1 when rising_edge(sclk) and out_val_c='1' else out_cnt;
+
+ out_blk_time <= (out_cnt / c_nof_channels) / g_wpfb.nof_points;
+
+ proc_fft_out_control(g_wpfb.wb_factor, g_wpfb.nof_points, c_nof_channels, g_wpfb.use_reorder, g_wpfb.use_fft_shift, g_wpfb.use_separate,
+ out_cnt, out_val_c, out_val_a, out_val_b, out_channel, out_bin, out_bin_cnt);
+
+ -- clk diff to avoid combinatorial glitches when selecting the data with out_val_a,b,c
+ reg_out_val_a <= out_val_a when rising_edge(sclk);
+ reg_out_val_b <= out_val_b when rising_edge(sclk);
+ reg_out_val_c <= out_val_c when rising_edge(sclk);
+ reg_out_channel <= out_channel when rising_edge(sclk);
+ reg_out_cnt <= out_cnt when rising_edge(sclk);
+ reg_out_bin_cnt <= out_bin_cnt when rising_edge(sclk);
+ reg_out_bin <= out_bin when rising_edge(sclk);
+ reg_out_blk_time <= out_blk_time when rising_edge(sclk);
+
+ out_re_a_scope <= out_re_scope when rising_edge(sclk) and out_val_a='1';
+ out_im_a_scope <= out_im_scope when rising_edge(sclk) and out_val_a='1';
+ out_re_b_scope <= out_re_scope when rising_edge(sclk) and out_val_b='1';
+ out_im_b_scope <= out_im_scope when rising_edge(sclk) and out_val_b='1';
+ out_re_c_scope <= out_re_scope when rising_edge(sclk) and out_val_c='1';
+ out_im_c_scope <= out_im_scope when rising_edge(sclk) and out_val_c='1';
+
+ exp_re_a_scope <= exp_output_data_a_re_arr(out_bin_cnt) when rising_edge(sclk) and out_val_a='1';
+ exp_im_a_scope <= exp_output_data_a_im_arr(out_bin_cnt) when rising_edge(sclk) and out_val_a='1';
+ exp_re_b_scope <= exp_output_data_b_re_arr(out_bin_cnt) when rising_edge(sclk) and out_val_b='1';
+ exp_im_b_scope <= exp_output_data_b_im_arr(out_bin_cnt) when rising_edge(sclk) and out_val_b='1';
+ exp_re_c_scope <= exp_output_data_c_re_arr(out_bin_cnt) when rising_edge(sclk) and out_val_c='1';
+ exp_im_c_scope <= exp_output_data_c_im_arr(out_bin_cnt) when rising_edge(sclk) and out_val_c='1';
+
+ diff_re_a_scope <= exp_re_a_scope - out_re_a_scope;
+ diff_im_a_scope <= exp_im_a_scope - out_im_a_scope;
+ diff_re_b_scope <= exp_re_b_scope - out_re_b_scope;
+ diff_im_b_scope <= exp_im_b_scope - out_im_b_scope;
+ diff_re_c_scope <= exp_re_c_scope - out_re_c_scope;
+ diff_im_c_scope <= exp_im_c_scope - out_im_c_scope;
+
+ ---------------------------------------------------------------
+ -- VERIFY OUTPUT DATA
+ ---------------------------------------------------------------
+ p_verify_output : process(sclk)
+ begin
+ -- verify at sclk rising edge to avoid void differences due to delta-cycle differences that can occur between combinatorial signals
+ if rising_edge(sclk) then
+ if not c_in_complex then
+ if reg_out_channel=1 then
+ --if reg_out_val_a='1' then
+ assert out_re_a_scope = 0 report "Output data A real error in channel" severity error;
+ assert out_im_a_scope = 0 report "Output data A imag error in channel" severity error;
+ --end if;
+ if reg_out_val_b='1' then
+ assert out_re_b_scope = 0 report "Output data B real error in channel" severity error;
+ assert out_im_b_scope = 0 report "Output data B imag error in channel" severity error;
+ end if;
+ else
+ --if reg_out_val_a='1' then
+ assert diff_re_a_scope >= -g_diff_margin and diff_re_a_scope <= g_diff_margin report "Output data A real error" severity error;
+ assert diff_im_a_scope >= -g_diff_margin and diff_im_a_scope <= g_diff_margin report "Output data A imag error" severity error;
+ --end if;
+ if reg_out_val_b='1' then
+ assert diff_re_b_scope >= -g_diff_margin and diff_re_b_scope <= g_diff_margin report "Output data B real error" severity error;
+ assert diff_im_b_scope >= -g_diff_margin and diff_im_b_scope <= g_diff_margin report "Output data B imag error" severity error;
+ end if;
+ end if;
+ else
+ if reg_out_val_c='1' then
+ if reg_out_channel=1 then
+ assert out_re_c_scope = 0 report "Output data C real error in channel" severity error;
+ assert out_im_c_scope = 0 report "Output data C imag error in channel" severity error;
+ else
+ assert diff_re_c_scope >= -g_diff_margin and diff_re_c_scope <= g_diff_margin report "Output data C real error" severity error;
+ assert diff_im_c_scope >= -g_diff_margin and diff_im_c_scope <= g_diff_margin report "Output data C imag error" severity error;
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+ ---------------------------------------------------------------
+ -- READ EXPECTED FILTER OUTPUT DATA FROM FILE
+ ---------------------------------------------------------------
+ p_exp_filter_data : process
+ begin
+ -- read filter data from file
+ if c_in_complex then
+ proc_common_read_integer_file(g_data_file_c, c_nof_lines_c_pfir_header, g_data_file_nof_lines, c_nof_complex, exp_filter_data_c_arr);
+ wait for 1 ns;
+ for I in 0 to g_data_file_nof_lines-1 loop
+ exp_filter_data_c_re_arr(I) <= exp_filter_data_c_arr(2*I);
+ exp_filter_data_c_im_arr(I) <= exp_filter_data_c_arr(2*I+1);
+ end loop;
+ else
+ proc_common_read_integer_file(g_data_file_a, c_nof_lines_a_pfir_header, g_data_file_nof_lines, 1, exp_filter_data_a_arr);
+ proc_common_read_integer_file(g_data_file_b, c_nof_lines_b_pfir_header, g_data_file_nof_lines, 1, exp_filter_data_b_arr);
+ wait for 1 ns;
+ end if;
+ wait;
+ end process;
+
+ ---------------------------------------------------------------
+ -- READ EXPECTED WPFB OUTPUT DATA FROM FILE
+ ---------------------------------------------------------------
+ p_expected_wpfb_output : process
+ begin
+ if c_in_complex then
+ proc_common_read_integer_file(g_data_file_c, c_nof_lines_c_pfft_header, g_data_file_nof_lines, c_nof_complex, exp_output_data_c_arr);
+ wait for 1 ns;
+ for I in 0 to g_data_file_nof_lines-1 loop
+ exp_output_data_c_re_arr(I) <= exp_output_data_c_arr(2*I);
+ exp_output_data_c_im_arr(I) <= exp_output_data_c_arr(2*I+1);
+ end loop;
+ else
+ proc_common_read_integer_file(g_data_file_a, c_nof_lines_a_pfft_header, g_data_file_nof_lines/c_nof_complex, c_nof_complex, exp_output_data_a_arr);
+ proc_common_read_integer_file(g_data_file_b, c_nof_lines_b_pfft_header, g_data_file_nof_lines/c_nof_complex, c_nof_complex, exp_output_data_b_arr);
+ wait for 1 ns;
+ for I in 0 to g_data_file_nof_lines/c_nof_complex-1 loop
+ exp_output_data_a_re_arr(I) <= exp_output_data_a_arr(2*I);
+ exp_output_data_a_im_arr(I) <= exp_output_data_a_arr(2*I+1);
+ exp_output_data_b_re_arr(I) <= exp_output_data_b_arr(2*I);
+ exp_output_data_b_im_arr(I) <= exp_output_data_b_arr(2*I+1);
+ end loop;
+ end if;
+ wait;
+ end process;
+
+ ---------------------------------------------------------------
+ -- INPUT AND OUTPUT DATA SCOPES : ONLY FOR WB STREAM S = 0
+ ---------------------------------------------------------------
+ rewire_scope_data : for P in 0 to g_wpfb.wb_factor-1 generate
+ in_re_data((P+1)*c_in_dat_w-1 downto P*c_in_dat_w) <= in_re_arr(P)(c_in_dat_w-1 downto 0);
+ in_im_data((P+1)*c_in_dat_w-1 downto P*c_in_dat_w) <= in_im_arr(P)(c_in_dat_w-1 downto 0);
+
+ fil_re_data((P+1)*c_fil_dat_w-1 downto P*c_fil_dat_w) <= fil_re_arr(P)(c_fil_dat_w-1 downto 0);
+ fil_im_data((P+1)*c_fil_dat_w-1 downto P*c_fil_dat_w) <= fil_im_arr(P)(c_fil_dat_w-1 downto 0);
+
+ out_re_data((P+1)*c_out_dat_w-1 downto P*c_out_dat_w) <= out_re_arr(P)(c_out_dat_w-1 downto 0);
+ out_im_data((P+1)*c_out_dat_w-1 downto P*c_out_dat_w) <= out_im_arr(P)(c_out_dat_w-1 downto 0);
+ end generate;
+
+ u_in_re_scope : entity astron_sim_tools_lib.common_wideband_data_scope
+ generic map (
+ g_sim => TRUE,
+ g_wideband_factor => g_wpfb.wb_factor, -- Wideband rate factor = 4 for dp_clk processing frequency is 200 MHz frequency and SCLK sample frequency Fs is 800 MHz
+ g_wideband_big_endian => TRUE, -- When true in_data[3:0] = sample[t0,t1,t2,t3], else when false : in_data[3:0] = sample[t3,t2,t1,t0]
+ g_dat_w => c_in_dat_w -- Actual width of the data samples
+ )
+ port map (
+ -- Sample clock
+ SCLK => sclk, -- sample clk, use only for simulation purposes
+
+ -- Streaming input data
+ in_data => in_re_data,
+ in_val => in_val,
+
+ -- Scope output samples
+ out_dat => OPEN,
+ out_int => in_re_scope,
+ out_val => in_val_scope
+ );
+
+ u_in_im_scope : entity astron_sim_tools_lib.common_wideband_data_scope
+ generic map (
+ g_sim => TRUE,
+ g_wideband_factor => g_wpfb.wb_factor, -- Wideband rate factor = 4 for dp_clk processing frequency is 200 MHz frequency and SCLK sample frequency Fs is 800 MHz
+ g_wideband_big_endian => TRUE, -- When true in_data[3:0] = sample[t0,t1,t2,t3], else when false : in_data[3:0] = sample[t3,t2,t1,t0]
+ g_dat_w => c_in_dat_w -- Actual width of the data samples
+ )
+ port map (
+ -- Sample clock
+ SCLK => sclk, -- sample clk, use only for simulation purposes
+
+ -- Streaming input data
+ in_data => in_im_data,
+ in_val => in_val,
+
+ -- Scope output samples
+ out_dat => OPEN,
+ out_int => in_im_scope,
+ out_val => open
+ );
+
+ u_fil_re_scope : entity astron_sim_tools_lib.common_wideband_data_scope
+ generic map (
+ g_sim => TRUE,
+ g_wideband_factor => g_wpfb.wb_factor, -- Wideband rate factor = 4 for dp_clk processing frequency is 200 MHz frequency and SCLK sample frequency Fs is 800 MHz
+ g_wideband_big_endian => TRUE, -- When true in_data[3:0] = sample[t0,t1,t2,t3], else when false : in_data[3:0] = sample[t3,t2,t1,t0]
+ g_dat_w => c_fil_dat_w -- Actual width of the data samples
+ )
+ port map (
+ -- Sample clock
+ SCLK => sclk, -- sample clk, use only for simulation purposes
+
+ -- Streaming input data
+ in_data => fil_re_data,
+ in_val => fil_val,
+
+ -- Scope output samples
+ out_dat => OPEN,
+ out_int => fil_re_scope,
+ out_val => fil_val_scope
+ );
+
+ u_fil_im_scope : entity astron_sim_tools_lib.common_wideband_data_scope
+ generic map (
+ g_sim => TRUE,
+ g_wideband_factor => g_wpfb.wb_factor, -- Wideband rate factor = 4 for dp_clk processing frequency is 200 MHz frequency and SCLK sample frequency Fs is 800 MHz
+ g_wideband_big_endian => TRUE, -- When true in_data[3:0] = sample[t0,t1,t2,t3], else when false : in_data[3:0] = sample[t3,t2,t1,t0]
+ g_dat_w => c_fil_dat_w -- Actual width of the data samples
+ )
+ port map (
+ -- Sample clock
+ SCLK => sclk, -- sample clk, use only for simulation purposes
+
+ -- Streaming input data
+ in_data => fil_im_data,
+ in_val => fil_val,
+
+ -- Scope output samples
+ out_dat => OPEN,
+ out_int => fil_im_scope,
+ out_val => open
+ );
+
+ u_out_re_scope : entity astron_sim_tools_lib.common_wideband_data_scope
+ generic map (
+ g_sim => TRUE,
+ g_wideband_factor => g_wpfb.wb_factor, -- Wideband rate factor = 4 for dp_clk processing frequency is 200 MHz frequency and SCLK sample frequency Fs is 800 MHz
+ g_wideband_big_endian => FALSE, -- When true in_data[3:0] = sample[t0,t1,t2,t3], else when false : in_data[3:0] = sample[t3,t2,t1,t0]
+ g_dat_w => c_out_dat_w -- Actual width of the data samples
+ )
+ port map (
+ -- Sample clock
+ SCLK => sclk, -- sample clk, use only for simulation purposes
+
+ -- Streaming input data
+ in_data => out_re_data,
+ in_val => out_val,
+
+ -- Scope output samples
+ out_dat => OPEN,
+ out_int => out_re_scope,
+ out_val => out_val_c
+ );
+
+ u_out_im_scope : entity astron_sim_tools_lib.common_wideband_data_scope
+ generic map (
+ g_sim => TRUE,
+ g_wideband_factor => g_wpfb.wb_factor, -- Wideband rate factor = 4 for dp_clk processing frequency is 200 MHz frequency and SCLK sample frequency Fs is 800 MHz
+ g_wideband_big_endian => FALSE, -- When true in_data[3:0] = sample[t0,t1,t2,t3], else when false : in_data[3:0] = sample[t3,t2,t1,t0]
+ g_dat_w => c_out_dat_w -- Actual width of the data samples
+ )
+ port map (
+ -- Sample clock
+ SCLK => sclk, -- sample clk, use only for simulation purposes
+
+ -- Streaming input data
+ in_data => out_im_data,
+ in_val => out_val,
+
+ -- Scope output samples
+ out_dat => OPEN,
+ out_int => out_im_scope,
+ out_val => open
+ );
+
+end tb;
Index: trunk/wpfb_pkg.vhd
===================================================================
--- trunk/wpfb_pkg.vhd (nonexistent)
+++ trunk/wpfb_pkg.vhd (revision 2)
@@ -0,0 +1,221 @@
+-------------------------------------------------------------------------------
+-- Author: Harm Jan Pepping : pepping at astron.nl: 2012
+-- Copyright (C) 2012
+-- ASTRON (Netherlands Institute for Radio Astronomy)
+-- 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 .
+--
+-------------------------------------------------------------------------------
+
+library ieee, common_pkg_lib, astron_r2sdf_fft_lib, astron_wb_fft_lib, astron_filter_lib;
+use IEEE.std_logic_1164.all;
+use common_pkg_lib.common_pkg.all;
+use astron_r2sdf_fft_lib.rTwoSDFPkg.all;
+use astron_wb_fft_lib.fft_pkg.all;
+use astron_filter_lib.fil_pkg.all;
+
+package wpfb_pkg is
+
+ -- Parameters for the (wideband) poly phase filter.
+ type t_wpfb is record
+ -- General parameters for the wideband poly phase filter
+ wb_factor : natural; -- = default 4, wideband factor
+ nof_points : natural; -- = 1024, N point FFT (Also the number of subbands for the filter part)
+ nof_chan : natural; -- = default 0, defines the number of channels (=time-multiplexed input signals): nof channels = 2**nof_chan
+ nof_wb_streams : natural; -- = 1, the number of parallel wideband streams. The filter coefficients are shared on every wb-stream.
+
+ -- Parameters for the poly phase filter
+ nof_taps : natural; -- = 16, the number of FIR taps per subband
+ fil_backoff_w : natural; -- = 0, number of bits for input backoff to avoid output overflow
+ fil_in_dat_w : natural; -- = 8, number of input bits
+ fil_out_dat_w : natural; -- = 16, number of output bits
+ coef_dat_w : natural; -- = 16, data width of the FIR coefficients
+
+ -- Parameters for the FFT
+ use_reorder : boolean; -- = false for bit-reversed output, true for normal output
+ use_fft_shift : boolean; -- = false for [0, pos, neg] bin frequencies order, true for [neg, 0, pos] bin frequencies order in case of complex input
+ use_separate : boolean; -- = false for complex input, true for two real inputs
+ fft_in_dat_w : natural; -- = 16, number of input bits
+ fft_out_dat_w : natural; -- = 16, number of output bits >= (fil_in_dat_w=8) + log2(nof_points=1024)/2 = 13
+ fft_out_gain_w : natural; -- = 0, output gain factor applied after the last stage output, before requantization to out_dat_w
+ stage_dat_w : natural; -- = 18, number of bits that are used inter-stage
+ guard_w : natural; -- = 2, guard used to avoid overflow in first FFT stage, compensated in last guard_w nof FFT stages.
+ -- on average the gain per stage is 2 so guard_w = 1, but the gain can be 1+sqrt(2) [Lyons section
+ -- 12.3.2], therefore use input guard_w = 2.
+ guard_enable : boolean; -- = true when input needs guarding, false when input requires no guarding but scaling must be
+ -- skipped at the last stage(s) compensate for input guard (used in wb fft with pipe fft section
+ -- doing the input guard and par fft section doing the output compensation)
+
+ -- Parameters for the statistics
+ stat_data_w : positive; -- = 56
+ stat_data_sz : positive; -- = 2
+ nof_blk_per_sync : natural; -- = 800000, number of FFT output blocks per sync interval, used to pass on BSN
+
+ -- Pipeline parameters for both poly phase filter and FFT. These are heritaged from the filter and fft libraries.
+ pft_pipeline : t_fft_pipeline; -- Pipeline settings for the pipelined FFT
+ fft_pipeline : t_fft_pipeline; -- Pipeline settings for the parallel FFT
+ fil_pipeline : t_fil_ppf_pipeline; -- Pipeline settings for the filter units
+
+ end record;
+
+ -----------------------------------------------------------------------------
+ -- Apertif application specfic settings
+ -----------------------------------------------------------------------------
+
+ -- For reference Fsub, actual setting is done in the apertif_unb1_bn_filterbank design:
+ -- * wb_factor = 4 : wideband factor
+ -- nof_points = 1024 : N point FFT
+ -- nof_chan = 0 : nof channels = 2**nof_chan = 1
+ -- nof_wb_streams = 1 : 1 two real wb stream per WPFB, because the subband filterbank uses 2 independent instances of WPFB
+ -- * nof_taps = 16 : number of FIR taps in the subband filterbank
+ -- fil_backoff_w = 1 : backoff input to fit temporary PFIR output overshoot that can occur even though DC gain is 1
+ -- fil_in_dat_w = 8 : ADC data width
+ -- fil_out_dat_w = 16 : = fft_in_dat_w
+ -- coef_dat_w = 16 : width of the subband FIR coefficients
+ -- * use_reorder = true : must be true for two real input FFT
+ -- use_fft_shift = false : must be false for two real input FFT
+ -- use_separate = true : must be true for two real input FFT
+ -- fft_in_dat_w = 16 : = c_dsp_mult_w-guard_w = 18-2
+ -- fft_out_dat_w = 16 : subband data width in the transpose transport and at the BF input
+ -- fft_out_gain_w = 1 : compensate for divide by 2 in separate function for two real input FFT
+ -- stage_dat_w = 18 : = c_dsp_mult_w, number of bits that are used inter-stage
+ -- guard_w = 2 : must be 2 to avoid overflow in first FFT stage
+ -- guard_enable = true : must be true to enable input guard_w
+ -- * stat_data_w = 56 : could be 52 = 2*16+1 - 1 + ceil_log2(781250)
+ -- . 2*fft_out_dat_w for product
+ -- . +1 for complex product
+ -- . -1 to skip double sign
+ -- . +ceil_log2(Nint) for accumlation bit growth
+ -- stat_data_sz = 2 : must be 2 to fit stat_data_w in two 32 bit words
+ -- nof_blk_per_sync = 800000 : number of FFT output blocks per sync interval
+
+ -- Fsub settings:
+ -- . fil_backoff_w = 1 instead of 0 to avoid the overflow that occurs for WG with --ampl >= 119 and e.g. --sub 65, --chan 4,
+ -- see svn -r 18800 log of node_apertif_unb1_bn_filterbank
+ -- . fft_out_dat_w = 16 by internal dp_requantize will not overflow, so no need to use external dp_requantize with clipping
+ -- . fft_out_gain_w = 1 instead of 0 to compensate for 1/2 in separate.
+ constant c_wpfb_apertif_subbands : t_wpfb := (4, 1024, 0, 1,
+ 16, 1, 8, 16, 16,
+ true, false, true, 16, 16, 1, c_dsp_mult_w, 2, true, 56, 2, 800000,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+
+ -- For reference Fchan_x, actual setting is done in the apertif_unb1_correlator design:
+ -- * wb_factor = 1 : wideband factor
+ -- nof_points = 64 : N point FFT
+ -- nof_chan = 1 : nof channels = 2**nof_chan = 2 multiplex streams
+ -- nof_wb_streams = 12 : 12 complex streams per WPFB, that all share the FIR coefficients
+ -- * nof_taps = 8 : number of FIR taps in the channel filterbank
+ -- fil_backoff_w = 0 : backoff input to fit temporary PFIR output overshoot can occur even though DC gain is 1
+ -- fil_in_dat_w = 8 : keep at 8, also when Apertif BF outputs 6 bit beamlet data, because that is sign extended to 8b
+ -- fil_out_dat_w = 16 : = fft_in_dat_w
+ -- coef_dat_w = 9 : width of the channel FIR coefficients
+ -- * use_reorder = false : use true to have [0, pos, neg] frequency bin order for complex input FFT
+ -- use_fft_shift = false : use false to keep [0, pos, neg] frequency bin order
+ -- use_separate = false : must be false for complex input FFT
+ -- fft_in_dat_w = 16 : = c_dsp_mult_w-guard_w = 18-2
+ -- fft_out_dat_w = 9 : to fit correlator input width
+ -- fft_out_gain_w = 0 : keep at 0 for complex input input FFT
+ -- stage_dat_w = 18 : = c_dsp_mult_w, number of bits that are used inter-stage
+ -- guard_w = 2 : must be 2 to avoid overflow in first FFT stage
+ -- guard_enable = true : must be true to enable input guard_w
+ -- * stat_data_w = 56 : could be 32 = 2*9+1 - 1 + ceil_log2(781250/64):
+ -- . 2*fft_out_dat_w for product
+ -- . +1 for complex product
+ -- . -1 to skip double sign
+ -- . +ceil_log2(Nint) for accumlation bit growth
+ -- stat_data_sz = 2 : keep two 32b-word, even if stat_data_w could fit in one 32b-word
+ -- nof_blk_per_sync = 12500 : = 800000/64, number of FFT output blocks per sync interval
+
+ -- Fchan_x settings in node_apertif_unb1_correlator_processing.vhd:
+ -- . fil_backoff_w = 0, because for the Fchan there appears no PFIR output overshoot in practise using WG data
+ -- . use_reorder = false and use_fft_shift = false, because channel index bit flip and FFT shift are done in
+ -- apertif_unb1_correlator_vis_offload
+ -- . fft_out_dat_w = 18, because in there is a separate dp_requantize to get from 18b --> 9b in
+ -- node_apertif_unb1_correlator_processing, this dp_requantize uses symmertical clipping.
+ CONSTANT c_wpfb_apertif_channels : t_wpfb := (1, 64, 1, 12,
+ 8, 0, 8, 16, 9,
+ false, false, false, 16, 18, 0, c_dsp_mult_w, 2, true, 56, 2, 12500,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+
+ -- Fchan_sc3 settings:
+ -- . Arts SC3 uses the Fchan fine channels from Apertif X. Therefore to allow commensal Arts SC3 the Apertif X
+ -- will have to use use_reorder = true and use_fft_shift = true.
+ -- . Arts SC4 at half Stokes rate, so with nof_blk_per_sync = 12500 and nof_points = 64, has same rate as
+ -- Arts SC3. At full rate Arts SC4 would have nof_blk_per_sync = 25000 and nof_points = 32.
+ -- . fft_out_dat_w = 9, because Arts SC3 uses the fine channels from Apertif X.
+ constant c_wpfb_arts_channels_sc3 : t_wpfb := (1, 64, 1, 12,
+ 8, 0, 8, 16, 9,
+ true, true, false, 16, 9, 0, c_dsp_mult_w, 2, true, 56, 2, 12500,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+
+ -- Fchan_sc4 settings in arts_unb1_sc4_processing.vhd svn -r 19337:
+ -- . fft_out_dat_w = 9 for Arts SC3, but can be 12 to preserve more LSbit for SC4. However this is not necessary,
+ -- because the 9b are already sufficient to maintain sensitivity
+ -- . fft_out_gain_w = 2 to fit 2 more LSbits which is possible because fft_out_dat_w = 12. However if
+ -- fft_out_dat_w = 9, then fft_out_gain_w must be 0 to avoid output overflow. Instead the factor 2**2
+ -- then needs to be accommodated at the input of the subsequent IQUV, IAB or TAB processing.
+ -- . Using fft_out_dat_w = 12 instead of 9 and fft_out_gain_w = 2 instead of 0 created 12 - 9 - 2 = 1 bit more
+ -- dynamic range. Therefore it may not be necessary to use fine channel symmetrical clipping using an external
+ -- dp_requantize, like in Apertif X.
+ CONSTANT c_wpfb_arts_channels_sc4 : t_wpfb := (1, 64, 1, 12,
+ 8, 0, 8, 16, 9,
+ true, true, false, 16, 12, 2, c_dsp_mult_w, 2, true, 56, 2, 12500,
+ c_fft_pipeline, c_fft_pipeline, c_fil_ppf_pipeline);
+
+ -- Conclusion:
+ -- . To support fine channel offload to Arts SC3 the Apertif X settings will have to use use_reorder = true
+ -- and use_fft_shift = true
+ -- . It seems fine to keep the Arts SC4 settings fft_out_dat_w = 12 and fft_out_gain_w = 2 and no fine channel
+ -- clipping.
+ -- . Arts SC3 will use the same settings as Apertif X so fft_out_dat_w = 9 and fft_out_gain_w = 0 and fine
+ -- channel clipping. The input of the subsequent IQUV, IAB or TAB processing in arts_unb2b_sc3 may need to
+ -- be shifted by fft_out_gain_w compared to how it is connected in Arts SC4.
+
+ -- Estimate maximum number of blocks of latency between WPFB input and output
+ function func_wpfb_maximum_sop_latency(wpfb : t_wpfb) return natural;
+ function func_wpfb_set_nof_block_per_sync(wpfb : t_wpfb; nof_block_per_sync : NATURAL) return t_wpfb;
+
+end package wpfb_pkg;
+
+package body wpfb_pkg is
+
+ function func_wpfb_maximum_sop_latency(wpfb : t_wpfb) return natural is
+ constant c_nof_channels : natural := 2**wpfb.nof_chan;
+ constant c_block_size : natural := c_nof_channels * wpfb.nof_points / wpfb.wb_factor;
+ constant c_block_dly : natural := 10;
+ begin
+ -- The prefilter, pipelined FFT, pipelined reorder and the wideband separate reorder
+ -- cause block latency.
+ -- The parallel FFT has no block latency.
+ -- The parallel FFT reorder is merely a rewiring and causes no latency.
+ -- ==> This yields maximim 4 block latency
+ -- ==> Add one extra block latency to round up
+ -- Each block in the Wideband FFT also introduces about c_block_dly clock cycles of
+ -- pipeline latency.
+ -- ==> This yields maximum ( 5 * c_block_dly ) / c_block_size of block latency
+ return 4 + 1 + (5 * c_block_dly) / c_block_size;
+ end func_wpfb_maximum_sop_latency;
+
+ -- Overwrite nof_block_per_sync field in wpfb (typically for faster simulation)
+ function func_wpfb_set_nof_block_per_sync(wpfb : t_wpfb; nof_block_per_sync : NATURAL) return t_wpfb is
+ variable v_wpfb : t_wpfb;
+ begin
+ v_wpfb := wpfb;
+ v_wpfb.nof_blk_per_sync := nof_block_per_sync;
+ return v_wpfb;
+ end func_wpfb_set_nof_block_per_sync;
+
+end wpfb_pkg;
+
Index: trunk/wpfb_unit.vhd
===================================================================
--- trunk/wpfb_unit.vhd (nonexistent)
+++ trunk/wpfb_unit.vhd (revision 2)
@@ -0,0 +1,426 @@
+--------------------------------------------------------------------------------
+-- Author: Harm Jan Pepping : HJP at astron.nl: April 2012
+--------------------------------------------------------------------------------
+--
+-- Copyright (C) 2012
+-- ASTRON (Netherlands Institute for Radio Astronomy)
+-- 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 .
+--
+--------------------------------------------------------------------------------
+-- Purpose: Wideband FFT with Subband Statistics and streaming interfaces.
+--
+-- Description: This unit connects an incoming array of streaming interfaces
+-- to the wideband fft. The output of the wideband fft is
+-- connected to a set of subband statistics units. The statistics
+-- can be read via the memory mapped interface.
+-- A control unit takes care of the correct composition of the
+-- output streams(sop,eop,sync,bsn,err).
+--
+-- Remarks: . The unit can handle only one sync at a time. Therfor the
+-- sync interval should be larger than the total pipeline
+-- stages of the wideband fft.
+--
+-- . The g_coefs_file_prefix points to the location where the files
+-- with the initial content for the coefficients memories are located.
+-- These files can be created using the python script: create_mifs.py
+-- create_mifs.py is located in $UNB/Firmware/dsp/filter/src/python/
+-- It is possible to create the mif files based on every possible
+-- configuration of the filterbank in terms of:
+-- * wb_factor
+-- * nof points
+-- * nof_taps
+-- . The wbfb unit can handle a wideband factor > 1 (g_wpfb.wb_factor) or
+-- a narrowband factor > 1 (g_wpfb.nof_chan). Both factors can NOT be
+-- used at the same time.
+
+library ieee, common_pkg_lib, dp_pkg_lib, astron_r2sdf_fft_lib, astron_statistics_lib, astron_filter_lib, astron_wb_fft_lib, astron_diagnostics_lib, astron_mm_lib, astron_ram_lib;
+use IEEE.std_logic_1164.all;
+use STD.textio.all;
+use common_pkg_lib.common_pkg.all;
+use astron_ram_lib.common_ram_pkg.all;
+use dp_pkg_lib.dp_stream_pkg.ALL;
+use astron_r2sdf_fft_lib.rTwoSDFPkg.all;
+use astron_statistics_lib.all;
+use astron_filter_lib.all;
+use astron_filter_lib.fil_pkg.all;
+use astron_wb_fft_lib.all;
+use astron_wb_fft_lib.fft_pkg.all;
+use work.wpfb_pkg.all;
+
+entity wpfb_unit is
+ generic (
+ g_wpfb : t_wpfb;
+ g_use_prefilter : boolean := TRUE;
+ g_stats_ena : boolean := TRUE; -- Enables the statistics unit
+ g_use_bg : boolean := FALSE;
+ g_coefs_file_prefix : string := "../../../../filter/build/data/coefs_wide" -- File prefix for the coefficients files.
+ );
+ port (
+ dp_rst : in std_logic := '0';
+ dp_clk : in std_logic;
+ mm_rst : in std_logic;
+ mm_clk : in std_logic;
+ ram_fil_coefs_mosi : in t_mem_mosi;
+ ram_fil_coefs_miso : out t_mem_miso := c_mem_miso_rst;
+ ram_st_sst_mosi : in t_mem_mosi; -- Subband statistics registers
+ ram_st_sst_miso : out t_mem_miso := c_mem_miso_rst;
+ reg_bg_ctrl_mosi : in t_mem_mosi;
+ reg_bg_ctrl_miso : out t_mem_miso;
+ ram_bg_data_mosi : in t_mem_mosi;
+ ram_bg_data_miso : out t_mem_miso;
+ in_sosi_arr : in t_dp_sosi_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ out_sosi_arr : out t_dp_sosi_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0)
+ );
+end entity wpfb_unit;
+
+architecture str of wpfb_unit is
+
+ constant c_nof_stats : natural := 2**g_wpfb.nof_chan * g_wpfb.nof_points/g_wpfb.wb_factor;
+
+ constant c_fil_ppf : t_fil_ppf := (g_wpfb.wb_factor,
+ g_wpfb.nof_chan,
+ g_wpfb.nof_points,
+ g_wpfb.nof_taps,
+ c_nof_complex*g_wpfb.nof_wb_streams, -- Complex FFT always requires 2 filter streams: real and imaginary
+ g_wpfb.fil_backoff_w,
+ g_wpfb.fil_in_dat_w,
+ g_wpfb.fil_out_dat_w,
+ g_wpfb.coef_dat_w);
+
+ constant c_fft : t_fft := (g_wpfb.use_reorder,
+ g_wpfb.use_fft_shift,
+ g_wpfb.use_separate,
+ g_wpfb.nof_chan,
+ g_wpfb.wb_factor,
+ 0,
+ g_wpfb.nof_points,
+ g_wpfb.fft_in_dat_w,
+ g_wpfb.fft_out_dat_w,
+ g_wpfb.fft_out_gain_w,
+ g_wpfb.stage_dat_w,
+ g_wpfb.guard_w,
+ g_wpfb.guard_enable,
+ g_wpfb.stat_data_w,
+ g_wpfb.stat_data_sz);
+
+
+ constant c_bg_buf_adr_w : natural := ceil_log2(g_wpfb.nof_points/g_wpfb.wb_factor);
+ constant c_bg_data_file_index_arr : t_nat_natural_arr := array_init(0, g_wpfb.nof_wb_streams*g_wpfb.wb_factor, 1);
+ constant c_bg_data_file_prefix : string := "UNUSED";
+
+ signal ram_st_sst_mosi_arr : t_mem_mosi_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal ram_st_sst_miso_arr : t_mem_miso_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0) := (others => c_mem_miso_rst);
+
+ signal fil_in_arr : t_fil_slv_arr(c_nof_complex*g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal fil_out_arr : t_fil_slv_arr(c_nof_complex*g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal fil_out_val : std_logic;
+
+ signal fft_in_re_arr : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal fft_in_im_arr : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal fft_in_val : std_logic;
+
+ signal fft_out_re_arr_i : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal fft_out_im_arr_i : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal fft_out_re_arr : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal fft_out_im_arr : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal fft_out_val : std_logic_vector(g_wpfb.nof_wb_streams-1 downto 0);
+
+ signal fft_out_sosi_arr : t_dp_sosi_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0) := (others => c_dp_sosi_rst);
+ signal bg_siso_arr : t_dp_siso_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0) := (others => c_dp_siso_rdy);
+
+ type reg_type is record
+ in_sosi_arr : t_dp_sosi_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ end record;
+
+ signal r, rin : reg_type;
+
+begin
+
+ ---------------------------------------------------------------
+ -- CHECK IF PROVIDED GENERICS ARE ALLOWED.
+ ---------------------------------------------------------------
+ assert not(g_wpfb.nof_chan /= 0 and g_wpfb.wb_factor /= 1 and rising_edge(dp_clk)) report "nof_chan must be 0 when wb_factor > 1" severity FAILURE;
+
+ ---------------------------------------------------------------
+ -- INPUT REGISTER FOR THE SOSI ARRAY
+ ---------------------------------------------------------------
+ -- The complete input sosi arry is registered.
+ comb : process(r, in_sosi_arr)
+ variable v : reg_type;
+ begin
+ v := r;
+ v.in_sosi_arr := in_sosi_arr;
+ rin <= v;
+ end process comb;
+
+ regs : process(dp_clk)
+ begin
+ if rising_edge(dp_clk) then
+ r <= rin;
+ end if;
+ end process;
+
+ ---------------------------------------------------------------
+ -- COMBINE MEMORY MAPPED INTERFACES
+ ---------------------------------------------------------------
+ -- Combine the internal array of mm interfaces for the subband
+ -- statistics to one array that is connected to the port of the
+ -- fft_wide_unit.
+ u_mem_mux_sst : entity astron_mm_lib.common_mem_mux
+ generic map (
+ g_nof_mosi => g_wpfb.nof_wb_streams*g_wpfb.wb_factor,
+ g_mult_addr_w => ceil_log2(g_wpfb.stat_data_sz*c_nof_stats)
+ )
+ port map (
+ mosi => ram_st_sst_mosi,
+ miso => ram_st_sst_miso,
+ mosi_arr => ram_st_sst_mosi_arr,
+ miso_arr => ram_st_sst_miso_arr
+ );
+
+ gen_pfb : if g_use_bg = FALSE generate
+ ---------------------------------------------------------------
+ -- PREPARE INPUT DATA FOR WIDEBAND POLY PHASE FILTER
+ ---------------------------------------------------------------
+ -- Extract the data from the in_sosi_arr records and resize it
+ -- to fit the format for the fil_ppf_wide unit. The reordering
+ -- is done in such a way that the filtercoeficients are reused.
+ -- Note that both the real part and the imaginary part have
+ -- their own filterchannel.
+ -- When wb_factor = 4 and nof_wb_streams = 2 the mapping is as
+ -- follows (S = wb stream number, W = wideband stream number):
+ --
+ -- in_sosi_arr | fil_in_arr | fft_in_re_arr | fft_in_im_arr
+ -- S W | S W | S W | S W
+ -- 0 0 0 | 0 0 0 RE |0 0 0 0 RE |1 0 0 0 IM
+ -- 1 0 1 | 1 0 0 IM |4 1 0 1 RE |5 1 0 1 IM
+ -- 2 0 2 | 2 1 0 RE |8 2 0 2 RE |9 2 0 2 IM
+ -- 3 0 3 | 3 1 0 IM |12 3 0 3 RE |13 3 0 3 IM
+ -- 4 1 0 | 4 0 1 RE |2 4 1 0 RE |3 4 1 0 IM
+ -- 5 1 1 | 5 0 1 IM |6 5 1 1 RE |7 5 1 1 IM
+ -- 6 1 2 | 6 1 1 RE |10 6 1 2 RE |11 6 1 2 IM
+ -- 7 1 3 | 7 1 1 IM |14 7 1 3 RE |15 7 1 3 IM
+ -- | 8 0 2 RE | |
+ -- | 9 0 2 IM | |
+ -- | 10 1 2 RE | |
+ -- | 11 1 2 IM | |
+ -- | 12 0 3 RE | |
+ -- | 13 0 3 IM | |
+ -- | 14 1 3 RE | |
+ -- | 15 1 3 IM | |
+ --
+ gen_prep_filter_wb_factor: for I in 0 to g_wpfb.wb_factor-1 generate
+ gen_prep_filter_streams: for J in 0 to g_wpfb.nof_wb_streams-1 generate
+ fil_in_arr(2*J+I*g_wpfb.nof_wb_streams*c_nof_complex) <= RESIZE_SVEC(r.in_sosi_arr(I+J*g_wpfb.wb_factor).re(g_wpfb.fil_in_dat_w-1 downto 0), fil_in_arr(0)'length);
+ fil_in_arr(2*J+I*g_wpfb.nof_wb_streams*c_nof_complex+1) <= RESIZE_SVEC(r.in_sosi_arr(I+J*g_wpfb.wb_factor).im(g_wpfb.fil_in_dat_w-1 downto 0), fil_in_arr(0)'length);
+ end generate;
+ end generate;
+
+ ---------------------------------------------------------------
+ -- THE POLY PHASE FILTER
+ ---------------------------------------------------------------
+ gen_prefilter : IF g_use_prefilter = TRUE generate
+ u_filter : entity astron_filter_lib.fil_ppf_wide
+ generic map (
+ g_fil_ppf => c_fil_ppf,
+ g_fil_ppf_pipeline => g_wpfb.fil_pipeline,
+ 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_fil_coefs_mosi,
+ ram_coefs_miso => ram_fil_coefs_miso,
+ in_dat_arr => fil_in_arr,
+ in_val => r.in_sosi_arr(0).valid,
+ out_dat_arr => fil_out_arr,
+ out_val => fil_out_val
+ );
+ end generate;
+
+ -- Bypass filter
+ gen_no_prefilter : if g_use_prefilter = FALSE generate
+ fil_out_arr <= fil_in_arr;
+ fil_out_val <= r.in_sosi_arr(0).valid;
+ end generate;
+
+ fft_in_val <= fil_out_val;
+
+ ---------------------------------------------------------------
+ -- THE WIDEBAND FFT
+ ---------------------------------------------------------------
+ gen_wide_band_fft: if g_wpfb.wb_factor > 1 generate
+ ---------------------------------------------------------------
+ -- PREPARE INPUT DATA FOR WIDEBAND FFT
+ ---------------------------------------------------------------
+ -----------------------------------------------------------------------------------------------------
+ gen_prep_fft_streams: for I in 0 to g_wpfb.nof_wb_streams-1 generate
+ gen_prep_fft_wb_factor: for J in 0 to g_wpfb.wb_factor-1 generate
+ fft_in_re_arr(I*g_wpfb.wb_factor+J) <= fil_out_arr(J*c_nof_complex*g_wpfb.nof_wb_streams+I*c_nof_complex);
+ fft_in_im_arr(I*g_wpfb.wb_factor+J) <= fil_out_arr(J*c_nof_complex*g_wpfb.nof_wb_streams+I*c_nof_complex+1);
+ end generate;
+ end generate;
+ -----------------------------------------------------------------------------------------------------
+ gen_prep_wide_fft_streams: for I in 0 to g_wpfb.nof_wb_streams-1 generate
+ u_fft_wide : entity astron_wb_fft_lib.fft_r2_wide
+ generic map(
+ g_fft => c_fft, -- generics for the WFFT
+ g_pft_pipeline => g_wpfb.pft_pipeline,
+ g_fft_pipeline => g_wpfb.fft_pipeline
+ )
+ port map(
+ clk => dp_clk,
+ rst => dp_rst,
+ in_re_arr => fft_in_re_arr((I+1)*g_wpfb.wb_factor-1 downto I*g_wpfb.wb_factor),
+ in_im_arr => fft_in_im_arr((I+1)*g_wpfb.wb_factor-1 downto I*g_wpfb.wb_factor),
+ in_val => fft_in_val,
+ out_re_arr => fft_out_re_arr((I+1)*g_wpfb.wb_factor-1 downto I*g_wpfb.wb_factor),
+ out_im_arr => fft_out_im_arr((I+1)*g_wpfb.wb_factor-1 downto I*g_wpfb.wb_factor),
+ out_val => fft_out_val(I)
+ );
+ end generate;
+ end generate;
+
+ ---------------------------------------------------------------
+ -- THE PIPELINED FFT
+ ---------------------------------------------------------------
+ gen_pipeline_fft: if g_wpfb.wb_factor = 1 generate
+ ---------------------------------------------------------------
+ -- PREPARE INPUT DATA FOR WIDEBAND FFT
+ ---------------------------------------------------------------
+ gen_prep_fft_streams: for I in 0 to g_wpfb.nof_wb_streams-1 generate
+ fft_in_re_arr(I) <= fil_out_arr(I*c_nof_complex);
+ fft_in_im_arr(I) <= fil_out_arr(I*c_nof_complex+1);
+ end generate;
+
+ gen_prep_pipe_fft_streams: for I in 0 to g_wpfb.nof_wb_streams-1 generate
+ u_fft_pipe : entity astron_wb_fft_lib.fft_r2_pipe
+ generic map(
+ g_fft => c_fft,
+ g_pipeline => g_wpfb.fft_pipeline
+ )
+ port map(
+ clk => dp_clk,
+ rst => dp_rst,
+ in_re => fft_in_re_arr(I)(c_fft.in_dat_w-1 downto 0),
+ in_im => fft_in_im_arr(I)(c_fft.in_dat_w-1 downto 0),
+ in_val => fft_in_val,
+ out_re => fft_out_re_arr_i(I)(c_fft.out_dat_w-1 downto 0),
+ out_im => fft_out_im_arr_i(I)(c_fft.out_dat_w-1 downto 0),
+ out_val => fft_out_val(I)
+ );
+ fft_out_re_arr(I) <= RESIZE_SVEC(fft_out_re_arr_i(I)(c_fft.out_dat_w-1 downto 0), fft_out_re_arr(I)'length);
+ fft_out_im_arr(I) <= RESIZE_SVEC(fft_out_im_arr_i(I)(c_fft.out_dat_w-1 downto 0), fft_out_im_arr(I)'length);
+ end generate;
+ end generate;
+
+ ---------------------------------------------------------------
+ -- FFT CONTROL UNIT
+ ---------------------------------------------------------------
+ -- The fft control unit composes the output array in the dp-
+ -- streaming format.
+ u_fft_control : entity astron_wb_fft_lib.fft_wide_unit_control
+ generic map (
+ g_fft => c_fft,
+ g_nof_ffts => g_wpfb.nof_wb_streams
+ )
+ port map(
+ rst => dp_rst,
+ clk => dp_clk,
+ in_re_arr => fft_out_re_arr,
+ in_im_arr => fft_out_im_arr,
+ in_val => fft_out_val(0),
+ ctrl_sosi => r.in_sosi_arr(0),
+ out_sosi_arr => fft_out_sosi_arr
+ );
+
+ end generate;
+
+ ----------------------------------------------------------------------------
+ -- Source: block generator
+ ----------------------------------------------------------------------------
+ gen_bg : if g_use_bg = TRUE generate
+ u_bg : entity astron_diagnostics_lib.mms_diag_block_gen
+ generic map(
+ g_nof_streams => g_wpfb.nof_wb_streams*g_wpfb.wb_factor,
+ g_buf_dat_w => c_nof_complex*g_wpfb.fft_out_dat_w,
+ g_buf_addr_w => c_bg_buf_adr_w, -- Waveform buffer size 2**g_buf_addr_w nof samples
+ g_file_index_arr => c_bg_data_file_index_arr,
+ g_file_name_prefix => c_bg_data_file_prefix
+ )
+ port map(
+ -- System
+ mm_rst => mm_rst,
+ mm_clk => mm_clk,
+ dp_rst => dp_rst,
+ dp_clk => dp_clk,
+ en_sync => '0',
+ -- MM interface
+ reg_bg_ctrl_mosi => reg_bg_ctrl_mosi,
+ reg_bg_ctrl_miso => reg_bg_ctrl_miso,
+ ram_bg_data_mosi => ram_bg_data_mosi,
+ ram_bg_data_miso => ram_bg_data_miso,
+ -- ST interface
+ out_siso_arr => bg_siso_arr,
+ out_sosi_arr => fft_out_sosi_arr
+ );
+ end generate;
+
+ ---------------------------------------------------------------
+ -- SUBBAND STATISTICS
+ ---------------------------------------------------------------
+ -- For all "wb_factor"x"nof_wb_streams" output streams of the
+ -- wideband FFT a subband statistics unit is placed if the
+ -- g_stats_ena is TRUE.
+ -- Since the subband statistics module uses embedded DSP blocks
+ -- for multiplication, the incoming data cannot be wider
+ -- than 18 bit.
+ gen_stats : if g_stats_ena = TRUE generate
+ gen_stats_streams: for I in 0 to g_wpfb.nof_wb_streams-1 generate
+ gen_stats_wb_factor: for J in 0 to g_wpfb.wb_factor-1 generate
+ u_subband_stats : entity astron_statistics_lib.st_sst
+ generic map(
+ g_nof_stat => c_nof_stats,
+ g_in_data_w => g_wpfb.fft_out_dat_w,
+ g_stat_data_w => g_wpfb.stat_data_w,
+ g_stat_data_sz => g_wpfb.stat_data_sz
+ )
+ port map (
+ mm_rst => mm_rst,
+ mm_clk => mm_clk,
+ dp_rst => dp_rst,
+ dp_clk => dp_clk,
+ in_complex => fft_out_sosi_arr(I*g_wpfb.wb_factor+J),
+ ram_st_sst_mosi => ram_st_sst_mosi_arr(I*g_wpfb.wb_factor+J),
+ ram_st_sst_miso => ram_st_sst_miso_arr(I*g_wpfb.wb_factor+J)
+ );
+ end generate;
+ end generate;
+ end generate;
+
+ -- Connect to the outside world
+ gen_output_streams: for I in 0 to g_wpfb.nof_wb_streams-1 generate
+ gen_output_wb_factor : for J in 0 to g_wpfb.wb_factor-1 generate
+ out_sosi_arr(I*g_wpfb.wb_factor+J) <= fft_out_sosi_arr(I*g_wpfb.wb_factor+J);
+ end generate;
+ end generate;
+
+end str;
+
+
+
Index: trunk/wpfb_unit_dev.vhd
===================================================================
--- trunk/wpfb_unit_dev.vhd (nonexistent)
+++ trunk/wpfb_unit_dev.vhd (revision 2)
@@ -0,0 +1,718 @@
+--------------------------------------------------------------------------------
+-- Author: Harm Jan Pepping : HJP at astron.nl: April 2012
+--------------------------------------------------------------------------------
+--
+-- Copyright (C) 2012
+-- ASTRON (Netherlands Institute for Radio Astronomy)
+-- 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 .
+--
+--------------------------------------------------------------------------------
+-- Purpose: Wideband polyphase filterbank with subband statistics and streaming interfaces.
+--
+-- Description:
+--
+-- This WPFB unit connects an incoming array of streaming interfaces to the
+-- wideband pft + fft.
+-- The output of the wideband fft is connected to a set of subband statistics
+-- units. The statistics can be read via the memory mapped interface.
+-- A control unit takes care of the correct composition of the control of the
+-- output streams regarding sop, eop, sync, bsn, err.
+--
+-- The wpfb unit can handle a wideband factor >= 1 (g_wpfb.wb_factor) or
+-- a narrowband factor >= 1 (2**g_wpfb.nof_chan).
+-- . For wb_factor = 1 the wpfb_unit uses fft_r2_pipe
+-- . For wb_factor > 1 the wpfb_unit uses fft_r2_wide
+-- . For wb_factor >= 1 the wpfb_unit supports nof_chan >= 0, even though the
+-- concept of channels is typically not useful when wb_factor > 1.
+-- . The wpfb_unit does support use_reorder.
+-- . The wpfb_unit does support use_separate.
+-- . The wpfb_unit does support input flow control with invalid gaps in the
+-- input.
+--
+-- . g_coefs_file_prefix:
+-- The g_coefs_file_prefix points to the location where the files
+-- with the initial content for the coefficients memories are located and
+-- is described in fil_ppf_wide.vhd.
+--
+-- . fft_out_gain_w
+-- For two real input typically fft_out_gain_w = 1 is used to compensate for
+-- the divide by 2 in the separate function that is done because real input
+-- frequency bins have norm 0.5. For complex input typically fft_out_gain_w
+-- = 0, because the complex bins have norm 1.
+--
+-- . g_dont_flip_channels:
+-- True preserves channel interleaving, set by g_wpfb.nof_chan>0, of the FFT
+-- output when g_bit_flip=true to reorder the FFT output.
+-- The g_dont_flip_channels applies for both complex input and two_real
+-- input FFT. The g_dont_flip_channels is only implemented for the pipelined
+-- fft_r2_pipe, because for g_wpfb.wb_factor=1 using g_wpfb.nof_chan>0 makes
+-- sense, while for the fft_r2_wide with g_wpfb.wb_factor>1 using input
+-- multiplexing via g_wpfb.nof_chan>0 makes less sense.
+--
+-- The reordering to the fil_ppf_wide is done such that the FIR filter
+-- coefficients are reused. The same filter coefficients are used for all
+-- streams. The filter has real coefficients, because the filterbank
+-- channels are symmetrical in frequency. The real part and the imaginary
+-- part are filtered independently and also use the same real FIR
+-- coefficients.
+--
+-- Note that:
+-- . The same P of all streams are grouped the in filter and all P per
+-- stream are grouped in the FFT. Hence the WPFB input is grouped per
+-- P for all wideband streams to allow FIR coefficients reuse per P
+-- for all wideband streams. The WPFB output is grouped per wideband
+-- stream to have all P together.
+--
+-- . The wideband time index t is big-endian inside the prefilter and
+-- little-endian inside the FFT.
+-- When g_big_endian_wb_in=true then the WPFB input must be in big-endian
+-- format, else in little-endian format.
+-- For little-endian time index t increments in the same direction as the
+-- wideband factor index P, so P = 0, 1, 2, 3 --> t0, t1, t2, t3.
+-- For big-endian the time index t increments in the opposite direction of
+-- the wideband factor index P, so P = 3, 2, 1, 0 --> t0, t1, t2, t3.
+-- The WPFB output is fixed little-endian, so with frequency bins in
+-- incrementing order. However the precise frequency bin order depends
+-- on the reorder generics.
+--
+-- When wb_factor = 4 and nof_wb_streams = 2 the mapping is as follows using
+-- the array notation:
+--
+-- . I = array index
+-- . S = stream index of a wideband stream
+-- . P = wideband factor index
+-- . t = time index
+--
+-- parallel serial type
+-- in_sosi_arr [nof_streams][wb_factor] [t] cint
+--
+-- fil_in_arr [wb_factor][nof_streams][complex] [t] int
+-- fil_out_arr [wb_factor][nof_streams][complex] [t] int
+--
+-- fil_sosi_arr [nof_streams][wb_factor] [t] cint
+-- fft_in_re_arr [nof_streams][wb_factor] [t] int
+-- fft_in_im_arr [nof_streams][wb_factor] [t] int
+-- fft_out_re_arr [nof_streams][wb_factor] [bin] int
+-- fft_out_im_arr [nof_streams][wb_factor] [bin] int
+-- fft_out_sosi_arr [nof_streams][wb_factor] [bin] cint
+-- pfb_out_sosi_arr [nof_streams][wb_factor] [bin] cint with sync, BSN, sop, eop
+-- out_sosi_arr [nof_streams][wb_factor] [bin] cint with sync, BSN, sop, eop
+--
+-- in_sosi_arr | fil_in_arr | fft_in_re_arr | fft_out_re_arr
+-- fil_sosi_arr | fil_out_arr | fft_in_im_arr | fft_out_im_arr
+-- | | | fft_out_sosi_arr
+-- | | | pfb_out_sosi_arr
+-- | | | out_sosi_arr
+-- | | |
+-- I S P t | I P S | I S P t | I S P
+-- 7 1 3 0 | 15 3 1 IM | 7 1 3 3 | 7 1 3
+-- 6 1 2 1 | 14 3 1 RE | 6 1 2 2 | 6 1 2
+-- 5 1 1 2 | 13 3 0 IM | 5 1 1 1 | 5 1 1
+-- 4 1 0 3 | 12 3 0 RE | 4 1 0 0 | 4 1 0
+-- 3 0 3 0 | 11 2 1 IM | 3 0 3 3 | 3 0 3
+-- 2 0 2 1 | 10 2 1 RE | 2 0 2 2 | 2 0 2
+-- 1 0 1 2 | 9 2 0 IM | 1 0 1 1 | 1 0 1
+-- 0 0 0 3 | 8 2 0 RE | 0 0 0 0 | 0 0 0
+-- | 7 1 1 IM | |
+-- ^ | 6 1 1 RE | ^ |
+-- big | 5 1 0 IM | little |
+-- endian | 4 1 0 RE | endian |
+-- | 3 0 1 IM | |
+-- | 2 0 1 RE | |
+-- | 1 0 0 IM | |
+-- | 0 0 0 RE | |
+--
+-- The WPFB output are the frequency bins per transformed block:
+-- . subbands, in case ot two real input or
+-- . channels, in case of complex input
+--
+-- The order of the WPFB output depends on the g_fft fields:
+-- . wb_factor
+-- . use_reorder
+-- . use_fft_shift
+-- . use_separate
+--
+-- The frequency bin order at the output is obtained with reg_out_bin
+-- in the test bench tb_wpfb_unit_dev.vhd.
+--
+-- Output examples:
+--
+-- Frequency bins:
+-- fs = sample frequency
+-- Bb = fs/nof_points = bin bandwidth
+--
+-- 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+-- ^ ^ ^ ^ ^
+-- <--------- negative bin frequencies ---------> 0 <---------- positive bin frequencies ------->
+-- -fs/2 -Bb 0 +Bb +fs/2-Bb
+--
+-- I) Wideband wb_factor = 4
+-- 1) Two real inputs:
+--
+-- out_sosi_arr:
+-- I S P bin frequency order . nof_streams = 2
+-- 7 1 3 12 12 13 13 14 14 15 15 . wb_factor = 4
+-- 6 1 2 8 8 9 9 10 10 11 11 . nof_points = 32
+-- 5 1 1 4 4 5 5 6 6 7 7 . use_reorder = true
+-- 4 1 0 0 0 1 1 2 2 3 3 . use_fft_shift = false
+-- 3 0 3 12 12 13 13 14 14 15 15 . use_separate = true
+-- 2 0 2 8 8 9 9 10 10 11 11 - input A via in_sosi_arr().re
+-- 1 0 1 4 4 5 5 6 6 7 7 - input B via in_sosi_arr().im
+-- 0 0 0 0 0 1 1 2 2 3 3
+-- input A B A B A B A B
+--
+-- when nof_chan=1 then:
+-- I S P bin frequency order
+-- 7 1 3 12 12 13 13 14 14 15 15 12 12 13 13 14 14 15 15
+-- 6 1 2 8 8 9 9 10 10 11 11 8 8 9 9 10 10 11 11
+-- 5 1 1 4 4 5 5 6 6 7 7 4 4 5 5 6 6 7 7
+-- 4 1 0 0 0 1 1 2 2 3 3 0 0 1 1 2 2 3 3
+-- 3 0 3 12 12 13 13 14 14 15 15 12 12 13 13 14 14 15 15
+-- 2 0 2 8 8 9 9 10 10 11 11 8 8 9 9 10 10 11 11
+-- 1 0 1 4 4 5 5 6 6 7 7 4 4 5 5 6 6 7 7
+-- 0 0 0 0 0 1 1 2 2 3 3 0 0 1 1 2 2 3 3
+-- input A B A B A B A B A B A B A B A B
+-- channel 0....................0 1....................1
+--
+-- 2a) Complex input with fft_shift:
+--
+-- out_sosi_arr:
+-- I S P bin frequency order . nof_streams = 2
+-- 7 1 3 24 25 26 27 28 29 30 31 . wb_factor = 4
+-- 6 1 2 16 17 18 19 20 21 22 23 . nof_points = 32
+-- 5 1 1 8 9 10 11 12 13 14 15 . use_reorder = true
+-- 4 1 0 0 1 2 3 4 5 6 7 . use_fft_shift = true
+-- 3 0 3 24 25 26 27 28 29 30 31 . use_separate = false
+-- 2 0 2 16 17 18 19 20 21 22 23 - complex input via in_sosi_arr().re and im
+-- 1 0 1 8 9 10 11 12 13 14 15
+-- 0 0 0 0 1 2 3 4 5 6 7
+--
+-- when nof_chan=1 then:
+-- I S P bin frequency order
+-- 7 1 3 24 25 26 27 28 29 30 31 24 25 26 27 28 29 30 31
+-- 6 1 2 16 17 18 19 20 21 22 23 16 17 18 19 20 21 22 23
+-- 5 1 1 8 9 10 11 12 13 14 15 8 9 10 11 12 13 14 15
+-- 4 1 0 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-- 3 0 3 24 25 26 27 28 29 30 31 24 25 26 27 28 29 30 31
+-- 2 0 2 16 17 18 19 20 21 22 23 16 17 18 19 20 21 22 23
+-- 1 0 1 8 9 10 11 12 13 14 15 8 9 10 11 12 13 14 15
+-- 0 0 0 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-- channel 0....................0 1....................1
+--
+-- 2b) Complex input with reorder, but no fft_shift:
+--
+-- out_sosi_arr:
+-- I S P bin frequency order . nof_streams = 2
+-- 7 1 3 8 9 10 11 12 13 14 15 . wb_factor = 4
+-- 6 1 2 0 1 2 3 4 5 6 7 . nof_points = 32
+-- 5 1 1 24 25 26 27 28 29 30 31 . use_reorder = true
+-- 4 1 0 16 17 18 19 20 21 22 23 . use_fft_shift = false
+-- 3 0 3 8 9 10 11 12 13 14 15 . use_separate = false
+-- 2 0 2 0 1 2 3 4 5 6 7 - complex input via in_sosi_arr().re and im
+-- 1 0 1 24 25 26 27 28 29 30 31
+-- 0 0 0 16 17 18 19 20 21 22 23
+--
+-- when nof_chan=1 then:
+-- I S P bin frequency order
+-- 7 1 3 8 9 10 11 12 13 14 15 8 9 10 11 12 13 14 15
+-- 6 1 2 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-- 5 1 1 24 25 26 27 28 29 30 31 24 25 26 27 28 29 30 31
+-- 4 1 0 16 17 18 19 20 21 22 23 16 17 18 19 20 21 22 23
+-- 3 0 3 8 9 10 11 12 13 14 15 8 9 10 11 12 13 14 15
+-- 2 0 2 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-- 1 0 1 24 25 26 27 28 29 30 31 24 25 26 27 28 29 30 31
+-- 0 0 0 16 17 18 19 20 21 22 23 16 17 18 19 20 21 22 23
+-- channel 0....................0 1....................1
+--
+-- 2c) Complex input without reorder (so bit flipped):
+--
+-- out_sosi_arr:
+-- I S P bin frequency order . nof_streams = 2
+-- 7 1 3 8 12 10 14 9 13 11 15 . wb_factor = 4
+-- 6 1 2 24 28 26 30 25 29 27 31 . nof_points = 32
+-- 5 1 1 0 4 2 6 1 5 3 7 . use_reorder = false
+-- 4 1 0 16 20 18 22 17 21 19 23 . use_fft_shift = false
+-- 3 0 3 8 12 10 14 9 13 11 15 . use_separate = false
+-- 2 0 2 24 28 26 30 25 29 27 31 - complex input via in_sosi_arr().re and im
+-- 1 0 1 0 4 2 6 1 5 3 7
+-- 0 0 0 16 20 18 22 17 21 19 23
+--
+-- when nof_chan=1 then:
+-- I S P bin frequency order
+-- 7 1 3 8 8 12 12 10 10 14 14 9 9 13 13 11 11 15 15
+-- 6 1 2 24 24 28 28 26 26 30 30 25 25 29 29 27 27 31 31
+-- 5 1 1 0 0 4 4 2 2 6 6 1 1 5 5 3 3 7 7
+-- 4 1 0 16 16 20 20 18 18 22 22 17 17 21 21 19 19 23 23
+-- 3 0 3 8 8 12 12 10 10 14 14 9 9 13 13 11 11 15 15
+-- 2 0 2 24 24 28 28 26 26 30 30 25 25 29 29 27 27 31 31
+-- 1 0 1 0 0 4 4 2 2 6 6 1 1 5 5 3 3 7 7
+-- 0 0 0 16 16 20 20 18 18 22 22 17 17 21 21 19 19 23 23
+-- channel 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+--
+-- II) Narrowband wb_factor = 1
+--
+-- 1) Two real inputs:
+--
+-- . nof_streams = 2
+-- . nof_chan = 0
+-- . wb_factor = 1
+-- . nof_points = 32
+-- . use_reorder = true
+-- . use_fft_shift = false
+-- . use_separate = true
+-- - input A via in_sosi_arr().re
+-- - input B via in_sosi_arr().im
+--
+-- out_sosi_arr:
+-- I S P bin frequency order
+-- 1 1 0 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15
+-- 0 0 0 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15
+-- input A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B
+--
+-- when nof_chan=1 then:
+-- I S P bin frequency order
+-- 1 1 0 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15
+-- 0 0 0 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15
+-- input A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B
+-- channel: 0............................................................................................0 1............................................................................................1
+--
+-- 2) Complex input
+-- . nof_streams = 2
+-- . nof_chan = 0
+-- . wb_factor = 1
+-- . nof_points = 32
+-- . use_separate = false
+-- - complex input via in_sosi_arr().re and im
+
+-- 2a) Complex input with fft_shift (so use_reorder = true, use_fft_shift = true)
+--
+-- out_sosi_arr:
+-- I S P bin frequency order
+-- 1 1 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+-- 0 0 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+--
+-- when nof_chan=1 then:
+-- I S P bin frequency order
+-- 1 1 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+-- 0 0 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+-- channel: 0............................................................................................0 1............................................................................................1
+--
+-- 2b) Complex input with reorder but no fft_shift (so use_reorder = true, use_fft_shift = false)
+--
+-- out_sosi_arr:
+-- I S P bin frequency order
+-- 1 1 0 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+-- 0 0 0 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+--
+-- when nof_chan=1 then:
+-- I S P bin frequency order
+-- 1 1 0 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+-- 0 0 0 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+-- channel: 0............................................................................................0 1............................................................................................1
+--
+-- 2c) Complex input without reorder (so use_reorder = false, use_fft_shift = false)
+--
+-- out_sosi_arr:
+-- I S P bin frequency order
+-- 1 1 0 16 0 24 8 20 4 28 12 18 2 26 10 22 6 30 14 17 1 25 9 21 5 29 13 19 3 27 11 23 7 31 15
+-- 0 0 0 16 0 24 8 20 4 28 12 18 2 26 10 22 6 30 14 17 1 25 9 21 5 29 13 19 3 27 11 23 7 31 15
+--
+-- when nof_chan=1 then:
+-- I S P bin frequency order
+-- 1 1 0 16 16 0 0 24 24 8 8 20 20 4 4 28 28 12 12 18 18 2 2 26 26 10 10 22 22 6 6 30 30 14 14 17 17 1 1 25 25 9 9 21 21 5 5 29 29 13 13 19 19 3 3 27 27 11 11 23 23 7 7 31 31 15 15
+-- 0 0 0 16 16 0 0 24 24 8 8 20 20 4 4 28 28 12 12 18 18 2 2 26 26 10 10 22 22 6 6 30 30 14 14 17 17 1 1 25 25 9 9 21 21 5 5 29 29 13 13 19 19 3 3 27 27 11 11 23 23 7 7 31 31 15 15
+-- channel: 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
+--
+-- Remarks:
+-- . The unit can handle only one sync at a time. Therfor the
+-- sync interval should be larger than the total pipeline
+-- stages of the wideband fft.
+--
+
+library ieee, common_pkg_lib, dp_pkg_lib, astron_r2sdf_fft_lib, astron_statistics_lib, astron_filter_lib, astron_wb_fft_lib, astron_diagnostics_lib, astron_ram_lib, astron_mm_lib;
+use IEEE.std_logic_1164.all;
+use STD.textio.all;
+use common_pkg_lib.common_pkg.all;
+use astron_ram_lib.common_ram_pkg.all;
+use dp_pkg_lib.dp_stream_pkg.ALL;
+use astron_r2sdf_fft_lib.rTwoSDFPkg.all;
+use astron_statistics_lib.all;
+use astron_filter_lib.all;
+use astron_filter_lib.fil_pkg.all;
+use astron_wb_fft_lib.all;
+use astron_wb_fft_lib.fft_pkg.all;
+use work.wpfb_pkg.all;
+
+entity wpfb_unit_dev is
+ generic (
+ g_big_endian_wb_in : boolean := true;
+ g_wpfb : t_wpfb;
+ g_dont_flip_channels: boolean := false; -- True preserves channel interleaving for pipelined FFT
+ g_use_prefilter : boolean := TRUE;
+ g_stats_ena : boolean := TRUE; -- Enables the statistics unit
+ g_use_bg : boolean := FALSE;
+ g_coefs_file_prefix : string := "data/coefs_wide" -- File prefix for the coefficients files.
+ );
+ port (
+ dp_rst : in std_logic := '0';
+ dp_clk : in std_logic;
+ mm_rst : in std_logic;
+ mm_clk : in std_logic;
+ ram_fil_coefs_mosi : in t_mem_mosi;
+ ram_fil_coefs_miso : out t_mem_miso := c_mem_miso_rst;
+ ram_st_sst_mosi : in t_mem_mosi; -- Subband statistics registers
+ ram_st_sst_miso : out t_mem_miso := c_mem_miso_rst;
+ reg_bg_ctrl_mosi : in t_mem_mosi;
+ reg_bg_ctrl_miso : out t_mem_miso;
+ ram_bg_data_mosi : in t_mem_mosi;
+ ram_bg_data_miso : out t_mem_miso;
+ in_sosi_arr : in t_dp_sosi_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ fil_sosi_arr : out t_dp_sosi_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ out_sosi_arr : out t_dp_sosi_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0)
+ );
+end entity wpfb_unit_dev;
+
+architecture str of wpfb_unit_dev is
+
+ constant c_nof_channels : natural := 2**g_wpfb.nof_chan;
+
+ constant c_nof_data_per_block : natural := c_nof_channels * g_wpfb.nof_points;
+ constant c_nof_valid_per_block : natural := c_nof_data_per_block / g_wpfb.wb_factor;
+
+ constant c_nof_stats : natural := c_nof_valid_per_block;
+
+ constant c_fil_ppf : t_fil_ppf := (g_wpfb.wb_factor,
+ g_wpfb.nof_chan,
+ g_wpfb.nof_points,
+ g_wpfb.nof_taps,
+ c_nof_complex*g_wpfb.nof_wb_streams, -- Complex FFT always requires 2 filter streams: real and imaginary
+ g_wpfb.fil_backoff_w,
+ g_wpfb.fil_in_dat_w,
+ g_wpfb.fil_out_dat_w,
+ g_wpfb.coef_dat_w);
+
+ constant c_fft : t_fft := (g_wpfb.use_reorder,
+ g_wpfb.use_fft_shift,
+ g_wpfb.use_separate,
+ g_wpfb.nof_chan,
+ g_wpfb.wb_factor,
+ 0,
+ g_wpfb.nof_points,
+ g_wpfb.fft_in_dat_w,
+ g_wpfb.fft_out_dat_w,
+ g_wpfb.fft_out_gain_w,
+ g_wpfb.stage_dat_w,
+ g_wpfb.guard_w,
+ g_wpfb.guard_enable,
+ g_wpfb.stat_data_w,
+ g_wpfb.stat_data_sz);
+
+ constant c_fft_r2_check : boolean := fft_r2_parameter_asserts(c_fft);
+
+ constant c_bg_buf_adr_w : natural := ceil_log2(g_wpfb.nof_points/g_wpfb.wb_factor);
+ constant c_bg_data_file_index_arr : t_nat_natural_arr := array_init(0, g_wpfb.nof_wb_streams*g_wpfb.wb_factor, 1);
+ constant c_bg_data_file_prefix : string := "UNUSED";
+
+ signal ram_st_sst_mosi_arr : t_mem_mosi_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal ram_st_sst_miso_arr : t_mem_miso_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0) := (others => c_mem_miso_rst);
+
+ signal fil_in_arr : t_fil_slv_arr(c_nof_complex*g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal fil_in_val : std_logic;
+ signal fil_out_arr : t_fil_slv_arr(c_nof_complex*g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal fil_out_val : std_logic;
+
+ signal fft_in_re_arr : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal fft_in_im_arr : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal fft_in_val : std_logic;
+
+ signal fft_out_re_arr_i : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal fft_out_im_arr_i : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal fft_out_re_arr : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal fft_out_im_arr : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal fft_out_re_arr_pipe : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal fft_out_im_arr_pipe : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ signal fft_out_val_arr : std_logic_vector(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+
+ signal fft_out_sosi : t_dp_sosi;
+ signal fft_out_sosi_arr : t_dp_sosi_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0) := (others => c_dp_sosi_rst);
+
+ signal pfb_out_sosi_arr : t_dp_sosi_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0) := (others => c_dp_sosi_rst);
+
+ type reg_type is record
+ in_sosi_arr : t_dp_sosi_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0);
+ end record;
+
+ signal r, rin : reg_type;
+
+begin
+
+ -- The complete input sosi arry is registered.
+ comb : process(r, in_sosi_arr)
+ variable v : reg_type;
+ begin
+ v := r;
+ v.in_sosi_arr := in_sosi_arr;
+ rin <= v;
+ end process comb;
+
+ regs : process(dp_clk)
+ begin
+ if rising_edge(dp_clk) then
+ r <= rin;
+ end if;
+ end process;
+
+ ---------------------------------------------------------------
+ -- COMBINE MEMORY MAPPED INTERFACES
+ ---------------------------------------------------------------
+ -- Combine the internal array of mm interfaces for the subband
+ -- statistics to one array that is connected to the port of the
+ -- fft_wide_unit.
+ u_mem_mux_sst : entity astron_mm_lib.common_mem_mux
+ generic map (
+ g_nof_mosi => g_wpfb.nof_wb_streams*g_wpfb.wb_factor,
+ g_mult_addr_w => ceil_log2(g_wpfb.stat_data_sz*c_nof_stats)
+ )
+ port map (
+ mosi => ram_st_sst_mosi,
+ miso => ram_st_sst_miso,
+ mosi_arr => ram_st_sst_mosi_arr,
+ miso_arr => ram_st_sst_miso_arr
+ );
+
+ gen_pfb : if g_use_bg = FALSE generate
+ ---------------------------------------------------------------
+ -- REWIRE THE DATA FOR WIDEBAND POLY PHASE FILTER
+ ---------------------------------------------------------------
+
+ -- Wire in_sosi_arr --> fil_in_arr
+ wire_fil_in_wideband: for P in 0 to g_wpfb.wb_factor-1 generate
+ wire_fil_in_streams: for S in 0 to g_wpfb.nof_wb_streams-1 generate
+ fil_in_arr(P*g_wpfb.nof_wb_streams*c_nof_complex+S*c_nof_complex) <= RESIZE_SVEC_32(r.in_sosi_arr(S*g_wpfb.wb_factor+P).re(g_wpfb.fil_in_dat_w-1 downto 0));
+ fil_in_arr(P*g_wpfb.nof_wb_streams*c_nof_complex+S*c_nof_complex+1) <= RESIZE_SVEC_32(r.in_sosi_arr(S*g_wpfb.wb_factor+P).im(g_wpfb.fil_in_dat_w-1 downto 0));
+ end generate;
+ end generate;
+ fil_in_val <= r.in_sosi_arr(0).valid;
+
+ -- Wire fil_out_arr --> fil_sosi_arr
+ wire_fil_sosi_streams: for S in 0 to g_wpfb.nof_wb_streams-1 generate
+ wire_fil_sosi_wideband: for P in 0 to g_wpfb.wb_factor-1 generate
+ fil_sosi_arr(S*g_wpfb.wb_factor+P).valid <= fil_out_val;
+ fil_sosi_arr(S*g_wpfb.wb_factor+P).re <= RESIZE_DP_DSP_DATA(fil_out_arr(P*g_wpfb.nof_wb_streams*c_nof_complex+S*c_nof_complex ));
+ fil_sosi_arr(S*g_wpfb.wb_factor+P).im <= RESIZE_DP_DSP_DATA(fil_out_arr(P*g_wpfb.nof_wb_streams*c_nof_complex+S*c_nof_complex+1));
+ end generate;
+ end generate;
+
+ -- Wire fil_out_arr --> fft_in_re_arr, fft_in_im_arr
+ wire_fft_in_streams: for S in 0 to g_wpfb.nof_wb_streams-1 generate
+ wire_fft_in_wideband: for P in 0 to g_wpfb.wb_factor-1 generate
+ fft_in_re_arr(S*g_wpfb.wb_factor + P) <= fil_out_arr(P*g_wpfb.nof_wb_streams*c_nof_complex+S*c_nof_complex);
+ fft_in_im_arr(S*g_wpfb.wb_factor + P) <= fil_out_arr(P*g_wpfb.nof_wb_streams*c_nof_complex+S*c_nof_complex+1);
+ end generate;
+ end generate;
+
+ ---------------------------------------------------------------
+ -- THE POLY PHASE FILTER
+ ---------------------------------------------------------------
+ gen_prefilter : IF g_use_prefilter = TRUE generate
+ u_filter : entity astron_filter_lib.fil_ppf_wide
+ generic map (
+ g_big_endian_wb_in => g_big_endian_wb_in,
+ g_big_endian_wb_out => false, -- reverse wideband order from big-endian [3:0] = [t0,t1,t2,t3] in fil_ppf_wide to little-endian [3:0] = [t3,t2,t1,t0] in fft_r2_wide
+ g_fil_ppf => c_fil_ppf,
+ g_fil_ppf_pipeline => g_wpfb.fil_pipeline,
+ 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_fil_coefs_mosi,
+ ram_coefs_miso => ram_fil_coefs_miso,
+ in_dat_arr => fil_in_arr,
+ in_val => fil_in_val,
+ out_dat_arr => fil_out_arr,
+ out_val => fil_out_val
+ );
+ end generate;
+
+ -- Bypass filter
+ no_prefilter : if g_use_prefilter = FALSE generate
+ fil_out_arr <= fil_in_arr;
+ fil_out_val <= fil_in_val;
+ end generate;
+
+ fft_in_val <= fil_out_val;
+
+ ---------------------------------------------------------------
+ -- THE WIDEBAND FFT
+ ---------------------------------------------------------------
+ gen_wideband_fft: if g_wpfb.wb_factor > 1 generate
+ gen_fft_r2_wide_streams: for S in 0 to g_wpfb.nof_wb_streams-1 generate
+ u_fft_r2_wide : entity astron_wb_fft_lib.fft_r2_wide
+ generic map(
+ g_fft => c_fft, -- generics for the WFFT
+ g_pft_pipeline => g_wpfb.pft_pipeline,
+ g_fft_pipeline => g_wpfb.fft_pipeline
+ )
+ port map(
+ clk => dp_clk,
+ rst => dp_rst,
+ in_re_arr => fft_in_re_arr((S+1)*g_wpfb.wb_factor-1 downto S*g_wpfb.wb_factor),
+ in_im_arr => fft_in_im_arr((S+1)*g_wpfb.wb_factor-1 downto S*g_wpfb.wb_factor),
+ in_val => fft_in_val,
+ out_re_arr => fft_out_re_arr((S+1)*g_wpfb.wb_factor-1 downto S*g_wpfb.wb_factor),
+ out_im_arr => fft_out_im_arr((S+1)*g_wpfb.wb_factor-1 downto S*g_wpfb.wb_factor),
+ out_val => fft_out_val_arr(S)
+ );
+ end generate;
+ end generate;
+
+ ---------------------------------------------------------------
+ -- THE PIPELINED FFT
+ ---------------------------------------------------------------
+ gen_pipeline_fft: if g_wpfb.wb_factor = 1 generate
+ gen_fft_r2_pipe_streams: for S in 0 to g_wpfb.nof_wb_streams-1 generate
+ u_fft_r2_pipe : entity astron_wb_fft_lib.fft_r2_pipe
+ generic map(
+ g_fft => c_fft,
+ g_dont_flip_channels => g_dont_flip_channels,
+ g_pipeline => g_wpfb.fft_pipeline
+ )
+ port map(
+ clk => dp_clk,
+ rst => dp_rst,
+ in_re => fft_in_re_arr(S)(c_fft.in_dat_w-1 downto 0),
+ in_im => fft_in_im_arr(S)(c_fft.in_dat_w-1 downto 0),
+ in_val => fft_in_val,
+ out_re => fft_out_re_arr_i(S)(c_fft.out_dat_w-1 downto 0),
+ out_im => fft_out_im_arr_i(S)(c_fft.out_dat_w-1 downto 0),
+ out_val => fft_out_val_arr(S)
+ );
+
+ fft_out_re_arr(S) <= RESIZE_SVEC_32(fft_out_re_arr_i(S)(c_fft.out_dat_w-1 downto 0));
+ fft_out_im_arr(S) <= RESIZE_SVEC_32(fft_out_im_arr_i(S)(c_fft.out_dat_w-1 downto 0));
+ end generate;
+ end generate;
+
+ ---------------------------------------------------------------
+ -- FFT CONTROL UNIT
+ ---------------------------------------------------------------
+
+ -- Capture input BSN at input sync and pass the captured input BSN it on to PFB output sync.
+ -- The FFT output valid defines PFB output sync, sop, eop.
+
+ fft_out_sosi.sync <= r.in_sosi_arr(0).sync;
+ fft_out_sosi.bsn <= r.in_sosi_arr(0).bsn;
+ fft_out_sosi.valid <= fft_out_val_arr(0);
+
+ wire_fft_out_sosi_arr : for I in 0 to g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 generate
+ fft_out_sosi_arr(I).re <= RESIZE_DP_DSP_DATA(fft_out_re_arr(I));
+ fft_out_sosi_arr(I).im <= RESIZE_DP_DSP_DATA(fft_out_im_arr(I));
+ fft_out_sosi_arr(I).valid <= fft_out_val_arr(I);
+ end generate;
+
+ u_dp_block_gen_valid_arr : ENTITY work.dp_block_gen_valid_arr
+ GENERIC MAP (
+ g_nof_streams => g_wpfb.nof_wb_streams*g_wpfb.wb_factor,
+ g_nof_data_per_block => c_nof_valid_per_block,
+ g_nof_blk_per_sync => g_wpfb.nof_blk_per_sync,
+ g_check_input_sync => false,
+ g_nof_pages_bsn => 1,
+ g_restore_global_bsn => true
+ )
+ PORT MAP (
+ rst => dp_rst,
+ clk => dp_clk,
+ -- Streaming sink
+ snk_in => fft_out_sosi,
+ snk_in_arr => fft_out_sosi_arr,
+ -- Streaming source
+ src_out_arr => pfb_out_sosi_arr,
+ -- Control
+ enable => '1'
+ );
+ end generate;
+
+ ----------------------------------------------------------------------------
+ -- Source: block generator
+ ----------------------------------------------------------------------------
+ gen_bg : if g_use_bg = TRUE generate
+ u_bg : entity astron_diagnostics_lib.mms_diag_block_gen
+ generic map(
+ g_nof_streams => g_wpfb.nof_wb_streams*g_wpfb.wb_factor,
+ g_buf_dat_w => c_nof_complex*g_wpfb.fft_out_dat_w,
+ g_buf_addr_w => c_bg_buf_adr_w, -- Waveform buffer size 2**g_buf_addr_w nof samples
+ g_file_index_arr => c_bg_data_file_index_arr,
+ g_file_name_prefix => c_bg_data_file_prefix
+ )
+ port map(
+ -- System
+ mm_rst => mm_rst,
+ mm_clk => mm_clk,
+ dp_rst => dp_rst,
+ dp_clk => dp_clk,
+ en_sync => '0',
+ -- MM interface
+ reg_bg_ctrl_mosi => reg_bg_ctrl_mosi,
+ reg_bg_ctrl_miso => reg_bg_ctrl_miso,
+ ram_bg_data_mosi => ram_bg_data_mosi,
+ ram_bg_data_miso => ram_bg_data_miso,
+ -- ST interface
+ out_sosi_arr => pfb_out_sosi_arr
+ );
+ end generate;
+
+ ---------------------------------------------------------------
+ -- SUBBAND STATISTICS
+ ---------------------------------------------------------------
+ -- For all "wb_factor"x"nof_wb_streams" output streams of the
+ -- wideband FFT a subband statistics unit is placed if the
+ -- g_stats_ena is TRUE.
+ -- Since the subband statistics module uses embedded DSP blocks
+ -- for multiplication, the incoming data cannot be wider
+ -- than 18 bit.
+ gen_stats : if g_stats_ena = TRUE generate
+ gen_stats_streams: for S in 0 to g_wpfb.nof_wb_streams-1 generate
+ gen_stats_wideband: for P in 0 to g_wpfb.wb_factor-1 generate
+ u_subband_stats : entity astron_statistics_lib.st_sst
+ generic map(
+ g_nof_stat => c_nof_stats,
+ g_in_data_w => g_wpfb.fft_out_dat_w,
+ g_stat_data_w => g_wpfb.stat_data_w,
+ g_stat_data_sz => g_wpfb.stat_data_sz
+ )
+ port map (
+ mm_rst => mm_rst,
+ mm_clk => mm_clk,
+ dp_rst => dp_rst,
+ dp_clk => dp_clk,
+ in_complex => pfb_out_sosi_arr(S*g_wpfb.wb_factor+P),
+ ram_st_sst_mosi => ram_st_sst_mosi_arr(S*g_wpfb.wb_factor+P),
+ ram_st_sst_miso => ram_st_sst_miso_arr(S*g_wpfb.wb_factor+P)
+ );
+ end generate;
+ end generate;
+ end generate;
+
+ -- Connect to the outside world
+ out_sosi_arr <= pfb_out_sosi_arr;
+
+end str;
+
+
+