OpenCores
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; + + +

powered by: WebSVN 2.1.0

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