Skip to content
Snippets Groups Projects
Commit cde35d38 authored by Reinier van der Walle's avatar Reinier van der Walle
Browse files

Merge branch 'master' into L2SDP-605

parents 8d62d722 4355ee54
Branches
No related tags found
1 merge request!206Corrected lofar2_unb2c_sdp_station_full top-level and revision pkg.
Pipeline #25559 passed
Showing
with 1181 additions and 25 deletions
......@@ -45,6 +45,7 @@ synth_files =
src/vhdl/common_ddio_in.vhd
src/vhdl/common_ddio_out.vhd
src/vhdl/common_create_strobes_from_valid.vhd
src/vhdl/common_wideband_data_scope.vhd
src/vhdl/common_iobuf_in.vhd
#$UNB/Firmware/modules/common/src/vhdl/common_iobuf_in_a_stratix4.vhd
......@@ -195,6 +196,7 @@ test_bench_files =
tb/vhdl/tb_common_to_sreal.vhd
tb/vhdl/tb_delta_cycle_demo.vhd
tb/vhdl/tb_mms_common_variable_delay.vhd
tb/vhdl/tb_common_create_strobes_from_valid.vhd
tb/vhdl/tb_tb_resize.vhd
tb/vhdl/tb_tb_round.vhd
......@@ -209,6 +211,7 @@ test_bench_files =
tb/vhdl/tb_tb_common_rl.vhd
tb/vhdl/tb_tb_common_rl_register.vhd
tb/vhdl/tb_tb_common_transpose.vhd
tb/vhdl/tb_tb_common_create_strobes_from_valid.vhd
regression_test_vhdl =
tb/vhdl/tb_common_fifo_rd.vhd
......@@ -236,6 +239,7 @@ regression_test_vhdl =
tb/vhdl/tb_tb_common_rl.vhd
tb/vhdl/tb_tb_common_rl_register.vhd
tb/vhdl/tb_tb_common_transpose.vhd
tb/vhdl/tb_tb_common_create_strobes_from_valid.vhd
[modelsim_project_file]
modelsim_copy_files =
......
-------------------------------------------------------------------------------
--
-- Copyright 2022
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-------------------------------------------------------------------------------
-- Author: Eric Kooistra
-- Purpose: Create sync interval by counting input valids
-- Description:
--
-- The first out_sync is created at the first inval after rst release. The
-- subsequent out_sync are created every m in_val, at the start of a block.
--
-- n = g_nof_clk_per_block
-- m = g_nof_clk_per_sync
-- _____________________________________________________
-- in_val __|
--
-- blk_cnt | 0 | 1 | 2 | 3 | 4 |
--
-- val_cnt |0 |n |n*2 |n*3 - m | |0
-- _ _ _
-- out_sync __| |_____________________| |_______________________| |_
-- _____________________________________________________
-- out_val __|
-- _ _ _ _ _ _
-- out_sop __| |_______| |_______| |_______| |_______| |_______| |_
-- _ _ _ _ _
-- out_eop __________| |_______| |_______| |_______| |_______| |___
--
-- Remark:
-- . Use VHDL coding template from:
-- https://support.astron.nl/confluence/display/SBe/VHDL+design+patterns+for+RTL+coding
-- . The out_sop and out_eop are created as well, for reference.
-- . The out_sync1 for LOFAR1 style is only avaiable if g_pipeline = TRUE,
-- because the pipeline is needed to let the out_sync1 preceed the
-- out_sop and other strobes.
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE work.common_pkg.ALL;
ENTITY common_create_strobes_from_valid IS
GENERIC (
g_pipeline : BOOLEAN := TRUE;
g_nof_clk_per_sync : NATURAL := 200*10**6;
g_nof_clk_per_block : NATURAL := 1024
);
PORT (
rst : IN STD_LOGIC := '0';
clk : IN STD_LOGIC;
in_val : IN STD_LOGIC;
out_val : OUT STD_LOGIC;
out_sop : OUT STD_LOGIC;
out_eop : OUT STD_LOGIC;
out_sync : OUT STD_LOGIC; -- DP style: sync at sop
out_sync1 : OUT STD_LOGIC -- LOFAR1 style: sync before sop
);
END common_create_strobes_from_valid;
ARCHITECTURE rtl OF common_create_strobes_from_valid IS
TYPE t_state IS RECORD -- function state registers
val_cnt : NATURAL RANGE 0 TO g_nof_clk_per_sync-1;
blk_cnt : NATURAL RANGE 0 TO g_nof_clk_per_block-1;
END RECORD;
TYPE t_outputs IS RECORD -- copy of entity outputs
out_val : STD_LOGIC;
out_sop : STD_LOGIC;
out_eop : STD_LOGIC;
out_sync : STD_LOGIC;
END RECORD;
CONSTANT c_state_rst : t_state := (val_cnt => 0, blk_cnt => 0);
CONSTANT c_outputs_rst : t_outputs := ('0', '0', '0', '0');
SIGNAL q : t_state := c_state_rst; -- stored state with latency one
SIGNAL d : t_state := c_state_rst; -- zero latency state
SIGNAL o : t_outputs := c_outputs_rst; -- zero latency outputs
SIGNAL p : t_outputs := c_outputs_rst; -- pipelined outputs
BEGIN
-- p_state
q <= d WHEN rising_edge(clk);
p_comb : PROCESS(rst, q, in_val)
VARIABLE v : t_state;
BEGIN
-- Default
v := q;
o.out_val <= in_val;
o.out_sop <= '0';
o.out_eop <= '0';
o.out_sync <= '0';
-- Function
IF in_val = '1' THEN
-- maintain in_val counters
IF q.val_cnt >= g_nof_clk_per_sync-1 THEN
v.val_cnt := 0;
ELSE
v.val_cnt := v.val_cnt + 1;
END IF;
IF q.blk_cnt >= g_nof_clk_per_block-1 THEN
v.blk_cnt := 0;
ELSE
v.blk_cnt := v.blk_cnt + 1;
END IF;
-- create out_sop at start of block
IF q.blk_cnt = 0 THEN
o.out_sop <= '1';
END IF;
-- create out_eop at end of block
IF q.blk_cnt = g_nof_clk_per_block-1 THEN
o.out_eop <= '1';
END IF;
-- create out_sync at start of first block of sync interval
IF q.blk_cnt = 0 AND q.val_cnt < g_nof_clk_per_block THEN
o.out_sync <= '1';
END IF;
END IF;
-- Reset
IF rst = '1' THEN
v := c_state_rst;
END IF;
-- Result
d <= v;
END PROCESS;
-- Output
p <= o WHEN rising_edge(clk);
out_val <= o.out_val WHEN g_pipeline = FALSE ELSE p.out_val;
out_sop <= o.out_sop WHEN g_pipeline = FALSE ELSE p.out_sop;
out_eop <= o.out_eop WHEN g_pipeline = FALSE ELSE p.out_eop;
out_sync <= o.out_sync WHEN g_pipeline = FALSE ELSE p.out_sync;
out_sync1 <= '0' WHEN g_pipeline = FALSE ELSE o.out_sync;
END rtl;
......@@ -2177,9 +2177,8 @@ PACKAGE BODY common_pkg IS
END;
FUNCTION INCR_SVEC(vec : STD_LOGIC_VECTOR; dec : INTEGER) RETURN STD_LOGIC_VECTOR IS
VARIABLE v_dec : INTEGER;
BEGIN
RETURN STD_LOGIC_VECTOR(SIGNED(vec) + v_dec); -- uses function "+" (L : SIGNED, R : INTEGER)
RETURN STD_LOGIC_VECTOR(SIGNED(vec) + dec); -- uses function "+" (L : SIGNED, R : INTEGER)
END;
FUNCTION INCR_SVEC(vec : STD_LOGIC_VECTOR; dec : SIGNED) RETURN STD_LOGIC_VECTOR IS
......
-------------------------------------------------------------------------------
--
-- Copyright 2022
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-------------------------------------------------------------------------------
-- Author: Eric Kooistra
-- Purpose: Self checking and self-stopping tb for common_create_strobes_from_valid.vhd
-- Usage:
-- > as 3
-- > run -a
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE work.common_pkg.ALL;
USE work.tb_common_pkg.ALL;
ENTITY tb_common_create_strobes_from_valid IS
GENERIC (
g_pipeline : BOOLEAN := FALSE;
g_in_val_gaps : BOOLEAN := TRUE;
g_nof_clk_per_sync : NATURAL := 10;
g_nof_clk_per_block : NATURAL := 5
);
END tb_common_create_strobes_from_valid;
ARCHITECTURE tb OF tb_common_create_strobes_from_valid IS
CONSTANT clk_period : TIME := 10 ns;
CONSTANT c_nof_block_per_sync_max : NATURAL := ceil_div(g_nof_clk_per_sync, g_nof_clk_per_block);
CONSTANT c_nof_block_per_sync_min : NATURAL := g_nof_clk_per_sync / g_nof_clk_per_block;
CONSTANT c_fractional : BOOLEAN := c_nof_block_per_sync_min /= c_nof_block_per_sync_max;
CONSTANT c_nof_sync : NATURAL := sel_a_b(c_fractional, g_nof_clk_per_block, 1) * 3;
SIGNAL tb_end : STD_LOGIC := '0';
SIGNAL rst : STD_LOGIC := '1';
SIGNAL clk : STD_LOGIC := '0';
SIGNAL in_val : STD_LOGIC := '0';
SIGNAL out_val : STD_LOGIC;
SIGNAL out_sop : STD_LOGIC;
SIGNAL out_eop : STD_LOGIC;
SIGNAL out_sync : STD_LOGIC;
SIGNAL out_val_cnt : NATURAL := 0;
BEGIN
clk <= NOT clk OR tb_end AFTER clk_period/2;
p_in_stimuli : PROCESS
BEGIN
rst <= '1';
proc_common_wait_some_cycles(clk, 10);
rst <= '0';
proc_common_wait_some_cycles(clk, 10);
FOR I IN 0 TO c_nof_sync-1 LOOP
FOR J IN 0 TO c_nof_block_per_sync_max-1 LOOP
FOR K IN 0 TO g_nof_clk_per_block-1 LOOP
IF g_in_val_gaps AND K = 0 THEN
in_val <= '0'; -- insert a one cycle gap
proc_common_wait_some_cycles(clk, 1);
END IF;
in_val <= '1';
proc_common_wait_some_cycles(clk, 1);
END LOOP;
END LOOP;
END LOOP;
proc_common_wait_some_cycles(clk, g_nof_clk_per_sync*2);
tb_end <= '1';
WAIT;
END PROCESS;
out_val_cnt <= out_val_cnt + 1 WHEN rising_edge(clk) AND out_val = '1';
p_verify : PROCESS(clk)
BEGIN
IF rising_edge(clk) THEN
IF out_val = '1' THEN
-- Verify out_eop
IF out_val_cnt MOD g_nof_clk_per_block = g_nof_clk_per_block-1 THEN
ASSERT out_eop = '1' REPORT "Missing out_eop." SEVERITY ERROR;
ELSE
ASSERT out_eop = '0' REPORT "Unexpected out_eop." SEVERITY ERROR;
END IF;
-- Verify out_sop
IF out_val_cnt MOD g_nof_clk_per_block = 0 THEN
ASSERT out_sop = '1' REPORT "Missing out_sop." SEVERITY ERROR;
ELSE
ASSERT out_sop = '0' REPORT "Unexpected out_sop." SEVERITY ERROR;
END IF;
-- Verify out_sync
IF out_val_cnt MOD g_nof_clk_per_block = 0 THEN
IF out_val_cnt MOD g_nof_clk_per_sync <= g_nof_clk_per_block-1 THEN
ASSERT out_sync = '1' REPORT "Missing out_sync." SEVERITY ERROR;
ELSE
ASSERT out_sync = '0' REPORT "Unexpected out_sync." SEVERITY ERROR;
END IF;
ELSE
ASSERT out_sync = '0' REPORT "Unexpected out_sync." SEVERITY ERROR;
END IF;
ELSE
-- Illegal strobe when out_val = '0'
ASSERT out_eop = '0' REPORT "Illegal out_eop." SEVERITY ERROR;
ASSERT out_sop = '0' REPORT "Illegal out_sop." SEVERITY ERROR;
ASSERT out_sync = '0' REPORT "Illegal out_sync." SEVERITY ERROR;
END IF;
END IF;
END PROCESS;
u_in_sync : ENTITY work.common_create_strobes_from_valid
GENERIC MAP (
g_pipeline => g_pipeline,
g_nof_clk_per_sync => g_nof_clk_per_sync,
g_nof_clk_per_block => g_nof_clk_per_block
)
PORT MAP (
rst => rst,
clk => clk,
in_val => in_val,
out_val => out_val,
out_sop => out_sop,
out_eop => out_eop,
out_sync => out_sync
);
END tb;
-------------------------------------------------------------------------------
--
-- Copyright 2022
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-------------------------------------------------------------------------------
-- Author: Eric Kooistra
-- Purpose: Multi tb for common_create_strobes_from_valid.vhd
-- Usage:
-- > as 3
-- > run -a
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY tb_tb_common_create_strobes_from_valid IS
END tb_tb_common_create_strobes_from_valid;
ARCHITECTURE tb OF tb_tb_common_create_strobes_from_valid IS
SIGNAL tb_end : STD_LOGIC := '0'; -- declare tb_end to avoid 'No objects found' error on 'when -label tb_end'
BEGIN
-- g_pipeline : BOOLEAN := FALSE;
-- g_in_val_gaps : BOOLEAN := FALSE;
-- g_nof_clk_per_sync : NATURAL := 17;
-- g_nof_clk_per_block : NATURAL := 7
u_integer_interval : ENTITY work.tb_common_create_strobes_from_valid GENERIC MAP (FALSE, FALSE, 10, 5);
u_integer_interval_with_gaps : ENTITY work.tb_common_create_strobes_from_valid GENERIC MAP (FALSE, TRUE, 10, 5);
u_integer_interval_with_gaps_pipe : ENTITY work.tb_common_create_strobes_from_valid GENERIC MAP ( TRUE, TRUE, 10, 5);
u_fractional_interval : ENTITY work.tb_common_create_strobes_from_valid GENERIC MAP (FALSE, FALSE, 17, 7);
u_fractional_interval_with_gaps : ENTITY work.tb_common_create_strobes_from_valid GENERIC MAP (FALSE, TRUE, 17, 7);
u_fractional_interval_with_gaps_pipe : ENTITY work.tb_common_create_strobes_from_valid GENERIC MAP ( TRUE, TRUE, 17, 7);
END tb;
......@@ -6,6 +6,9 @@ hdl_lib_technology =
synth_files =
src/vhdl/fft_pkg.vhd
src/vhdl/fft_lfsr.vhd
src/vhdl/fft_switch.vhd
src/vhdl/fft_unswitch.vhd
src/vhdl/fft_sepa.vhd
src/vhdl/fft_reorder_sepa_pipe.vhd
src/vhdl/fft_sepa_wide.vhd
......@@ -19,6 +22,7 @@ synth_files =
test_bench_files =
tb/vhdl/tb_fft_pkg.vhd
tb/vhdl/tb_fft_functions.vhd
tb/vhdl/tb_fft_switch.vhd
tb/vhdl/tb_fft_sepa.vhd
tb/vhdl/tb_fft_reorder_sepa_pipe.vhd
tb/vhdl/tb_fft_r2_bf_par.vhd
......@@ -33,6 +37,7 @@ test_bench_files =
tb/vhdl/tb_tb_fft_r2_wide.vhd
regression_test_vhdl =
tb/vhdl/tb_fft_switch.vhd
tb/vhdl/tb_tb_fft_r2_pipe.vhd
tb/vhdl/tb_tb_fft_r2_par.vhd
tb/vhdl/tb_tb_fft_r2_wide.vhd
......
-------------------------------------------------------------------------------
--
-- Copyright 2021
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-------------------------------------------------------------------------------
--
-- Author: ported by E. Kooistra, original 2004 by W. Lubberhuizen / W. Poeisz
-- Purpose: Scramble quantization noise crosstalk between two real inputs
-- Description: Ported from LOFAR1, see readme_lofar1.txt
-- Remark: Copy from applications/lofar1/RSP/pft2/src/vhdl/pft_lfsr.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY fft_lfsr IS
PORT (
in_en : IN STD_LOGIC;
out_bit1 : OUT STD_LOGIC;
out_bit2 : OUT STD_LOGIC;
clk : IN STD_LOGIC;
rst : IN STD_LOGIC
);
END fft_lfsr;
ARCHITECTURE rtl OF fft_lfsr IS
-- uses preferred pair of pritive trinomials
-- x^41 + x^20 + 1 and x^41 + x^3 + 1
-- see XAPP217
CONSTANT c_max : NATURAL := 41;
CONSTANT c1 : NATURAL := 20;
CONSTANT c2 : NATURAL := 3;
SIGNAL s1 : STD_LOGIC_VECTOR(c_max-1 DOWNTO 0);
SIGNAL nxt_s1 : STD_LOGIC_VECTOR(c_max-1 DOWNTO 0);
SIGNAL s2 : STD_LOGIC_VECTOR(c_max-1 DOWNTO 0);
SIGNAL nxt_s2 : STD_LOGIC_VECTOR(c_max-1 DOWNTO 0);
BEGIN
p_reg : PROCESS(rst,clk)
BEGIN
IF rst='1' THEN
s1 <= "01000101011101110101001011111000101100001";
s2 <= "11011001000101001011011001110101100101100";
ELSIF rising_edge(clk) THEN
s1 <= nxt_s1;
s2 <= nxt_s2;
END IF;
END PROCESS;
out_bit1 <= s1(s1'HIGH);
out_bit2 <= s2(s2'HIGH);
p_seed : PROCESS(in_en,s1,s2)
BEGIN
nxt_s1 <= s1;
nxt_s2 <= s2;
IF in_en='1' THEN
-- shift
nxt_s1(c_max-1 DOWNTO 1) <= s1(c_max-2 DOWNTO 0);
nxt_s2(c_max-1 DOWNTO 1) <= s2(c_max-2 DOWNTO 0);
-- feedback 1
nxt_s1(0) <= s1(c_max-1);
nxt_s2(0) <= s2(c_max-1);
-- feedback 2
nxt_s1(c1) <= s1(c_max-1) xor s1(c1-1);
nxt_s2(c2) <= s2(c_max-1) xor s2(c2-1);
END IF;
END PROCESS;
end rtl;
......@@ -39,7 +39,14 @@
-- an alternating way: A(0), B(0), A(1), B(1).... etc
--
--
-- Remarks: When g_fft.nof_chan is used the spectrums at the output will be interleaved
-- Remarks:
-- . When g_fft.use_separate = TRUE, then the two real inputs are pseudo randomly
-- multiplied by +1 or -1 every block of input samples in fft_switch. At the
-- FFT output this is undone by fft_unswitch. In this way any crosstalk due
-- to quantization noise between the two real inputs gets scrambled and thus
-- averages to zero when integrated over multiple blocks.
--
-- . When g_fft.nof_chan is used the spectrums at the output will be interleaved
-- per spectrum and NOT per sample. So in case g_fft.nof_chan = 1 there will be
-- two multiplexed channels at the input (c0t0 means channel 0, timestamp 0) :
--
......@@ -81,6 +88,10 @@ architecture str of fft_r2_pipe is
constant c_pipeline_remove_lsb : natural := 0;
constant c_switch_en : boolean := g_fft.use_separate; -- default do apply switch/unswitch per real input to mitigate quantization crosstalk
constant c_switch_sz_w : natural := ceil_log2(g_fft.nof_points) + g_fft.nof_chan;
constant c_switch_dat_w : natural := g_fft.in_dat_w + 1; -- add 1 extra bit to fit negation of most negative value per real input switch function
constant c_unswitch_dat_w : natural := g_fft.out_dat_w; -- no need for extra bit, because most negative value cannot occur in output
constant c_nof_stages : natural := ceil_log2(g_fft.nof_points);
constant c_stage_offset : natural := true_log2(g_fft.wb_factor); -- Stage offset is required for twiddle generation in wideband fft
constant c_in_scale_w : natural := g_fft.stage_dat_w - g_fft.in_dat_w - sel_a_b(g_fft.guard_enable, g_fft.guard_w, 0);
......@@ -93,6 +104,14 @@ architecture str of fft_r2_pipe is
-- . the data output of the last stage has index 0
type t_data_arr is array(c_nof_stages downto 0) of std_logic_vector(g_fft.stage_dat_w-1 downto 0);
signal in_dat_re : std_logic_vector(c_switch_dat_w-1 downto 0);
signal in_dat_im : std_logic_vector(c_switch_dat_w-1 downto 0);
signal in_dat_val : std_logic;
signal switch_re : std_logic_vector(c_switch_dat_w-1 downto 0);
signal switch_im : std_logic_vector(c_switch_dat_w-1 downto 0);
signal switch_val : std_logic;
signal data_re : t_data_arr;
signal data_im : t_data_arr;
signal last_re : std_logic_vector(c_raw_dat_w-1 downto 0);
......@@ -105,12 +124,42 @@ architecture str of fft_r2_pipe is
signal raw_out_im : std_logic_vector(c_raw_dat_w-1 downto 0);
signal raw_out_val : std_logic;
signal quant_re : std_logic_vector(g_fft.out_dat_w-1 downto 0);
signal quant_im : std_logic_vector(g_fft.out_dat_w-1 downto 0);
signal quant_val : std_logic;
begin
------------------------------------------------------------------------------
-- Mitigate quantization noise crosstalk between two real inputs by negating
-- the inputs per lock in a random pattern, when g_fft.use_separate = TRUE.
------------------------------------------------------------------------------
-- Inputs
data_re( c_nof_stages) <= scale_and_resize_svec(in_re, c_in_scale_w, g_fft.stage_dat_w);
data_im( c_nof_stages) <= scale_and_resize_svec(in_im, c_in_scale_w, g_fft.stage_dat_w);
data_val(c_nof_stages) <= in_val;
in_dat_re <= RESIZE_SVEC(in_re, c_switch_dat_w);
in_dat_im <= RESIZE_SVEC(in_im, c_switch_dat_w);
in_dat_val <= in_val;
u_switch : ENTITY work.fft_switch
GENERIC MAP (
g_switch_en => c_switch_en,
g_fft_sz_w => c_switch_sz_w,
g_dat_w => c_switch_dat_w
)
PORT MAP (
in_re => in_dat_re,
in_im => in_dat_im,
in_val => in_dat_val,
out_re => switch_re,
out_im => switch_im,
out_val => switch_val,
clk => clk,
rst => rst
);
data_re( c_nof_stages) <= scale_and_resize_svec(switch_re, c_in_scale_w, g_fft.stage_dat_w);
data_im( c_nof_stages) <= scale_and_resize_svec(switch_im, c_in_scale_w, g_fft.stage_dat_w);
data_val(c_nof_stages) <= switch_val;
------------------------------------------------------------------------------
-- pipelined FFT stages
......@@ -155,12 +204,11 @@ begin
in_re => data_re(1),
in_im => data_im(1),
in_val => data_val(1),
out_re => last_re,
out_im => last_im,
out_re => last_re, -- = data_re(0), but may instead have c_raw_dat_w bits
out_im => last_im, -- = data_im(0), but may instead have c_raw_dat_w bits
out_val => data_val(0)
);
------------------------------------------------------------------------------
-- Optional output reorder and separation
------------------------------------------------------------------------------
......@@ -190,7 +238,7 @@ begin
end generate;
no_reorder_no_generate : if(g_fft.use_separate=false and g_fft.use_reorder=false) generate
no_reorder_no_seperate : if(g_fft.use_separate=false and g_fft.use_reorder=false) generate
raw_out_re <= last_re;
raw_out_im <= last_im;
raw_out_val <= data_val(0);
......@@ -215,7 +263,7 @@ begin
port map (
clk => clk,
in_dat => raw_out_re,
out_dat => out_re,
out_dat => quant_re,
out_ovr => open
);
......@@ -235,7 +283,7 @@ begin
port map (
clk => clk,
in_dat => raw_out_im,
out_dat => out_im,
out_dat => quant_im,
out_ovr => open
);
......@@ -248,7 +296,25 @@ begin
rst => rst,
clk => clk,
in_dat => raw_out_val,
out_dat => out_val
out_dat => quant_val
);
-- Undo input random negation of u_switch at output when g_fft.use_separate = TRUE
u_unswitch : ENTITY work.fft_unswitch
GENERIC MAP (
g_switch_en => c_switch_en,
g_fft_sz_w => c_switch_sz_w,
g_dat_w => c_unswitch_dat_w
)
PORT MAP (
in_re => quant_re,
in_im => quant_im,
in_val => quant_val,
out_re => out_re,
out_im => out_im,
out_val => out_val,
clk => clk,
rst => rst
);
end str;
......
-------------------------------------------------------------------------------
--
-- Copyright 2021
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-------------------------------------------------------------------------------
--
-- Author: ported by E. Kooistra, original 2004 by W. Lubberhuizen / W. Poeisz
-- Purpose: Scramble quantization noise crosstalk between two real inputs
-- Description:
-- . Ported from LOFAR1, see readme_lofar1.txt
-- . The fft_switch multiplies the samples from two real inputs A and B in a
-- block by +1 or -1. The fft_unswitch undoes this by multiplying the FFT
-- output again by +1 and -1. The fft_unswitch takes account of that the FFT
-- has time mutliplexed the two spectra of the two inputs.
-- . The input switching is pseudo random base on a LFSR (linear feedback
-- shift register) sequence. The fft_switch and fft_unswitch start at the
-- first in_val = '1' and then continue 'forever' until a next power cycle
-- by rst ='1'.
-- Remark:
-- . Copy from applications/lofar1/RSP/pft2/src/vhdl/pft_switch.vhd
-- . Removed in_sync, because the in_val are guaranteed to arrive in blocks of
-- c_nof_clk_per_block samples, forever after rst release.
-- The purpose of the in_sync is to recover from an fractional input block,
-- but that cannot occur. The other parts of the FFT also rely on this block
-- processing, without need for in_sync to recover from fractional blocks.
-- The application that uses the FFT must guarantee to only pass on complete
-- blocks of c_nof_clk_per_block samples to the FFT.
-- . The two real inputs each use another LFSR sequence, like for LOFAR1.
-- For the crosstalk mitigation purpose scrambling only one input would be
-- enough, but scrambling both inputs is fine too.
LIBRARY IEEE, common_lib;
USE IEEE.std_logic_1164.ALL;
USE common_lib.common_pkg.ALL;
ENTITY fft_switch IS
GENERIC (
g_switch_en : BOOLEAN := FALSE;
g_fft_sz_w : NATURAL;
g_dat_w : NATURAL
);
PORT (
in_re : IN STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0); -- real input A
in_im : IN STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0); -- real input B
in_val : IN STD_LOGIC;
out_re : OUT STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0);
out_im : OUT STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0);
out_val : OUT STD_LOGIC;
clk : IN STD_LOGIC;
rst : IN STD_LOGIC
);
END fft_switch;
ARCHITECTURE rtl OF fft_switch IS
CONSTANT c_nof_clk_per_block : NATURAL := 2**g_fft_sz_w;
SIGNAL in_sop : STD_LOGIC;
SIGNAL in_eop : STD_LOGIC;
SIGNAL cnt : STD_LOGIC_VECTOR(g_fft_sz_w DOWNTO 0) := (OTHERS => '0');
SIGNAL nxt_cnt : STD_LOGIC_VECTOR(cnt'RANGE);
SIGNAL lfsr_bit1 : STD_LOGIC;
SIGNAL lfsr_bit2 : STD_LOGIC;
SIGNAL lfsr_en : STD_LOGIC;
SIGNAL nxt_out_re : STD_LOGIC_VECTOR(in_re'RANGE);
SIGNAL nxt_out_im : STD_LOGIC_VECTOR(in_im'RANGE);
BEGIN
-- Create input strobes to view data blocks for debugging
u_in_strobes : ENTITY common_lib.common_create_strobes_from_valid
GENERIC MAP (
g_pipeline => FALSE,
g_nof_clk_per_sync => c_nof_clk_per_block * 16, -- void value, sync is not used
g_nof_clk_per_block => c_nof_clk_per_block
)
PORT MAP (
rst => rst,
clk => clk,
in_val => in_val,
out_val => OPEN, -- out_val = in_val, because g_pipeline = FALSE
out_sop => in_sop,
out_eop => in_eop,
out_sync => OPEN
);
no_switch : IF g_switch_en = FALSE GENERATE
-- wire inputs to outputs
out_re <= in_re;
out_im <= in_im;
out_val <= in_val;
END GENERATE;
gen_switch : IF g_switch_en = TRUE GENERATE
p_reg : PROCESS (rst, clk)
BEGIN
IF rst = '1' THEN
cnt <= (OTHERS => '0');
out_val <= '0';
out_re <= (OTHERS => '0');
out_im <= (OTHERS => '0');
ELSIF rising_edge(clk) THEN
cnt <= nxt_cnt;
out_val <= in_val;
out_re <= nxt_out_re;
out_im <= nxt_out_im;
END IF;
END PROCESS;
p_counter: PROCESS(cnt, in_val)
BEGIN
nxt_cnt <= cnt;
IF in_val = '1' THEN
nxt_cnt <= INCR_UVEC(cnt, 1);
END IF;
END PROCESS;
p_lfsr_ctrl: PROCESS(cnt, in_val)
BEGIN
if TO_SINT(cnt) = -1 AND in_val = '1' THEN
lfsr_en <= '1';
ELSE
lfsr_en <= '0';
END IF;
END PROCESS;
p_out: PROCESS(in_re, in_im, cnt, lfsr_bit1, lfsr_bit2)
BEGIN
nxt_out_re <= in_re;
nxt_out_im <= in_im;
IF lfsr_bit1 = cnt(cnt'HIGH) THEN
nxt_out_re <= NEGATE_SVEC(in_re, g_dat_w); -- negate block of input A samples
END IF;
IF lfsr_bit2 = cnt(cnt'HIGH) THEN
nxt_out_im <= NEGATE_SVEC(in_im, g_dat_w); -- negate block of input B samples
END IF;
END PROCESS;
u_fft_lfsr: ENTITY work.fft_lfsr
PORT MAP (
clk => clk,
rst => rst,
in_en => lfsr_en,
out_bit1 => lfsr_bit1,
out_bit2 => lfsr_bit2
);
END GENERATE;
END rtl;
-------------------------------------------------------------------------------
--
-- Copyright 2021
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-------------------------------------------------------------------------------
--
-- Author: ported by E. Kooistra, original 2004 by W. Lubberhuizen / W. Poeisz
-- Purpose: Scramble quantization noise crosstalk between two real inputs
-- Description:
-- . Ported from LOFAR1, see readme_lofar1.txt
-- . See fft_switch.vhd
-- Remark:
-- . Copy from applications/lofar1/RSP/pft2/src/vhdl/pft_unswitch.vhd
-- . Removed in_sync, because the in_val are guaranteed to arrive in blocks of
-- c_nof_clk_per_block samples, forever after rst release.
LIBRARY IEEE, common_lib;
USE IEEE.std_logic_1164.ALL;
USE common_lib.common_pkg.ALL;
ENTITY fft_unswitch IS
GENERIC (
g_switch_en : BOOLEAN := FALSE;
g_fft_sz_w : NATURAL;
g_dat_w : NATURAL
);
PORT (
in_re : IN STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0);
in_im : IN STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0);
in_val : IN STD_LOGIC;
out_re : OUT STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0);
out_im : OUT STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0);
out_val : OUT STD_LOGIC;
clk : IN STD_LOGIC;
rst : IN STD_LOGIC
);
END fft_unswitch;
ARCHITECTURE rtl OF fft_unswitch IS
CONSTANT c_nof_clk_per_block : NATURAL := 2**g_fft_sz_w;
SIGNAL in_sop : STD_LOGIC;
SIGNAL in_eop : STD_LOGIC;
SIGNAL cnt : STD_LOGIC_VECTOR(g_fft_sz_w DOWNTO 0) := (OTHERS => '0');
SIGNAL nxt_cnt : STD_LOGIC_VECTOR(cnt'RANGE);
SIGNAL lfsr_bit1 : STD_LOGIC;
SIGNAL lfsr_bit2 : STD_LOGIC;
SIGNAL lfsr_en : STD_LOGIC;
SIGNAL nxt_out_re : STD_LOGIC_VECTOR(in_re'RANGE);
SIGNAL nxt_out_im : STD_LOGIC_VECTOR(in_im'RANGE);
BEGIN
-- Create input strobes to view data blocks for debugging
u_in_strobes : ENTITY common_lib.common_create_strobes_from_valid
GENERIC MAP (
g_pipeline => FALSE,
g_nof_clk_per_sync => c_nof_clk_per_block * 16, -- void value, sync is not used
g_nof_clk_per_block => c_nof_clk_per_block
)
PORT MAP (
rst => rst,
clk => clk,
in_val => in_val,
out_val => OPEN, -- out_val = in_val, because g_pipeline = FALSE
out_sop => in_sop,
out_eop => in_eop,
out_sync => OPEN
);
no_switch : IF g_switch_en = FALSE GENERATE
-- wire inputs to outputs
out_re <= in_re;
out_im <= in_im;
out_val <= in_val;
END GENERATE;
gen_switch : IF g_switch_en = TRUE GENERATE
p_reg : PROCESS (rst, clk)
BEGIN
IF rst = '1' THEN
cnt <= (OTHERS => '0');
out_val <= '0';
out_re <= (OTHERS => '0');
out_im <= (OTHERS => '0');
ELSIF rising_edge(clk) THEN
cnt <= nxt_cnt;
out_val <= in_val;
out_re <= nxt_out_re;
out_im <= nxt_out_im;
END IF;
END PROCESS;
p_counter: PROCESS(cnt, in_val)
BEGIN
nxt_cnt <= cnt;
IF in_val = '1' THEN
nxt_cnt <= INCR_UVEC(cnt, 1);
END IF;
END PROCESS;
p_lfsr_ctrl: PROCESS(cnt, in_val)
BEGIN
if TO_SINT(cnt) = -1 AND in_val = '1' THEN
lfsr_en <= '1';
ELSE
lfsr_en <= '0';
END IF;
END PROCESS;
p_out: PROCESS(in_re, in_im, cnt, lfsr_bit1, lfsr_bit2)
BEGIN
nxt_out_re <= in_re;
nxt_out_im <= in_im;
-- multiplexed spectrum for input A at index 0, B at index 1
IF cnt(0) = '0' THEN
IF cnt(cnt'HIGH) = lfsr_bit1 THEN -- negate spectrum to undo negate of block of real input A
nxt_out_re <= NEGATE_SVEC(in_re, g_dat_w);
nxt_out_im <= NEGATE_SVEC(in_im, g_dat_w);
END IF;
ELSE
IF cnt(cnt'HIGH) = lfsr_bit2 THEN -- negate spectrum to undo negate of block of real input B
nxt_out_re <= NEGATE_SVEC(in_re, g_dat_w);
nxt_out_im <= NEGATE_SVEC(in_im, g_dat_w);
END IF;
END IF;
END PROCESS;
u_fft_lfsr: ENTITY work.fft_lfsr
PORT MAP (
clk => clk,
rst => rst,
in_en => lfsr_en,
out_bit1 => lfsr_bit1,
out_bit2 => lfsr_bit2
);
END GENERATE;
END rtl;
-------------------------------------------------------------------------------
--
-- Copyright 2022
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-------------------------------------------------------------------------------
--
-- Author: E. Kooistra
-- Purpose: Tb for fft_switch.vhd + fft_unswitch.vhd
-- Description:
--
-- p_in_val --> u_fft_switch --> mux --> u_fft_unswitch --> demux --> p_verify
--
-- . p_in_val creates blocks of in_val, with or without g_in_val_gaps
-- . in_a and in_b are offset counter data that increment at in_val
-- . fft_switch uses an lfsr per input to randomly negate or keep the input
-- . mux models that the FFT complex output is multiplexes a, b in time
-- . fft_unswitch use the same lfsr as fft_switch to undo the random negate
-- on the multiplexed a, b output
-- . demux demultiplexes the output so that it can be compared to the delayed
-- input
-- . p_verify checks that the output is equal to the delayed input.
--
-- Remark:
-- . The fft_switch and fft_unswitch only use in_val, the other strobes sop,
-- eop and sync are only for tb debugging purposes to recognize the in_val
-- data blocks of c_nof_clk_per_block samples in the Wave window.
-- . The g_increment_at_val determines whether the in_re, in_im increment at
-- every sample (at in_val), or at every block of samples (at in_eop).
-- Default use g_increment_at_val = TRUE. Increment at eop is for debugging
-- purposes.
--
-- Usage:
-- > as 5
-- > run -a
-- # view a,b and re,im signals in radix decimal
LIBRARY IEEE, common_lib;
USE IEEE.std_logic_1164.ALL;
USE common_lib.common_pkg.ALL;
USE common_lib.tb_common_pkg.ALL;
ENTITY tb_fft_switch IS
GENERIC (
g_switch_en : BOOLEAN := TRUE;
g_in_val_gaps : BOOLEAN := TRUE;
g_increment_at_val : BOOLEAN := TRUE;
g_fft_size_w : NATURAL := 3;
g_nof_clk_per_sync : NATURAL := 32;
g_nof_sync : NATURAL := 2
);
END tb_fft_switch;
ARCHITECTURE tb OF tb_fft_switch IS
CONSTANT clk_period : TIME := 10 ns;
CONSTANT c_dat_w : NATURAL := 16;
CONSTANT c_nof_clk_per_block : NATURAL := 2**g_fft_size_w;
CONSTANT c_nof_block_per_sync_max : NATURAL := ceil_div(g_nof_clk_per_sync, c_nof_clk_per_block);
CONSTANT c_nof_block_per_sync_min : NATURAL := g_nof_clk_per_sync / c_nof_clk_per_block;
CONSTANT c_dly : NATURAL := 4; -- pipeling in fft_switch, mux, fft_unswitch and demux
SIGNAL tb_end : STD_LOGIC := '0';
SIGNAL rst : STD_LOGIC := '1';
SIGNAL clk : STD_LOGIC := '0';
-- Use fixed input A, B values
SIGNAL in_a : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0) := TO_SVEC(3, c_dat_w);
SIGNAL in_b : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0) := TO_SVEC(13, c_dat_w);
SIGNAL in_val : STD_LOGIC := '0';
SIGNAL in_sop : STD_LOGIC := '0';
SIGNAL in_eop : STD_LOGIC := '0';
SIGNAL in_sync : STD_LOGIC := '0';
SIGNAL switch_a : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
SIGNAL switch_b : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
SIGNAL switch_val : STD_LOGIC;
SIGNAL prev1_switch_a : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
SIGNAL prev1_switch_b : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
SIGNAL prev2_switch_a : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
SIGNAL prev2_switch_b : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
SIGNAL mux_toggle : STD_LOGIC := '0';
SIGNAL mux_re : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0) := (OTHERS => '0');
SIGNAL mux_im : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0) := (OTHERS => '0');
SIGNAL mux_val : STD_LOGIC := '0';
SIGNAL unswitch_re : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
SIGNAL unswitch_im : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
SIGNAL unswitch_val : STD_LOGIC := '0';
SIGNAL prev1_unswitch_re : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
SIGNAL prev1_unswitch_im : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
SIGNAL prev2_unswitch_re : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
SIGNAL prev2_unswitch_im : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
SIGNAL out_toggle : STD_LOGIC := '0';
SIGNAL out_a : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
SIGNAL out_b : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
SIGNAL out_val : STD_LOGIC;
SIGNAL out_sop : STD_LOGIC := '0';
SIGNAL out_eop : STD_LOGIC := '0';
SIGNAL out_sync : STD_LOGIC := '0';
SIGNAL dly_val : STD_LOGIC_VECTOR(0 TO c_dly) := (OTHERS => '0');
SIGNAL dly_a : t_integer_arr(0 TO c_dly) := (OTHERS => 0);
SIGNAL dly_b : t_integer_arr(0 TO c_dly) := (OTHERS => 0);
SIGNAL exp_val : STD_LOGIC := '0';
SIGNAL exp_a : INTEGER;
SIGNAL exp_b : INTEGER;
SIGNAL verify_en : STD_LOGIC := '0';
BEGIN
clk <= NOT clk OR tb_end AFTER clk_period/2;
p_in_val : PROCESS
BEGIN
rst <= '1';
in_val <= '0';
proc_common_wait_some_cycles(clk, 10);
rst <= '0';
proc_common_wait_some_cycles(clk, 10);
FOR I IN 0 TO g_nof_sync-1 LOOP
FOR J IN 0 TO c_nof_block_per_sync_max-1 LOOP
FOR K IN 0 TO c_nof_clk_per_block-1 LOOP
IF g_in_val_gaps AND K = 0 THEN
in_val <= '0'; -- insert a one cycle gap
proc_common_wait_some_cycles(clk, 1);
END IF;
in_val <= '1';
proc_common_wait_some_cycles(clk, 1);
END LOOP;
END LOOP;
END LOOP;
proc_common_wait_some_cycles(clk, g_nof_clk_per_sync*g_nof_sync);
tb_end <= '1';
WAIT;
END PROCESS;
-- Create in strobes for debugging
u_in_strobes : ENTITY common_lib.common_create_strobes_from_valid
GENERIC MAP (
g_pipeline => FALSE,
g_nof_clk_per_sync => g_nof_clk_per_sync,
g_nof_clk_per_block => c_nof_clk_per_block
)
PORT MAP (
rst => rst,
clk => clk,
in_val => in_val,
out_val => OPEN, -- out_val = in_val, because g_pipeline = FALSE
out_sop => in_sop,
out_eop => in_eop,
out_sync => in_sync
);
gen_increment_at_val : IF g_increment_at_val = TRUE GENERATE
in_a <= INCR_SVEC(in_a, 1) WHEN rising_edge(clk) AND in_val = '1';
in_b <= INCR_SVEC(in_b, 1) WHEN rising_edge(clk) AND in_val = '1';
END GENERATE;
gen_increment_at_eop : IF g_increment_at_val = FALSE GENERATE
in_a <= INCR_SVEC(in_a, 1) WHEN rising_edge(clk) AND in_eop = '1';
in_b <= INCR_SVEC(in_b, 1) WHEN rising_edge(clk) AND in_eop = '1';
END GENERATE;
u_fft_switch : ENTITY work.fft_switch
GENERIC MAP (
g_switch_en => g_switch_en,
g_fft_sz_w => g_fft_size_w,
g_dat_w => c_dat_w
)
PORT MAP (
in_re => in_a,
in_im => in_b,
in_val => in_val,
out_re => switch_a,
out_im => switch_b,
out_val => switch_val,
clk => clk,
rst => rst
);
-- Model A, B multiplexing part of FFT
-- 0 1 2 .. N-1
-- switch_a: a0 a1 a2 .. aN-1
-- switch_b: b0 b1 b2 .. bN-1
-- prev1_switch_a: a0 a1 .. aN-1
-- prev1_switch_b: b0 b1 .. bN-1
-- prev2_switch_a: a0 .. aN-1
-- prev2_switch_b: b0 .. bN-1
-- mux_toggle: 0 1 0 1 0 .. 1 0
-- 0 1 2 3 .. N-2 N-1
-- mux_re: a0 b0 a2 b2 .. aN-2 bN-2
-- mux_im: a1 b1 a3 b3 .. aN-1 bN-1
prev1_switch_a <= switch_a WHEN rising_edge(clk) AND switch_val = '1';
prev1_switch_b <= switch_b WHEN rising_edge(clk) AND switch_val = '1';
prev2_switch_a <= prev1_switch_a WHEN rising_edge(clk) AND switch_val = '1';
prev2_switch_b <= prev1_switch_b WHEN rising_edge(clk) AND switch_val = '1';
mux_toggle <= NOT mux_toggle WHEN rising_edge(clk) AND switch_val = '1';
mux_re <= prev1_switch_a WHEN mux_toggle = '1' ELSE prev2_switch_b; -- a0, b0, ..
mux_im <= switch_a WHEN mux_toggle = '1' ELSE prev1_switch_b; -- a1, b1, ..
mux_val <= switch_val WHEN rising_edge(clk);
u_fft_unswitch : ENTITY work.fft_unswitch
GENERIC MAP (
g_switch_en => g_switch_en,
g_fft_sz_w => g_fft_size_w,
g_dat_w => c_dat_w
)
PORT MAP (
in_re => mux_re,
in_im => mux_im,
in_val => mux_val,
out_re => unswitch_re,
out_im => unswitch_im,
out_val => unswitch_val,
clk => clk,
rst => rst
);
-- Demultiplex output to ease verification
-- 0 1 2 3 .. N-2 N-1
-- unswitch_re: a0 b0 a2 b2 .. aN-2 bN-2
-- unswitch_im: a1 b1 a3 b3 .. aN-1 bN-1
-- prev1_unswitch_re: a0 b0 a2 b2 .. aN-2 bN-2
-- prev1_unswitch_im: a1 b1 a3 b3 .. aN-1 bN-1
-- prev2_unswitch_re: a0 b0 a2 b2 .. aN-2 bN-2
-- prev2_unswitch_im: a1 b1 a3 b3 .. aN-1 bN-1
-- out_toggle: 0 1 0 1 0
-- 0 1 .. N-1
-- out_a: a0 a1 ..aN-1
-- out_b: b0 b1 ..bN-1
prev1_unswitch_re <= unswitch_re WHEN rising_edge(clk) AND unswitch_val = '1';
prev1_unswitch_im <= unswitch_im WHEN rising_edge(clk) AND unswitch_val = '1';
prev2_unswitch_re <= prev1_unswitch_re WHEN rising_edge(clk) AND unswitch_val = '1';
prev2_unswitch_im <= prev1_unswitch_im WHEN rising_edge(clk) AND unswitch_val = '1';
out_toggle <= NOT out_toggle WHEN rising_edge(clk) AND unswitch_val = '1';
out_a <= prev1_unswitch_re WHEN out_toggle = '1' ELSE prev2_unswitch_im; -- a0, a1, ..
out_b <= unswitch_re WHEN out_toggle = '1' ELSE prev1_unswitch_im; -- b0, b1, ..
out_val <= unswitch_val WHEN rising_edge(clk);
-- Create out strobes for debugging
u_out_strobes : ENTITY common_lib.common_create_strobes_from_valid
GENERIC MAP (
g_pipeline => FALSE,
g_nof_clk_per_sync => g_nof_clk_per_sync,
g_nof_clk_per_block => c_nof_clk_per_block
)
PORT MAP (
rst => rst,
clk => clk,
in_val => out_val,
out_val => OPEN, -- out_val = in_val, because g_pipeline = FALSE
out_sop => out_sop,
out_eop => out_eop,
out_sync => out_sync
);
-- Account for pipeling in fft_switch, mux, fft_unswitch and demux
dly_val(0) <= in_val;
dly_a(0) <= TO_SINT(in_a);
dly_b(0) <= TO_SINT(in_b);
dly_val(1 TO c_dly) <= dly_val(0 TO c_dly-1) WHEN rising_edge(clk);
dly_a(1 TO c_dly) <= dly_a(0 TO c_dly-1) WHEN rising_edge(clk);
dly_b(1 TO c_dly) <= dly_b(0 TO c_dly-1) WHEN rising_edge(clk);
exp_val <= dly_val(c_dly);
exp_a <= dly_a(c_dly);
exp_b <= dly_b(c_dly);
verify_en <= '1' WHEN exp_val = '1';
p_verify : PROCESS(clk)
BEGIN
IF rising_edge(clk) THEN
IF verify_en = '1' THEN
IF exp_val = '1' THEN
ASSERT TO_SINT(out_a) = exp_a REPORT "Wrong out_re" SEVERITY ERROR;
ASSERT TO_SINT(out_b) = exp_b REPORT "Wrong out_im" SEVERITY ERROR;
END IF;
ASSERT out_val = exp_val REPORT "Wrong out_val" SEVERITY ERROR;
END IF;
END IF;
END PROCESS;
END tb;
......@@ -53,6 +53,7 @@ ARCHITECTURE tb OF tb_tb_fft_r2_pipe IS
-- Real input
CONSTANT c_impulse_chirp : string := "data/run_pfft_m_impulse_chirp_8b_128points_16b.dat"; -- 25600 lines
CONSTANT c_sinusoid_chirp : string := "data/run_pfft_m_sinusoid_chirp_8b_128points_16b.dat"; -- 25600 lines
CONSTANT c_sinusoid : string := "data/run_pfft_m_sinusoid_8b_128points_16b.dat"; -- 640 lines
CONSTANT c_noise : string := "data/run_pfft_m_noise_8b_128points_16b.dat"; -- 1280 lines
CONSTANT c_dc_agwn : string := "data/run_pfft_m_dc_agwn_8b_128points_16b.dat"; -- 1280 lines
-- Complex input
......@@ -104,6 +105,7 @@ BEGIN
u_act_two_real_chirp : ENTITY work.tb_fft_r2_pipe GENERIC MAP (c_fft_two_real, c_diff_margin, c_sinusoid_chirp, 25600, c_impulse_chirp, 25600, c_unused, 0, 25600, FALSE);
u_act_two_real_a0 : ENTITY work.tb_fft_r2_pipe GENERIC MAP (c_fft_two_real, c_diff_margin, c_zero, 25600, c_impulse_chirp, 25600, c_unused, 0, 5120, FALSE);
u_act_two_real_b0 : ENTITY work.tb_fft_r2_pipe GENERIC MAP (c_fft_two_real, c_diff_margin, c_sinusoid_chirp, 25600, c_zero, 25600, c_unused, 0, 5120, FALSE);
u_act_two_real_sinus : ENTITY work.tb_fft_r2_pipe GENERIC MAP (c_fft_two_real, c_diff_margin, c_sinusoid, 640, c_zero, 640, c_unused, 0, 640, FALSE);
u_rnd_two_real_noise : ENTITY work.tb_fft_r2_pipe GENERIC MAP (c_fft_two_real, c_diff_margin, c_noise, 1280, c_dc_agwn, 1280, c_unused, 0, 1280, TRUE);
u_rnd_two_real_channels : ENTITY work.tb_fft_r2_pipe GENERIC MAP (c_fft_two_real_more_channels, c_diff_margin, c_noise, 1280, c_dc_agwn, 1280, c_unused, 0, 1280, TRUE);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment