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

Reworked tb using ref_grid. Verify bsn_time_offset /= 0 works for tb, but not yet for DUT.

parent 426b1fea
No related branches found
No related tags found
1 merge request!272L2SDP-801 Verify bsn time offset in dp_bsn_source_v2.vhd
...@@ -19,22 +19,28 @@ ...@@ -19,22 +19,28 @@
-- --
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- Author: P. Donker -- Author: P. Donker, E. Kooistra
-- Verify if eop and sop come in pairs and if sync is at sop and at expected_sync puls. -- Purpose: Tb to verify that the BS source can be started in any PPS interval
-- The tb is using a SSN (second sample number) and BSN (block sample number) generator as reference -- to create the BSN grid and sync interval as defined in Fig. 3.1 in
-- for the test, it uses g_pps_interval and g_block_size for generator timing settings. -- [1].
-- Start/Stop BSN source tests: -- Decsription:
-- 1) test 1x asynchronously (dp_on_pps='0') without automatic check, check visualy in wave window. -- * Start/Stop BSN source tests:
-- 2) test 3x synchronously (dp_on_pps='1') with automatic check. -- 1) test 1x asynchronously (dp_on_pps='0') without automatic check, check
-- visualy in wave window.
-- 2) test 3x synchronously (dp_on_pps='1') with automatic check.
-- . Verify if bs_sosi.eop and bs_sosi.sop come in pairs
-- . Verify that bs_sosi.sync is at bs_sosi.sop
-- . Verify that bs_sosi has fixed latency with respect to ref_grid
--
-- References:
-- [1] https://support.astron.nl/confluence/display/L2M/L2+STAT+Decision%3A+Timing+in+Station
-- [2] https://support.astron.nl/confluence/display/L2M/L6+FWLIB+Design+Document%3A+BSN+source+with+offset
-- --
-- [doc] = https://support.astron.nl/confluence/display/L2M/L6+FWLIB+Design+Document%3A+BSN+source+with+offset
-- Usage: -- Usage:
-- > as 10 -- > as 10
-- > run -all -- > run -all
-- . sop, eop are verified automatically -- . sop, eop are verified automatically
-- . sync and bsn are verified automatically -- . sync and bsn are verified automatically using the ref_grid
-- and then manually verify on/off in Wave window
LIBRARY IEEE, common_lib, dp_lib; LIBRARY IEEE, common_lib, dp_lib;
USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_1164.ALL;
...@@ -46,193 +52,196 @@ USE dp_lib.tb_dp_pkg.ALL; ...@@ -46,193 +52,196 @@ USE dp_lib.tb_dp_pkg.ALL;
ENTITY tb_dp_bsn_source_v2 IS ENTITY tb_dp_bsn_source_v2 IS
GENERIC ( GENERIC (
g_nof_pps : NATURAL := 20; g_nof_pps : NATURAL := 10;
g_pps_interval : NATURAL := 230; g_pps_interval : NATURAL := 10; --101;
g_block_size : NATURAL := 32 g_block_size : NATURAL := 7 --23
); );
END tb_dp_bsn_source_v2; END tb_dp_bsn_source_v2;
ARCHITECTURE tb OF tb_dp_bsn_source_v2 IS ARCHITECTURE tb OF tb_dp_bsn_source_v2 IS
CONSTANT c_clk_period : TIME := 10 ns; CONSTANT c_nof_repeat : NATURAL := 3;
CONSTANT c_bsn_w : NATURAL := 31;
CONSTANT c_dut_latency : NATURAL := 2; CONSTANT c_clk_period : TIME := 10 ns;
CONSTANT c_bsn_w : NATURAL := 31;
CONSTANT c_bsn_time_offset_w : NATURAL := ceil_log2(g_block_size);
-- Minimum latency between sync and PPS, due to logic in DUT
CONSTANT c_dut_latency : NATURAL := 3;
-- The state name tells what kind of test is being done -- The state name tells what kind of test is being done
TYPE t_state_enum IS ( TYPE t_state_enum IS (
s_disable, s_disable,
s_start, s_dp_on,
s_pps_start s_dp_on_pps
); );
SIGNAL tb_state : t_state_enum; -- Define the PPS (SSN) and BSN grid that both start at 0 according to Figure 3.1 in [1]:
TYPE t_time_grid IS RECORD
pps : STD_LOGIC; -- pulse per second, g_pps_interval clk per pps interval
ssn : NATURAL; -- seconds sequence number
bsn : NATURAL; -- block sequence number, g_block_size clk per block
sync : STD_LOGIC; -- active at sop when pps is active or was active
sop : STD_LOGIC; -- start of block
eop : STD_LOGIC; -- end of block
END RECORD;
CONSTANT c_time_grid_rst : t_time_grid := ('0', 0, 0, '0', '0', '0');
-- Reference grid
SIGNAL ref_grid : t_time_grid := c_time_grid_rst;
SIGNAL ssn_eop : STD_LOGIC := '0';
SIGNAL hold_pps : STD_LOGIC := '0';
SIGNAL nxt_hold_pps : STD_LOGIC := '0';
-- Tb
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 := '1'; SIGNAL clk : STD_LOGIC := '1';
SIGNAL tb_state : t_state_enum := s_disable;
-- DUT -- DUT
SIGNAL dp_on : STD_LOGIC := '0'; SIGNAL dp_on : STD_LOGIC := '0';
SIGNAL dp_on_pps : STD_LOGIC := '0'; SIGNAL dp_on_pps : STD_LOGIC := '0';
SIGNAL bsn_init : STD_LOGIC_VECTOR(c_bsn_w-1 DOWNTO 0) := (OTHERS=>'0'); SIGNAL dp_on_status : STD_LOGIC;
SIGNAL bs_restart : STD_LOGIC;
SIGNAL bs_sosi : t_dp_sosi; SIGNAL bsn_init : STD_LOGIC_VECTOR(c_bsn_w-1 DOWNTO 0) := (OTHERS=>'0');
SIGNAL bsn_time_offset : STD_LOGIC_VECTOR(c_bsn_time_offset_w-1 DOWNTO 0) := (OTHERS=>'0');
SIGNAL bs_sosi : t_dp_sosi;
-- Verify -- Verify
SIGNAL verify_sync : STD_LOGIC := '0'; SIGNAL exp_grid : t_time_grid;
SIGNAL hold_bs_sop : STD_LOGIC; SIGNAL unexpected_bs_sync : STD_LOGIC;
SIGNAL sl0 : STD_LOGIC := '0';
SIGNAL tb_bsn_cnt : INTEGER := 0; SIGNAL verify_en : STD_LOGIC := '0';
SIGNAL verify_sync : STD_LOGIC := '0';
-- Define the PPS grid and the BSN grid that both start at 0 according to Figure 3.1 in [doc]: SIGNAL hold_bs_sop : STD_LOGIC;
SIGNAL SSN : NATURAL := 0; SIGNAL prev_bs_valid : STD_LOGIC;
SIGNAL BSN : NATURAL := 0; SIGNAL bs_starts_cnt : NATURAL := 0;
SIGNAL pps_sop : STD_LOGIC := '0'; SIGNAL dbg_nof_blk : NATURAL;
SIGNAL nxt_pps_sop : STD_LOGIC := '0'; SIGNAL dbg_accumulate : NATURAL;
SIGNAL pps_eop : STD_LOGIC := '0'; SIGNAL dbg_expected_bsn : NATURAL;
SIGNAL bsn_sop : STD_LOGIC := '0';
SIGNAL nxt_bsn_sop : STD_LOGIC := '0';
SIGNAL bsn_eop : STD_LOGIC := '0';
SIGNAL expected_sync : STD_LOGIC := '0';
SIGNAL expected_sync_dly : STD_LOGIC := '0';
SIGNAL expected_bsn : NATURAL := 0;
SIGNAL expected_offset_bsn : NATURAL := 0;
SIGNAL dbg_nof_blk : NATURAL := 0;
SIGNAL dbg_accumulate : NATURAL := 0;
SIGNAL dbg_expected_bsn : NATURAL := 0;
BEGIN BEGIN
-----------------------------------------------------------------------------
-- Stimuli
-----------------------------------------------------------------------------
rst <= '1', '0' AFTER c_clk_period*7; rst <= '1', '0' AFTER c_clk_period*7;
clk <= (NOT clk) OR tb_end AFTER c_clk_period/2; clk <= (NOT clk) OR tb_end AFTER c_clk_period/2;
-----------------------------------------------------------------------------
-- SSN/BSN generator -- Generate reference time grid
SSN <= SSN + 1 WHEN rising_edge(clk) AND pps_eop='1'; -- Seconds Sequence Number -----------------------------------------------------------------------------
BSN <= BSN + 1 WHEN rising_edge(clk) AND bsn_eop='1'; -- Block Sequence Number proc_common_gen_pulse(1, g_pps_interval, '1', sl0, clk, ref_grid.pps);
proc_common_gen_pulse(1, g_block_size, '1', sl0, clk, ref_grid.sop);
proc_common_gen_pulse(1, g_pps_interval, '1', rst, clk, nxt_pps_sop); -- make PPS grid with pps_sop at start of interval ref_grid.eop <= ref_grid.sop'DELAYED((g_block_size - 1) * c_clk_period);
pps_sop <= nxt_pps_sop AFTER c_clk_period; ssn_eop <= ref_grid.pps'DELAYED((g_pps_interval - 1) * c_clk_period);
pps_eop <= pps_sop'DELAYED((g_pps_interval-1)*c_clk_period); -- make PPS grid with pps_eop at end of intervals ref_grid.ssn <= ref_grid.ssn + 1 WHEN rising_edge(clk) AND ssn_eop = '1';
ref_grid.bsn <= ref_grid.bsn + 1 WHEN rising_edge(clk) AND ref_grid.eop = '1';
proc_common_gen_pulse(1, g_block_size, '1', rst, clk, nxt_bsn_sop); -- make BSN grid with bsn_sop at start of interval
bsn_sop <= nxt_bsn_sop AFTER c_clk_period; -- Issue sync at start of block
bsn_eop <= bsn_sop'DELAYED((g_block_size-1)*c_clk_period); -- make BSN grid with bsn_eop at end of interval p_ref_grid_sync : PROCESS(ref_grid, hold_pps)
-- Define the expected sync that occurs when pps_sop = bsn sop, or else at the first bsn_sop after the pps_sop, see Figure 3.1 in [doc].
p_expected_sync : PROCESS
BEGIN BEGIN
WAIT UNTIL rising_edge(clk); ref_grid.sync <= '0';
expected_sync <= '0'; nxt_hold_pps <= hold_pps;
proc_common_wait_until_high(clk, pps_sop);
IF bsn_sop = '1' THEN IF ref_grid.pps = '1' THEN
expected_sync <= '1'; IF ref_grid.sop = '1' THEN
expected_bsn <= BSN+1; ref_grid.sync <= '1'; -- immediately issue sync
expected_offset_bsn <= 0; ELSE
ELSE nxt_hold_pps <= '1'; -- wait until next block
proc_common_wait_until_high(clk, bsn_sop); END IF;
expected_sync <= '1'; END IF;
expected_bsn <= BSN+1;
expected_offset_bsn <= (BSN+1) * g_block_size - SSN * g_pps_interval; IF hold_pps = '1' THEN
IF ref_grid.sop = '1' THEN
ref_grid.sync <= '1'; -- issue pending sync
nxt_hold_pps <= '0';
END IF;
END IF; END IF;
END PROCESS; END PROCESS;
expected_sync_dly <= expected_sync'DELAYED(c_dut_latency*c_clk_period);
-- MM control hold_pps <= nxt_hold_pps WHEN rising_edge(clk);
exp_grid <= ref_grid'DELAYED(c_dut_latency * c_clk_period);
-----------------------------------------------------------------------------
-- Stimuli
-----------------------------------------------------------------------------
p_mm : PROCESS p_mm : PROCESS
VARIABLE v_bsn_time_offset : NATURAL; VARIABLE v_ssn : NATURAL;
VARIABLE v_bsn_init : NATURAL; VARIABLE v_bsn_init : NATURAL;
VARIABLE v_bsn_time_offset : NATURAL;
BEGIN BEGIN
tb_end <= '0';
tb_state <= s_disable;
--pps <= '0';
dp_on <= '0';
dp_on_pps <= '0';
-- Get synchronous to clk -- Get synchronous to clk
proc_common_wait_until_low(clk, rst); proc_common_wait_until_low(clk, rst);
proc_common_wait_some_cycles(clk, 500); proc_common_wait_some_cycles(clk, 10);
-- Start asynchronously by making dp_on high -- Start asynchronously by making dp_on high
proc_common_wait_until_high(clk, expected_sync_dly); verify_en <= '0'; -- only verify visualy in wave window
tb_state <= s_pps_start; tb_state <= s_dp_on;
dp_on_pps <= '0'; dp_on_pps <= '0';
dp_on <= '1'; dp_on <= '1';
verify_sync <= '0'; -- only verify visualy in wave window
proc_common_wait_some_cycles(clk, g_nof_pps*g_pps_interval); proc_common_wait_some_cycles(clk, g_nof_pps*g_pps_interval);
verify_sync <= '0';
-- Stop by making dp_on low
tb_state <= s_disable; tb_state <= s_disable;
dp_on <= '0'; dp_on <= '0';
dp_on_pps <= '0'; dp_on_pps <= '0';
proc_common_wait_some_cycles(clk, 10);
-- wait until one pps_interval before next begin of SSN generator (pps_sop = bsn_sop)
proc_common_wait_until_high(clk, pps_sop);
v_bsn_time_offset := ((SSN + 2) * g_pps_interval) MOD g_block_size;
WHILE v_bsn_time_offset > 0 LOOP
proc_common_wait_some_cycles(clk, g_pps_interval);
v_bsn_time_offset := ((SSN + 2) * g_pps_interval) MOD g_block_size;
END LOOP;
-- Start synchronously by making dp_on high at pps -- Start synchronously by making dp_on and dp_on_pps high
FOR i IN 0 TO 2 LOOP verify_en <= '1'; -- verify automatically in test bench
-- Now start on PPS
proc_common_wait_until_high(clk, expected_sync); FOR I IN 0 TO c_nof_repeat-1 LOOP
v_bsn_time_offset := ((SSN + 1) * g_pps_interval) MOD g_block_size; -- Wait some variable time between tests, to enforce testing different
v_bsn_init := ((SSN + 1) * g_pps_interval) / g_block_size; -- bsn_time_offset values
IF v_bsn_time_offset = 0 THEN proc_common_wait_some_cycles(clk, 20);
bsn_init <= TO_UVEC(v_bsn_init, c_bsn_w); proc_common_wait_some_cycles(clk, I*g_pps_interval);
ELSE
bsn_init <= TO_UVEC(v_bsn_init+1, c_bsn_w); -- Wait until in the beginning of PPS interval
END IF; proc_common_wait_until_hi_lo(clk, ref_grid.pps);
tb_state <= s_pps_start; proc_common_wait_some_cycles(clk, c_dut_latency);
-- Determine bsn_init and bsn_time_offset for BSN source start
-- . bsn_init = BSN at sync
-- . bsn_time_offset = number of clk that sync occurs after PPS
v_ssn := ref_grid.ssn + 1; -- +1 to prepare start in next PPS interval
v_bsn_init := ceil_div(v_SSN * g_pps_interval, g_block_size); -- Equation 3.6 in [1]
v_bsn_time_offset := v_bsn_init * g_block_size - v_SSN * g_pps_interval; -- Equation 3.7 in [1]
bsn_init <= TO_UVEC(v_bsn_init, c_bsn_w); --
bsn_time_offset <= TO_UVEC(v_bsn_time_offset, c_bsn_time_offset_w);
-- Start synchronously by making dp_on and dp_on_pps high
tb_state <= s_dp_on_pps;
dp_on_pps <= '1'; dp_on_pps <= '1';
dp_on <= '1'; dp_on <= '1';
verify_sync <= '1'; -- verify automatically in test bench
proc_common_wait_some_cycles(clk, g_nof_pps*g_pps_interval); proc_common_wait_some_cycles(clk, g_nof_pps*g_pps_interval);
verify_sync <= '0';
-- Stop by making dp_on low
tb_state <= s_disable; tb_state <= s_disable;
dp_on <= '0'; dp_on <= '0';
dp_on_pps <= '0'; dp_on_pps <= '0';
-- wait until one pps_interval before next begin of SSN generator (pps_sop = bsn_sop)
proc_common_wait_until_high(clk, pps_sop);
v_bsn_time_offset := ((SSN + 2) * g_pps_interval) MOD g_block_size;
WHILE v_bsn_time_offset > 0 LOOP
proc_common_wait_some_cycles(clk, g_pps_interval);
v_bsn_time_offset := ((SSN + 2) * g_pps_interval) MOD g_block_size;
END LOOP;
END LOOP; END LOOP;
tb_end <= '1'; proc_common_wait_some_cycles(clk, 10);
ASSERT bs_starts_cnt = 1 + c_nof_repeat REPORT "Wrong number of BSN source starts." SEVERITY ERROR;
tb_end <= '1';
WAIT; WAIT;
END PROCESS; END PROCESS;
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Verification -- Verification
-- . Some aspects of bs_sosi are verified multiple times in different ways,
-- this overlap is fine, because the tb and DUT are rather complicated, so
-- using different approaches also helpt to verify the tb itself.
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
verify_sync <= verify_en AND bs_sosi.valid;
proc_dp_verify_sop_and_eop(clk, bs_sosi.valid, bs_sosi.sop, bs_sosi.eop, hold_bs_sop); -- Verify that sop and eop come in pairs proc_dp_verify_sop_and_eop(clk, bs_sosi.valid, bs_sosi.sop, bs_sosi.eop, hold_bs_sop); -- Verify that sop and eop come in pairs
proc_dp_verify_sync(clk, verify_sync, bs_sosi.sync, bs_sosi.sop, expected_sync_dly); -- Verify sync at sop and at expected_sync --proc_dp_verify_sync(clk, verify_sync, bs_sosi.sync, exp_grid.sop, exp_grid.sync); -- Verify sync at sop and at expected_sync
-- Verify sync at sop and at expected_sync again: -- Verify sync at sop and at expected_sync
-- . now using the proc_dp_verify_sync() variant for dp_bsn_source_v2 that proc_dp_verify_sync(g_pps_interval,
-- can verify fractional sync periods.
-- . the proc_dp_verify_sync() v2 variant was made later, so in fact
-- this tb_dp_bsn_source_v2 verifies this new v2 procedure.
proc_dp_verify_sync(TO_UINT(bsn_init),
g_pps_interval,
g_block_size, g_block_size,
clk, clk,
verify_sync, verify_en,
bs_sosi.sync, bs_sosi.sync,
bs_sosi.sop, bs_sosi.sop,
bs_sosi.bsn, bs_sosi.bsn,
...@@ -240,6 +249,28 @@ BEGIN ...@@ -240,6 +249,28 @@ BEGIN
dbg_accumulate, dbg_accumulate,
dbg_expected_bsn); dbg_expected_bsn);
-- Verify bs_sosi by comparing with exp_grid, this again verifies bs_sosi.sync, sop and bsn
p_verify_bs_sosi_grid : PROCESS(clk)
BEGIN
IF rising_edge(clk) THEN
unexpected_bs_sync <= '0';
IF verify_en = '1' AND bs_sosi.valid = '1' THEN
ASSERT TO_UINT(bs_sosi.bsn) = exp_grid.bsn REPORT "Wrong bs_sosi.bsn /= exp_grid.bsn" SEVERITY ERROR;
ASSERT bs_sosi.sync = exp_grid.sync REPORT "Wrong bs_sosi.sync /= exp_grid.sync" SEVERITY ERROR;
ASSERT bs_sosi.sop = exp_grid.sop REPORT "Wrong bs_sosi.sop /= exp_grid.sop" SEVERITY ERROR;
ASSERT bs_sosi.eop = exp_grid.eop REPORT "Wrong bs_sosi.eop /= exp_grid.eop" SEVERITY ERROR;
-- Mark error in Wave window
IF bs_sosi.sync = '1' AND bs_sosi.sync /= exp_grid.sync THEN
unexpected_bs_sync <= '1';
END IF;
END IF;
END IF;
END PROCESS;
-- Verify that bs_sosi.valid = '1' did happen after dp_on
prev_bs_valid <= bs_sosi.valid WHEN rising_edge(clk);
bs_starts_cnt <= bs_starts_cnt + 1 WHEN rising_edge(clk) AND bs_sosi.valid = '1' AND prev_bs_valid = '0';
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- DUT: dp_bsn_source_v2 -- DUT: dp_bsn_source_v2
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
...@@ -248,18 +279,25 @@ BEGIN ...@@ -248,18 +279,25 @@ BEGIN
GENERIC MAP ( GENERIC MAP (
g_block_size => g_block_size, g_block_size => g_block_size,
g_nof_clk_per_sync => g_pps_interval, g_nof_clk_per_sync => g_pps_interval,
g_bsn_w => c_bsn_w g_bsn_w => c_bsn_w,
g_bsn_time_offset_w => c_bsn_time_offset_w
) )
PORT MAP ( PORT MAP (
rst => rst, rst => rst,
clk => clk, clk => clk,
pps => pps_sop, pps => ref_grid.pps,
-- MM control -- MM control
dp_on => dp_on, dp_on => dp_on,
dp_on_pps => dp_on_pps, dp_on_pps => dp_on_pps,
bsn_init => bsn_init,
dp_on_status => dp_on_status, -- = src_out.valid
bs_restart => bs_restart, -- = src_out.sop for first sop after dp_on went high
bsn_init => bsn_init,
bsn_time_offset => bsn_time_offset,
-- Streaming -- Streaming
src_out => bs_sosi src_out => bs_sosi
); );
END tb; END tb;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment