Skip to content
Snippets Groups Projects
Commit 2483b15d authored by Eric Kooistra's avatar Eric Kooistra
Browse files

Made tb self checking and added description.

parent 561cfcb0
Branches
No related tags found
1 merge request!205Added g_sepa_switch_en to support mitigation of quantization noise crosstalk...
Pipeline #25243 passed
...@@ -21,22 +21,45 @@ ...@@ -21,22 +21,45 @@
-- Author: E. Kooistra -- Author: E. Kooistra
-- Purpose: Tb for fft_switch.vhd + fft_unswitch.vhd -- Purpose: Tb for fft_switch.vhd + fft_unswitch.vhd
-- Description: -- 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: -- Usage:
-- > as 5 -- > as 5
-- > run -a -- > run -a
-- # view a,b and re,im signals in radix decimal
LIBRARY IEEE, common_lib, dp_lib; LIBRARY IEEE, common_lib;
USE IEEE.std_logic_1164.ALL; USE IEEE.std_logic_1164.ALL;
USE common_lib.common_pkg.ALL; USE common_lib.common_pkg.ALL;
USE common_lib.tb_common_pkg.ALL; USE common_lib.tb_common_pkg.ALL;
USE dp_lib.dp_stream_pkg.ALL;
ENTITY tb_fft_switch IS ENTITY tb_fft_switch IS
GENERIC ( GENERIC (
g_in_val_gaps : BOOLEAN := FALSE; g_in_val_gaps : BOOLEAN := TRUE;
g_increment_at_val : BOOLEAN := TRUE;
g_fft_size_w : NATURAL := 3; g_fft_size_w : NATURAL := 3;
g_nof_clk_per_sync : NATURAL := 80; g_nof_clk_per_sync : NATURAL := 32;
g_nof_sync : NATURAL := 10 g_nof_sync : NATURAL := 2
); );
END tb_fft_switch; END tb_fft_switch;
...@@ -50,47 +73,65 @@ ARCHITECTURE tb OF tb_fft_switch IS ...@@ -50,47 +73,65 @@ ARCHITECTURE tb OF tb_fft_switch IS
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_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_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 tb_end : STD_LOGIC := '0';
SIGNAL rst : STD_LOGIC := '1'; SIGNAL rst : STD_LOGIC := '1';
SIGNAL clk : STD_LOGIC := '0'; SIGNAL clk : STD_LOGIC := '0';
-- Fixed input A, B values -- Use fixed input A, B values
SIGNAL in_val : STD_LOGIC := '0';
SIGNAL in_a : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0) := TO_SVEC(3, c_dat_w); 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(4, c_dat_w); SIGNAL in_b : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0) := TO_SVEC(13, c_dat_w);
SIGNAL in_sosi : t_dp_sosi := c_dp_sosi_rst; 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_en : STD_LOGIC := '1';
SIGNAL switch_a : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 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_b : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
SIGNAL switch_en : STD_LOGIC := '1'; SIGNAL switch_val : STD_LOGIC;
SIGNAL switch_sosi : t_dp_sosi; 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_toggle : STD_LOGIC := '0';
SIGNAL mux_re : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); SIGNAL mux_re : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
SIGNAL mux_im : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); SIGNAL mux_im : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
SIGNAL mux_sosi : t_dp_sosi; SIGNAL mux_val : STD_LOGIC;
SIGNAL fft_re : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
SIGNAL fft_im : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
SIGNAL fft_sosi : t_dp_sosi;
SIGNAL unswitch_en : STD_LOGIC := '1';
SIGNAL unswitch_re : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 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_im : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
SIGNAL unswitch_sosi : t_dp_sosi; SIGNAL unswitch_val : STD_LOGIC;
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_toggle : STD_LOGIC := '0';
SIGNAL out_a : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 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_b : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0);
SIGNAL out_sosi : t_dp_sosi; 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_sosi : t_dp_sosi; SIGNAL dly_val : STD_LOGIC_VECTOR(0 TO c_dly) := (OTHERS => '0');
SIGNAL exp_sosi : t_dp_sosi; 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 BEGIN
clk <= NOT clk OR tb_end AFTER clk_period/2; clk <= NOT clk OR tb_end AFTER clk_period/2;
p_in_val_stimuli : PROCESS p_in_val : PROCESS
BEGIN BEGIN
rst <= '1'; rst <= '1';
in_val <= '0'; in_val <= '0';
...@@ -114,10 +155,10 @@ BEGIN ...@@ -114,10 +155,10 @@ BEGIN
WAIT; WAIT;
END PROCESS; END PROCESS;
-- Create sync for fft_switch -- Create in strobes for debugging
u_sync_switch : ENTITY common_lib.common_create_sync_from_valid u_in_strobes : ENTITY common_lib.common_create_strobes_from_valid
GENERIC MAP ( GENERIC MAP (
g_pipeline => TRUE, g_pipeline => FALSE,
g_nof_clk_per_sync => g_nof_clk_per_sync, g_nof_clk_per_sync => g_nof_clk_per_sync,
g_nof_clk_per_block => c_nof_clk_per_block g_nof_clk_per_block => c_nof_clk_per_block
) )
...@@ -125,62 +166,64 @@ BEGIN ...@@ -125,62 +166,64 @@ BEGIN
rst => rst, rst => rst,
clk => clk, clk => clk,
in_val => in_val, in_val => in_val,
out_val => in_sosi.valid, out_val => OPEN, -- out_val = in_val, because g_pipeline = FALSE
out_sop => in_sosi.sop, -- for monitoring only out_sop => in_sop,
out_eop => in_sosi.eop, -- for monitoring only out_eop => in_eop,
out_sync1 => in_sosi.sync -- use LOFAR1 style sync, is sync before sop 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 u_fft_switch : ENTITY work.fft_switch
GENERIC MAP ( GENERIC MAP (
g_nof_clk_per_sync => g_nof_clk_per_sync,
g_fft_sz_w => g_fft_size_w, g_fft_sz_w => g_fft_size_w,
g_dat_w => c_dat_w g_dat_w => c_dat_w
) )
PORT MAP ( PORT MAP (
in_re => in_a, -- constant values in_re => in_a,
in_im => in_b, -- constant values in_im => in_b,
in_val => in_sosi.valid, in_val => in_val,
in_sync => in_sosi.sync, -- use LOFAR1 style sync, is sync before sop
switch_en => switch_en, switch_en => switch_en,
out_re => switch_a, out_re => switch_a,
out_im => switch_b, out_im => switch_b,
out_val => switch_sosi.valid, out_val => switch_val,
out_sync => switch_sosi.sync, -- for monitoring only
clk => clk, clk => clk,
rst => rst rst => rst
); );
-- Model A, B multiplexing part of FFT -- Model A, B multiplexing part of FFT
-- 0 1 ..N-1 0 1 2 3 .. N-2 N-1 -- 0 1 2 .. N-1
-- switch_a: a a ..a --> fft_re: a b a b .. a b -- switch_a: a0 a1 a2 .. aN-1
-- switch_b: b b ..b --> fft_im: a b a b .. a b -- switch_b: b0 b1 b2 .. bN-1
mux_toggle <= NOT mux_toggle WHEN rising_edge(clk) AND switch_sosi.valid = '1'; -- prev1_switch_a: a0 a1 .. aN-1
-- prev1_switch_b: b0 b1 .. bN-1
mux_re <= switch_a WHEN mux_toggle = '0' ELSE switch_b; -- prev2_switch_a: a0 .. aN-1
mux_im <= switch_a WHEN mux_toggle = '0' ELSE switch_b; -- prev2_switch_b: b0 .. bN-1
mux_sosi <= switch_sosi; -- mux_toggle: 0 1 0 1 0 .. 1 0
-- 0 1 2 3 .. N-2 N-1
-- Create sync for fft_unswitch -- mux_re: a0 b0 a2 b2 .. aN-2 bN-2
u_sync_unswitch : ENTITY common_lib.common_create_sync_from_valid -- mux_im: a1 b1 a3 b3 .. aN-1 bN-1
GENERIC MAP (
g_pipeline => TRUE, prev1_switch_a <= switch_a WHEN rising_edge(clk) AND switch_val = '1';
g_nof_clk_per_sync => g_nof_clk_per_sync, prev1_switch_b <= switch_b WHEN rising_edge(clk) AND switch_val = '1';
g_nof_clk_per_block => c_nof_clk_per_block 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';
PORT MAP (
rst => rst, mux_toggle <= NOT mux_toggle WHEN rising_edge(clk) AND switch_val = '1';
clk => clk,
in_val => mux_sosi.valid, mux_re <= prev1_switch_a WHEN mux_toggle = '1' ELSE prev2_switch_b; -- a0, b0, ..
out_val => fft_sosi.valid, mux_im <= switch_a WHEN mux_toggle = '1' ELSE prev1_switch_b; -- a1, b1, ..
out_sop => fft_sosi.sop, -- for monitoring only mux_val <= switch_val WHEN rising_edge(clk);
out_eop => fft_sosi.eop, -- for monitoring only
out_sync1 => fft_sosi.sync -- use LOFAR1 style sync, is sync before sop
);
-- Pipeline the complex data to align with the strobes of fft_sosi
fft_re <= mux_re WHEN rising_edge(clk);
fft_im <= mux_im WHEN rising_edge(clk);
u_fft_unswitch : ENTITY work.fft_unswitch u_fft_unswitch : ENTITY work.fft_unswitch
...@@ -189,41 +232,81 @@ BEGIN ...@@ -189,41 +232,81 @@ BEGIN
g_dat_w => c_dat_w g_dat_w => c_dat_w
) )
PORT MAP ( PORT MAP (
in_re => fft_re, in_re => mux_re,
in_im => fft_im, in_im => mux_im,
in_val => fft_sosi.valid, in_val => mux_val,
in_sync => fft_sosi.sync, switch_en => unswitch_en,
switch_en => switch_en,
out_re => unswitch_re, out_re => unswitch_re,
out_im => unswitch_im, out_im => unswitch_im,
out_val => unswitch_sosi.valid, out_val => unswitch_val,
out_sync => unswitch_sosi.sync, -- for monitoring only
clk => clk, clk => clk,
rst => rst rst => rst
); );
-- Demultiplex output to ease verification -- Demultiplex output to ease verification
-- 0 1 2 3 .. N-2 N-1 0 1 ..N-1 -- 0 1 2 3 .. N-2 N-1
-- unswitch_re: a b a b .. a b --> out_a: a a ..a -- unswitch_re: a0 b0 a2 b2 .. aN-2 bN-2
-- unswitch_im: a b a b .. a b --> out_b: b b ..b -- unswitch_im: a1 b1 a3 b3 .. aN-1 bN-1
out_toggle <= NOT out_toggle WHEN rising_edge(clk) AND unswitch_sosi.valid = '1'; -- prev1_unswitch_re: a0 b0 a2 b2 .. aN-2 bN-2
-- prev1_unswitch_im: a1 b1 a3 b3 .. aN-1 bN-1
out_a <= unswitch_re WHEN out_toggle = '0'; -- prev2_unswitch_re: a0 b0 a2 b2 .. aN-2 bN-2
out_b <= unswitch_im WHEN out_toggle = '1'; -- 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
);
out_sosi.valid <= unswitch_sosi.valid; -- Account for pipeling in fft_switch, mux, fft_unswitch and demux
out_sosi.sync <= unswitch_sosi.sync; 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);
dly_sosi <= in_sosi WHEN rising_edge(clk); -- Account for pipeling in fft_switch verify_en <= '1' WHEN exp_val = '1';
exp_sosi <= dly_sosi WHEN rising_edge(clk); -- Account for pipeling in fft_unswitch
p_verify : PROCESS(clk) p_verify : PROCESS(clk)
BEGIN BEGIN
IF rising_edge(clk) THEN IF rising_edge(clk) THEN
ASSERT out_a = in_a REPORT "Wrong out_re" SEVERITY ERROR; IF verify_en = '1' THEN
ASSERT out_b = in_b REPORT "Wrong out_im" SEVERITY ERROR; IF exp_val = '1' THEN
ASSERT out_sosi.valid = exp_sosi.valid REPORT "Wrong out_val" SEVERITY ERROR; ASSERT TO_SINT(out_a) = exp_a REPORT "Wrong out_re" SEVERITY ERROR;
ASSERT out_sosi.sync = exp_sosi.sync REPORT "Wrong out_sync" 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 IF;
END PROCESS; END PROCESS;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment