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

Add tb_dp_rsn_source.vhd, it compiles OK but does not verify rs_sosi yet.

parent 2dea6766
No related branches found
No related tags found
1 merge request!317Resolve L2SDP-7
Pipeline #46150 passed with warnings
...@@ -221,6 +221,7 @@ test_bench_files = ...@@ -221,6 +221,7 @@ test_bench_files =
tb/vhdl/tb_mmp_dp_bsn_align_v2.vhd tb/vhdl/tb_mmp_dp_bsn_align_v2.vhd
tb/vhdl/tb_dp_bsn_monitor.vhd tb/vhdl/tb_dp_bsn_monitor.vhd
tb/vhdl/tb_dp_bsn_monitor_v2.vhd tb/vhdl/tb_dp_bsn_monitor_v2.vhd
tb/vhdl/tb_dp_rsn_source.vhd
tb/vhdl/tb_dp_bsn_source.vhd tb/vhdl/tb_dp_bsn_source.vhd
tb/vhdl/tb_dp_bsn_source_v2.vhd tb/vhdl/tb_dp_bsn_source_v2.vhd
tb/vhdl/tb_mms_dp_bsn_source.vhd tb/vhdl/tb_mms_dp_bsn_source.vhd
......
-------------------------------------------------------------------------------
--
-- 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 tb_dp_rsn_source
-- Use dp_bsn_source_v2 to create bs_sosi and extending it with dut =
-- dp_rsn_source to create and verify rs_sosi.
-- Remark:
-- * This tb is made based on tb_dp_bsn_source_v2.
LIBRARY IEEE, common_lib, dp_lib;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
USE common_lib.common_pkg.ALL;
USE common_lib.tb_common_pkg.ALL;
USE dp_lib.dp_stream_pkg.ALL;
USE dp_lib.tb_dp_pkg.ALL;
ENTITY tb_dp_rsn_source IS
GENERIC (
g_pps_interval : NATURAL := 16; --101;
g_bs_block_size : NATURAL := 5; --23
g_rs_block_size : NATURAL := 5 --23
);
END tb_dp_rsn_source;
ARCHITECTURE tb OF tb_dp_rsn_source IS
-- The nof block per sync interval will be the same after every
-- c_min_nof_pps_interval. The c_gcd is the greatest common divider of
-- g_pps_interval and g_bs_block_size, so g_bs_block_size / c_gcd yields an
-- integer. When g_pps_interval and g_bs_block_size are relative prime,
-- then c_gcd = 1, and then it takes g_bs_block_size nof g_pps_interval
-- for the pattern of c_nof_block_per_sync_lo and c_nof_block_per_sync_hi
-- to repeat. If c_gcd = g_bs_block_size, then c_nof_block_per_sync_lo =
-- c_nof_block_per_sync_hi, so then the nof block per sync interval is
-- the same in every pps interval.
CONSTANT c_gcd : NATURAL := gcd(g_pps_interval, g_bs_block_size);
CONSTANT c_min_nof_pps_interval : NATURAL := g_bs_block_size / c_gcd;
CONSTANT c_nof_block_per_sync_lo : NATURAL := g_pps_interval / g_bs_block_size;
CONSTANT c_nof_block_per_sync_hi : NATURAL := ceil_div(g_pps_interval, g_bs_block_size);
-- choose c_nof_pps and c_nof_repeat > c_min_nof_pps_interval, because the
-- fractional sync pattern will repeat every c_min_nof_pps_interval number
-- of g_pps_intervals.
CONSTANT c_factor : NATURAL := 3;
CONSTANT c_nof_pps : NATURAL := c_min_nof_pps_interval * c_factor;
CONSTANT c_nof_repeat : NATURAL := c_min_nof_pps_interval * c_factor;
CONSTANT c_clk_period : TIME := 10 ns;
CONSTANT c_bsn_w : NATURAL := 31;
CONSTANT c_bsn_time_offset_w : NATURAL := ceil_log2(g_bs_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
TYPE t_state_enum IS (
s_disable,
s_dp_on,
s_dp_on_pps
);
-- 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_bs_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 rst : STD_LOGIC := '1';
SIGNAL clk : STD_LOGIC := '1';
SIGNAL tb_state : t_state_enum := s_disable;
-- BSN source
SIGNAL dp_on : STD_LOGIC := '0';
SIGNAL dp_on_pps : STD_LOGIC := '0';
SIGNAL dp_on_status : STD_LOGIC;
SIGNAL bs_restart : STD_LOGIC;
SIGNAL bs_new_interval : STD_LOGIC;
SIGNAL tb_new_interval : STD_LOGIC := '0';
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;
-- RSN source
SIGNAL rs_restart : STD_LOGIC;
SIGNAL rs_new_interval : STD_LOGIC;
SIGNAL rs_sosi : t_dp_sosi;
-- Verify
SIGNAL exp_grid : t_time_grid;
SIGNAL unexpected_bs_sync : STD_LOGIC;
SIGNAL sl0 : STD_LOGIC := '0';
SIGNAL verify_en : STD_LOGIC := '0';
SIGNAL verify_sync : STD_LOGIC := '0';
SIGNAL hold_bs_sop : STD_LOGIC;
SIGNAL prev_bs_valid : STD_LOGIC;
SIGNAL bs_starts_cnt : NATURAL := 0;
SIGNAL dbg_c_nof_pps : NATURAL := c_nof_pps;
SIGNAL dbg_c_nof_repeat : NATURAL := c_nof_repeat;
SIGNAL dbg_nof_blk : NATURAL;
SIGNAL dbg_accumulate : NATURAL;
SIGNAL dbg_expected_bsn : NATURAL;
BEGIN
rst <= '1', '0' AFTER c_clk_period*7;
clk <= (NOT clk) OR tb_end AFTER c_clk_period/2;
-----------------------------------------------------------------------------
-- Generate reference time grid
-----------------------------------------------------------------------------
proc_common_gen_pulse(1, g_pps_interval, '1', sl0, clk, ref_grid.pps);
proc_common_gen_pulse(1, g_bs_block_size, '1', sl0, clk, ref_grid.sop);
ref_grid.eop <= ref_grid.sop'DELAYED((g_bs_block_size - 1) * c_clk_period);
ssn_eop <= ref_grid.pps'DELAYED((g_pps_interval - 1) * c_clk_period);
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';
-- Issue sync at start of block
p_ref_grid_sync : PROCESS(ref_grid, hold_pps)
BEGIN
ref_grid.sync <= '0';
nxt_hold_pps <= hold_pps;
IF ref_grid.pps = '1' THEN
IF ref_grid.sop = '1' THEN
ref_grid.sync <= '1'; -- immediately issue sync
ELSE
nxt_hold_pps <= '1'; -- wait until next block
END IF;
END IF;
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 PROCESS;
hold_pps <= nxt_hold_pps WHEN rising_edge(clk);
exp_grid <= ref_grid'DELAYED(c_dut_latency * c_clk_period);
-----------------------------------------------------------------------------
-- Stimuli
-----------------------------------------------------------------------------
p_mm : PROCESS
VARIABLE v_ssn : NATURAL;
VARIABLE v_bsn_init : NATURAL;
VARIABLE v_bsn_time_offset : NATURAL;
BEGIN
-- Get synchronous to clk
proc_common_wait_until_low(clk, rst);
proc_common_wait_some_cycles(clk, 10);
-- Start asynchronously by making dp_on high
verify_en <= '0'; -- only verify visualy in wave window
tb_state <= s_dp_on;
dp_on_pps <= '0';
dp_on <= '1';
proc_common_wait_some_cycles(clk, c_nof_pps*g_pps_interval);
tb_state <= s_disable;
dp_on <= '0';
dp_on_pps <= '0';
proc_common_wait_some_cycles(clk, 10);
-- Start synchronously by making dp_on and dp_on_pps high
verify_en <= '1'; -- verify automatically in test bench
FOR I IN 0 TO c_nof_repeat-1 LOOP
-- Wait some variable time between tests, to enforce testing different
-- bsn_time_offset values
proc_common_wait_some_cycles(clk, 20);
proc_common_wait_some_cycles(clk, I*g_pps_interval);
-- Wait until in the beginning of PPS interval
proc_common_wait_until_hi_lo(clk, ref_grid.pps);
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_bs_block_size); -- Equation 3.6 in [1]
v_bsn_time_offset := v_bsn_init * g_bs_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 <= '1';
proc_common_wait_some_cycles(clk, c_nof_pps*g_pps_interval);
tb_state <= s_disable;
dp_on <= '0';
dp_on_pps <= '0';
END LOOP;
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;
END PROCESS;
-----------------------------------------------------------------------------
-- 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_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
proc_dp_verify_sync(0, -- start bsn of PPS grid and BSN grid is 0, see [1]
g_pps_interval,
g_bs_block_size,
clk,
verify_en,
bs_sosi.sync,
bs_sosi.sop,
bs_sosi.bsn,
dbg_nof_blk,
dbg_accumulate,
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 by verifying bs_start
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';
p_verify_bs_restart : PROCESS(clk)
BEGIN
IF rising_edge(clk) THEN
IF bs_restart = '1' THEN
ASSERT bs_sosi.sync = '1' REPORT "Unexpected bs_start while bs_sosi.sync /= 1" SEVERITY ERROR;
ASSERT prev_bs_valid = '0' REPORT "Unexpected bs_start while prev_bs_valid /= 0" SEVERITY ERROR;
END IF;
END IF;
END PROCESS;
p_verify_bs_new_interval : PROCESS(clk)
BEGIN
IF rising_edge(clk) THEN
IF bs_restart = '1' THEN
ASSERT bs_new_interval = '1' REPORT "Wrong begin of bs_new_interval" SEVERITY ERROR;
tb_new_interval <= '1';
ELSIF bs_sosi.sync = '1' THEN
ASSERT bs_new_interval = '0' REPORT "Wrong end of bs_new_interval" SEVERITY ERROR;
tb_new_interval <= '0';
ELSIF tb_new_interval = '1' THEN
ASSERT bs_new_interval = '1' REPORT "Wrong level during bs_new_interval" SEVERITY ERROR;
ELSE
ASSERT bs_new_interval = '0' REPORT "Unexpected bs_new_interval" SEVERITY ERROR;
END IF;
END IF;
END PROCESS;
-----------------------------------------------------------------------------
-- DUT: dp_bsn_source_v2
-----------------------------------------------------------------------------
u_bsn : ENTITY work.dp_bsn_source_v2
GENERIC MAP (
g_block_size => g_bs_block_size,
g_nof_clk_per_sync => g_pps_interval,
g_bsn_w => c_bsn_w,
g_bsn_time_offset_w => c_bsn_time_offset_w
)
PORT MAP (
rst => rst,
clk => clk,
pps => ref_grid.pps,
-- MM control
dp_on => dp_on,
dp_on_pps => dp_on_pps,
dp_on_status => dp_on_status, -- = src_out.valid
bs_restart => bs_restart, -- = src_out.sync for first sync after dp_on went high
bs_new_interval => bs_new_interval, -- active during first src_out.sync interval
bsn_init => bsn_init,
bsn_time_offset => bsn_time_offset,
-- Streaming
src_out => bs_sosi
);
u_rsn : ENTITY work.dp_rsn_source
GENERIC MAP (
g_block_size => g_rs_block_size,
g_nof_clk_per_sync => g_pps_interval,
g_bsn_w => c_bsn_w
)
PORT MAP (
rst => rst,
clk => clk,
-- Input stream sosi control using BSN
bs_sosi => bs_sosi, -- input reference stream using BSN
-- Output stream sosi control using RSN
rs_sosi => rs_sosi, -- output stream using RSN and g_rs_block_size, g_nof_clk_per_sync
rs_restart => rs_restart, -- = rs_sosi.sync for first sync after bs_sosi.valid went high
rs_new_interval => rs_new_interval -- = active during first rs_sosi.sync interval
);
END tb;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment