diff --git a/libraries/base/dp/src/vhdl/dp_bsn_source_reg_v2.vhd b/libraries/base/dp/src/vhdl/dp_bsn_source_reg_v2.vhd index fed0ff23ae38c86639905c25d83da8144c8bf35c..65c0b826c10db0a6209734773b2295ef8e8115eb 100644 --- a/libraries/base/dp/src/vhdl/dp_bsn_source_reg_v2.vhd +++ b/libraries/base/dp/src/vhdl/dp_bsn_source_reg_v2.vhd @@ -34,8 +34,8 @@ -- RD '0' = DP off; RD '1' = DP on. -- [1] WR dp_on_pps 0x0 -- 1 [31..0] WR nof_clk_per_sync 0x0 --- 2 [31..0] RW bsn[31..0] 0x0 write init_bsn, read current bsn --- 3 [31..0] RW bsn[63..32] 0x0 write init_bsn, read current bsn +-- 2 [31..0] RW bsn[31..0] 0x0 write bsn_init, read current bsn +-- 3 [31..0] RW bsn[63..32] 0x0 write bsn_init, read current bsn -- ==================================================================================== LIBRARY IEEE, common_lib; @@ -64,7 +64,7 @@ ENTITY dp_bsn_source_reg_v2 IS st_on_pps : OUT STD_LOGIC := '0'; -- level st_on_status : IN STD_LOGIC; st_nof_clk_per_sync : OUT STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); -- nof block per sync - st_init_bsn : OUT STD_LOGIC_VECTOR; -- wr init BSN + st_bsn_init : OUT STD_LOGIC_VECTOR; -- wr init BSN st_current_bsn : IN STD_LOGIC_VECTOR -- rd current BSN ); END dp_bsn_source_reg_v2; @@ -72,7 +72,7 @@ END dp_bsn_source_reg_v2; ARCHITECTURE rtl OF dp_bsn_source_reg_v2 IS - CONSTANT c_bsn_w : NATURAL := st_init_bsn'LENGTH; + CONSTANT c_bsn_w : NATURAL := st_bsn_init'LENGTH; -- Define the actual size of the MM slave register CONSTANT c_mm_reg : t_c_mem := (latency => 1, @@ -90,8 +90,8 @@ ARCHITECTURE rtl OF dp_bsn_source_reg_v2 IS SIGNAL mm_nof_clk_per_sync : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); - SIGNAL mm_init_bsn : STD_LOGIC_VECTOR(c_longword_w-1 DOWNTO 0); - SIGNAL mm_init_bsn_wr : STD_LOGIC; + SIGNAL mm_bsn_init : STD_LOGIC_VECTOR(c_longword_w-1 DOWNTO 0); + SIGNAL mm_bsn_init_wr : STD_LOGIC; SIGNAL mm_current_bsn : STD_LOGIC_VECTOR(c_longword_w-1 DOWNTO 0) := (OTHERS=>'0'); SIGNAL mm_current_bsn_hi : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0) := (OTHERS=>'0'); @@ -116,15 +116,15 @@ BEGIN mm_on <= '0'; mm_on_pps <= '0'; mm_nof_clk_per_sync <= TO_UVEC(g_nof_clk_per_sync, c_word_w); - mm_init_bsn <= (OTHERS=>'0'); - mm_init_bsn_wr <= '0'; + mm_bsn_init <= (OTHERS=>'0'); + mm_bsn_init_wr <= '0'; mm_current_bsn_hi <= (OTHERS=>'0'); ELSIF rising_edge(mm_clk) THEN -- Read access defaults sla_out.rdval <= '0'; -- Access event defaults - mm_init_bsn_wr <= '0'; + mm_bsn_init_wr <= '0'; -- Write access: set register value IF sla_in.wr = '1' THEN @@ -138,10 +138,10 @@ BEGIN -- Write init BSN WHEN 2 => - mm_init_bsn(31 DOWNTO 0) <= sla_in.wrdata(31 DOWNTO 0); + mm_bsn_init(31 DOWNTO 0) <= sla_in.wrdata(31 DOWNTO 0); WHEN 3 => - mm_init_bsn(63 DOWNTO 32) <= sla_in.wrdata(31 DOWNTO 0); - mm_init_bsn_wr <= '1'; + mm_bsn_init(63 DOWNTO 32) <= sla_in.wrdata(31 DOWNTO 0); + mm_bsn_init_wr <= '1'; WHEN OTHERS => NULL; -- not used MM addresses END CASE; @@ -192,15 +192,15 @@ BEGIN st_on <= mm_on; st_on_pps <= mm_on_pps; st_nof_clk_per_sync <= mm_nof_clk_per_sync; - st_init_bsn <= mm_init_bsn(c_bsn_w-1 DOWNTO 0); + st_bsn_init <= mm_bsn_init(c_bsn_w-1 DOWNTO 0); p_st_clk : PROCESS(st_rst, st_clk) BEGIN IF st_rst='1' THEN - st_init_bsn <= TO_UVEC(0, c_bsn_w); + st_bsn_init <= TO_UVEC(0, c_bsn_w); ELSIF rising_edge(st_clk) THEN - IF mm_init_bsn_wr='1' THEN - st_init_bsn <= mm_init_bsn(c_bsn_w-1 DOWNTO 0); -- use wr of mm_init_bsn high part for in_new to ensure proper transfer of double word + IF mm_bsn_init_wr='1' THEN + st_bsn_init <= mm_bsn_init(c_bsn_w-1 DOWNTO 0); -- use wr of mm_bsn_init high part for in_new to ensure proper transfer of double word END IF; END IF; END PROCESS; @@ -253,16 +253,16 @@ BEGIN ); -- write occurs with sufficient margin before it is used, still use common_reg_cross_domain nonetheless - u_init_bsn : ENTITY common_lib.common_reg_cross_domain + u_bsn_init : ENTITY common_lib.common_reg_cross_domain PORT MAP ( in_rst => mm_rst, in_clk => mm_clk, - in_new => mm_init_bsn_wr, -- use wr of mm_init_bsn high part for in_new to ensure proper transfer of double word - in_dat => mm_init_bsn(c_bsn_w-1 DOWNTO 0), + in_new => mm_bsn_init_wr, -- use wr of mm_bsn_init high part for in_new to ensure proper transfer of double word + in_dat => mm_bsn_init(c_bsn_w-1 DOWNTO 0), in_done => OPEN, -- pulses when no more pending in_new out_rst => st_rst, out_clk => st_clk, - out_dat => st_init_bsn, + out_dat => st_bsn_init, out_new => OPEN ); diff --git a/libraries/base/dp/src/vhdl/dp_bsn_source_v2.vhd b/libraries/base/dp/src/vhdl/dp_bsn_source_v2.vhd index 5108162f14d92ff6ff48eef7da576b77443e31ab..f12b484d052821754f3bb99d351b1e48d9ded4ce 100644 --- a/libraries/base/dp/src/vhdl/dp_bsn_source_v2.vhd +++ b/libraries/base/dp/src/vhdl/dp_bsn_source_v2.vhd @@ -31,6 +31,9 @@ -- Remarks: -- Starting the data path is only possible from the dp_off state, so one -- has to disable (dp_on='0') the data path before restarting it. +-- +-- author : P.Donker okt. 2020 +-- LIBRARY IEEE, common_lib; USE IEEE.STD_LOGIC_1164.ALL; @@ -43,7 +46,7 @@ ENTITY dp_bsn_source_v2 IS g_block_size : NATURAL := 256; g_nof_clk_per_sync : NATURAL := 200 * 10**6; g_bsn_w : NATURAL := 48; - g_offset_w : NATURAL := 4 + g_time_offset_w : NATURAL := 10 ); PORT ( rst : IN STD_LOGIC; @@ -55,10 +58,9 @@ ENTITY dp_bsn_source_v2 IS dp_on_status : OUT STD_LOGIC; - init_bsn : IN STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0) := (OTHERS=>'0'); + bsn_init : IN STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0) := (OTHERS=>'0'); nof_clk_per_sync : IN STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0) := TO_UVEC(g_nof_clk_per_sync, c_word_w); - offset_bsn : IN STD_LOGIC_VECTOR(g_offset_w-1 DOWNTO 0) := (OTHERS=>'0'); - --offset_bsn : IN STD_LOGIC_VECTOR(g_offset_w-1 DOWNTO 0) := TO_UVEC(4, g_offset_w); + bsn_time_offset : IN STD_LOGIC_VECTOR(g_time_offset_w-1 DOWNTO 0) := (OTHERS=>'0'); src_out : OUT t_dp_sosi -- only uses sync, bsn[], valid, sop and eop ); @@ -70,7 +72,21 @@ ARCHITECTURE rtl OF dp_bsn_source_v2 IS CONSTANT c_block_size_cnt_w : NATURAL := ceil_log2(g_block_size); CONSTANT c_block_cnt_zero : STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0) := (OTHERS => '0'); - TYPE t_state_enum IS (s_init, s_dp_off, s_dp_on_sop, s_dp_on, s_dp_on_eop, s_bsn_offset); + -- The state machine starts synchronously via s_bsn_time_offset, s_dp_on_sop to s_dp_on, or it starts + -- directly to s_dp_on. When in dp_on it loops between s_dp_on and s_dp_on_eop for every block. + -- If the BSN source is switched off, then after completing the block s_dp_on_eop goes back to + -- s_dp_off. + -- + -- Sketch of the state machine: + -- + -- s_init --> s_dp_off --> s_bsn_time_offset -- ------------ (loop) <--- + -- \ \ \ / \ + -- \ ---------------------------> s_dp_on_sop --> s_dp_on --> s_dp_on_eop -- + -- \ / + -- ----------------------------------------------------------------- (off) <--- + + + TYPE t_state_enum IS (s_init, s_dp_off, s_bsn_time_offset, s_dp_on_sop, s_dp_on, s_dp_on_eop); SIGNAL state : t_state_enum; SIGNAL nxt_state : t_state_enum; @@ -79,17 +95,14 @@ ARCHITECTURE rtl OF dp_bsn_source_v2 IS SIGNAL block_size_cnt : STD_LOGIC_VECTOR(c_block_size_cnt_w-1 DOWNTO 0); SIGNAL nxt_block_size_cnt : STD_LOGIC_VECTOR(c_block_size_cnt_w-1 DOWNTO 0); - --SIGNAL block_cnt : STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0); - --SIGNAL nxt_block_cnt : STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0); - SIGNAL i_src_out : t_dp_sosi := c_dp_sosi_init; SIGNAL nxt_src_out : t_dp_sosi; - SIGNAL nxt_dp_on_status : STD_LOGIC; SIGNAL i_dp_on_status : STD_LOGIC; + SIGNAL nxt_dp_on_status : STD_LOGIC; - SIGNAL nxt_offset_bsn_cnt : STD_LOGIC_VECTOR(g_offset_w-1 DOWNTO 0); - SIGNAL offset_bsn_cnt : STD_LOGIC_VECTOR(g_offset_w-1 DOWNTO 0); + SIGNAL nxt_bsn_time_offset_cnt : STD_LOGIC_VECTOR(g_time_offset_w-1 DOWNTO 0); + SIGNAL bsn_time_offset_cnt : STD_LOGIC_VECTOR(g_time_offset_w-1 DOWNTO 0); SIGNAL nxt_clk_cnt : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); SIGNAL clk_cnt : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); @@ -101,41 +114,56 @@ BEGIN src_out <= i_src_out; dp_on_status <= i_dp_on_status; - p_state : PROCESS(state, prev_state, dp_on, dp_on_pps, pps, block_size_cnt, clk_cnt, init_bsn, i_src_out, i_dp_on_status, offset_bsn_cnt) + p_state : PROCESS(state, prev_state, dp_on, dp_on_pps, pps, block_size_cnt, clk_cnt, bsn_init, i_src_out, i_dp_on_status, bsn_time_offset_cnt) BEGIN - nxt_state <= state; - nxt_src_out <= i_src_out; - nxt_src_out.sync <= '0'; - nxt_src_out.valid <= '0'; - nxt_src_out.sop <= '0'; - nxt_src_out.eop <= '0'; - nxt_block_size_cnt <= block_size_cnt; - nxt_clk_cnt <= INCR_UVEC(clk_cnt, 1); - nxt_sync <= sync; - nxt_dp_on_status <= i_dp_on_status; - nxt_offset_bsn_cnt <= offset_bsn_cnt; + nxt_state <= state; + nxt_src_out <= i_src_out; + nxt_src_out.sync <= '0'; + nxt_src_out.valid <= '0'; + nxt_src_out.sop <= '0'; + nxt_src_out.eop <= '0'; + nxt_block_size_cnt <= block_size_cnt; + nxt_clk_cnt <= INCR_UVEC(clk_cnt, 1); + nxt_sync <= sync; + nxt_dp_on_status <= i_dp_on_status; + nxt_bsn_time_offset_cnt <= bsn_time_offset_cnt; IF UNSIGNED(clk_cnt) = UNSIGNED(nof_clk_per_sync) - 1 THEN nxt_clk_cnt <= (OTHERS=>'0'); - nxt_sync <= '1'; -- set sync signal on next sop + nxt_sync <= '1'; -- will set src_out.sync on next src_out.sop END IF; CASE state IS - WHEN s_dp_on_eop => - nxt_src_out.eop <= '1'; - nxt_src_out.valid <= '1'; - nxt_state <= s_dp_on_sop; - nxt_block_size_cnt <= INCR_UVEC(block_size_cnt, 1); - IF dp_on = '0' THEN - nxt_state <= s_dp_off; + WHEN s_init => + nxt_state <= s_dp_off; + + WHEN s_dp_off => + nxt_dp_on_status <= '0'; + nxt_src_out.bsn <= RESIZE_DP_BSN(bsn_init); + nxt_sync <= '0'; + nxt_clk_cnt <= (OTHERS=>'0'); + IF dp_on = '1' THEN + IF dp_on_pps = '1' THEN + nxt_sync <= '1'; + IF pps = '1' THEN + IF UNSIGNED(bsn_time_offset) = 0 THEN + nxt_state <= s_dp_on_sop; + ELSE + nxt_bsn_time_offset_cnt <= (OTHERS=>'0'); + nxt_state <= s_bsn_time_offset; + END IF; + END IF; + ELSE + nxt_state <= s_dp_on_sop; + END IF; END IF; - WHEN s_dp_on => - nxt_src_out.valid <= '1'; - nxt_block_size_cnt <= INCR_UVEC(block_size_cnt, 1); - IF UNSIGNED(block_size_cnt) = g_block_size -3 THEN - nxt_state <= s_dp_on_eop; + WHEN s_bsn_time_offset => + IF UNSIGNED(bsn_time_offset_cnt) = UNSIGNED(bsn_time_offset) THEN + nxt_state <= s_dp_on_sop; + ELSE + nxt_bsn_time_offset_cnt <= INCR_UVEC(bsn_time_offset_cnt, 1); END IF; WHEN s_dp_on_sop => @@ -145,38 +173,28 @@ BEGIN nxt_state <= s_dp_on; nxt_block_size_cnt <= (OTHERS=>'0'); IF prev_state = s_dp_on_eop THEN - nxt_src_out.bsn(g_bsn_w-1 DOWNTO 0) <= INCR_UVEC(i_src_out.bsn(g_bsn_w-1 DOWNTO 0), 1); + -- nxt_src_out.bsn(g_bsn_w-1 DOWNTO 0) <= INCR_UVEC(i_src_out.bsn(g_bsn_w-1 DOWNTO 0), 1); + nxt_src_out.bsn <= INCR_DP_BSN(i_src_out.bsn, 1, g_bsn_w); END IF; IF sync = '1' THEN nxt_src_out.sync <= '1'; - nxt_sync <= '0'; -- clear sync if set + nxt_sync <= '0'; END IF; - WHEN s_dp_off => - nxt_dp_on_status <= '0'; - nxt_src_out.bsn <= RESIZE_DP_BSN(init_bsn); - nxt_sync <= '0'; -- clear sync if set - nxt_clk_cnt <= (OTHERS=>'0'); - IF dp_on = '1' THEN - IF dp_on_pps = '1' THEN - IF pps = '1' THEN - IF UNSIGNED(offset_bsn) = 0 THEN - nxt_state <= s_dp_on_sop; - ELSE - nxt_offset_bsn_cnt <= (OTHERS=>'0'); - nxt_state <= s_bsn_offset; - END IF; - END IF; - ELSE - nxt_state <= s_dp_on_sop; - END IF; + WHEN s_dp_on => + nxt_src_out.valid <= '1'; + nxt_block_size_cnt <= INCR_UVEC(block_size_cnt, 1); + IF UNSIGNED(block_size_cnt) = g_block_size -3 THEN + nxt_state <= s_dp_on_eop; END IF; - - WHEN s_bsn_offset => - IF offset_bsn_cnt = offset_bsn THEN - nxt_state <= s_dp_on_sop; - ELSE - nxt_offset_bsn_cnt <= INCR_UVEC(offset_bsn_cnt, 1); + + WHEN s_dp_on_eop => + nxt_src_out.eop <= '1'; + nxt_src_out.valid <= '1'; + nxt_state <= s_dp_on_sop; + nxt_block_size_cnt <= INCR_UVEC(block_size_cnt, 1); + IF dp_on = '0' THEN + nxt_state <= s_dp_off; END IF; WHEN OTHERS => -- s_init @@ -192,22 +210,20 @@ BEGIN prev_state <= s_init; state <= s_init; i_src_out <= c_dp_sosi_rst; - --block_cnt <= (OTHERS=>'0'); clk_cnt <= (OTHERS=>'0'); sync <= '0'; block_size_cnt <= (OTHERS=>'0'); i_dp_on_status <= '0'; - offset_bsn_cnt <= (OTHERS=>'0'); + bsn_time_offset_cnt <= (OTHERS=>'0'); ELSIF rising_edge(clk) THEN prev_state <= state; state <= nxt_state; i_src_out <= nxt_src_out; - --block_cnt <= nxt_block_cnt; clk_cnt <= nxt_clk_cnt; sync <= nxt_sync; block_size_cnt <= nxt_block_size_cnt; i_dp_on_status <= nxt_dp_on_status; - offset_bsn_cnt <= nxt_offset_bsn_cnt; + bsn_time_offset_cnt <= nxt_bsn_time_offset_cnt; END IF; END PROCESS; diff --git a/libraries/base/dp/src/vhdl/dp_stream_pkg.vhd b/libraries/base/dp/src/vhdl/dp_stream_pkg.vhd index bf43a639f3c3e81a6cac5e4cbe09b0541341fb6d..677d106cf4f081b06f34da46a8d4a8adc99317ef 100644 --- a/libraries/base/dp/src/vhdl/dp_stream_pkg.vhd +++ b/libraries/base/dp/src/vhdl/dp_stream_pkg.vhd @@ -264,6 +264,7 @@ PACKAGE dp_stream_pkg Is FUNCTION INCR_DP_DATA( vec : STD_LOGIC_VECTOR; dec : INTEGER; w : NATURAL) RETURN STD_LOGIC_VECTOR; -- unsigned vec(w-1:0) + dec FUNCTION INCR_DP_SDATA( vec : STD_LOGIC_VECTOR; dec : INTEGER; w : NATURAL) RETURN STD_LOGIC_VECTOR; -- signed vec(w-1:0) + dec FUNCTION INCR_DP_DSP_DATA(vec : STD_LOGIC_VECTOR; dec : INTEGER; w : NATURAL) RETURN STD_LOGIC_VECTOR; -- signed vec(w-1:0) + dec + FUNCTION INCR_DP_BSN( vec : STD_LOGIC_VECTOR; dec : INTEGER; w : NATURAL) RETURN STD_LOGIC_VECTOR; -- unsigned vec(w-1:0) + dec FUNCTION REPLICATE_DP_DATA( seq : STD_LOGIC_VECTOR ) RETURN STD_LOGIC_VECTOR; -- replicate seq as often as fits in c_dp_stream_data_w FUNCTION UNREPLICATE_DP_DATA(data : STD_LOGIC_VECTOR; seq_w : NATURAL) RETURN STD_LOGIC_VECTOR; -- unreplicate data to width seq_w, return low seq_w bits and set mismatch MSbits bits to '1' @@ -573,6 +574,11 @@ PACKAGE BODY dp_stream_pkg IS RETURN RESIZE_DP_DSP_DATA(STD_LOGIC_VECTOR(SIGNED(vec(w-1 DOWNTO 0)) + dec)); END INCR_DP_DSP_DATA; + FUNCTION INCR_DP_BSN(vec : STD_LOGIC_VECTOR; dec : INTEGER; w : NATURAL) RETURN STD_LOGIC_VECTOR IS + BEGIN + RETURN RESIZE_DP_BSN(STD_LOGIC_VECTOR(UNSIGNED(vec(w-1 DOWNTO 0)) + dec)); + END INCR_DP_BSN; + FUNCTION REPLICATE_DP_DATA(seq : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS CONSTANT c_seq_w : NATURAL := seq'LENGTH; CONSTANT c_nof_replications : NATURAL := ceil_div(c_dp_stream_data_w, c_seq_w); diff --git a/libraries/base/dp/src/vhdl/mms_dp_bsn_source_v2.vhd b/libraries/base/dp/src/vhdl/mms_dp_bsn_source_v2.vhd index 501e8860993b9ab7b23be43e6e53c51e25988f5b..3ca46fb3ca6be42201aac1ad78c7dcfd4d18fc6a 100644 --- a/libraries/base/dp/src/vhdl/mms_dp_bsn_source_v2.vhd +++ b/libraries/base/dp/src/vhdl/mms_dp_bsn_source_v2.vhd @@ -59,7 +59,7 @@ ARCHITECTURE str OF mms_dp_bsn_source_v2 IS SIGNAL dp_on : STD_LOGIC; SIGNAL dp_on_pps : STD_LOGIC; SIGNAL nof_clk_per_sync : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); - SIGNAL init_bsn : STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0); + SIGNAL bsn_init : STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0); SIGNAL i_bs_sosi : t_dp_sosi; @@ -92,7 +92,7 @@ BEGIN st_on_pps => dp_on_pps, st_on_status => dp_on_status, st_nof_clk_per_sync => nof_clk_per_sync, - st_init_bsn => init_bsn, + st_bsn_init => bsn_init, st_current_bsn => capture_bsn ); @@ -110,7 +110,7 @@ BEGIN dp_on => dp_on, dp_on_pps => dp_on_pps, dp_on_status => dp_on_status, - init_bsn => init_bsn, + bsn_init => bsn_init, nof_clk_per_sync => nof_clk_per_sync, -- Streaming src_out => i_bs_sosi diff --git a/libraries/base/dp/tb/vhdl/tb_dp_bsn_source_v2.vhd b/libraries/base/dp/tb/vhdl/tb_dp_bsn_source_v2.vhd index 591d5e92629b94ff8f1946f7a0b3cac5bd67da12..8fe8c59f7f2ebd83e860cd25ba13d0923af099b5 100644 --- a/libraries/base/dp/tb/vhdl/tb_dp_bsn_source_v2.vhd +++ b/libraries/base/dp/tb/vhdl/tb_dp_bsn_source_v2.vhd @@ -36,18 +36,16 @@ USE dp_lib.tb_dp_pkg.ALL; ENTITY tb_dp_bsn_source_v2 IS GENERIC ( - g_sync_offset : NATURAL := 0; -- must be < c_sync_period for proc_dp_verify_sync - g_clk_per_sync : NATURAL := 240 + g_pps_interval : NATURAL := 240; + g_block_size : NATURAL := 32 ); END tb_dp_bsn_source_v2; ARCHITECTURE tb OF tb_dp_bsn_source_v2 IS CONSTANT c_clk_period : TIME := 10 ns; - - CONSTANT c_block_size : NATURAL := 32; -- 31; - CONSTANT c_bsn_w : NATURAL := 31; -- 16; - CONSTANT c_sync_period : NATURAL := 8; + CONSTANT c_bsn_w : NATURAL := 31; + CONSTANT c_dut_latency : NATURAL := 2; -- The state name tells what kind of test is being done TYPE t_state_enum IS ( @@ -61,21 +59,35 @@ ARCHITECTURE tb OF tb_dp_bsn_source_v2 IS SIGNAL tb_end : STD_LOGIC := '0'; SIGNAL rst : STD_LOGIC := '1'; SIGNAL clk : STD_LOGIC := '1'; - SIGNAL pps : STD_LOGIC; -- DUT SIGNAL dp_on : STD_LOGIC := '0'; SIGNAL dp_on_pps : STD_LOGIC := '0'; - SIGNAL init_bsn : STD_LOGIC_VECTOR(c_bsn_w-1 DOWNTO 0) := (OTHERS=>'0'); + SIGNAL bsn_init : STD_LOGIC_VECTOR(c_bsn_w-1 DOWNTO 0) := (OTHERS=>'0'); SIGNAL bs_sosi : t_dp_sosi; -- Verify - SIGNAL verify_sync : STD_LOGIC := '1'; + SIGNAL verify_sync : STD_LOGIC := '0'; SIGNAL hold_bs_sop : STD_LOGIC; SIGNAL tb_bsn_cnt : INTEGER := 0; + -- Define the PPS grid and the BSN grid that both start at 0 according to Figure 3.1 in [doc]: + SIGNAL SSN : NATURAL := 0; + SIGNAL BSN : NATURAL := 0; + + SIGNAL pps_sop : STD_LOGIC := '0'; + SIGNAL nxt_pps_sop : STD_LOGIC := '0'; + SIGNAL pps_eop : STD_LOGIC := '0'; + 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; + BEGIN ----------------------------------------------------------------------------- @@ -84,70 +96,93 @@ BEGIN rst <= '1', '0' AFTER c_clk_period*7; clk <= (NOT clk) OR tb_end AFTER c_clk_period/2; + + -- SSN/BSN generator + 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', rst, clk, nxt_pps_sop); -- make PPS grid with pps_sop at start of interval + pps_sop <= nxt_pps_sop AFTER 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 + + 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; + bsn_eop <= bsn_sop'DELAYED((g_block_size-1)*c_clk_period); -- make BSN grid with bsn_eop at end of interval + + -- 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 + WAIT UNTIL rising_edge(clk); + expected_sync <= '0'; + proc_common_wait_until_lo_hi(clk, pps_sop); + IF bsn_sop = '1' THEN + expected_sync <= '1'; + expected_bsn <= BSN+1; + expected_offset_bsn <= 0; + ELSE + proc_common_wait_until_lo_hi(clk, bsn_sop); + expected_sync <= '1'; + expected_bsn <= BSN+1; + expected_offset_bsn <= (BSN+1) * g_block_size - SSN * g_pps_interval; + END IF; + END PROCESS; + + expected_sync_dly <= expected_sync'DELAYED(c_dut_latency*c_clk_period); + -- MM control p_mm : PROCESS + VARIABLE v_bsn_time_offset : NATURAL; + VARIABLE v_bsn_init : NATURAL; BEGIN tb_end <= '0'; tb_state <= s_disable; - pps <= '0'; + --pps <= '0'; dp_on <= '0'; dp_on_pps <= '0'; - init_bsn <= TO_UVEC(g_sync_offset, c_bsn_w); -- Get synchronous to clk proc_common_wait_until_low(clk, rst); proc_common_wait_some_cycles(clk, 500); - -- Start by making dp_on high - tb_state <= s_start; - dp_on <= '1'; - proc_common_wait_some_cycles(clk, 2000); - - -- Stop by making dp_on low - tb_state <= s_disable; - dp_on <= '0'; - proc_common_wait_some_cycles(clk, 1000); - - -- Now start on PPS - tb_state <= s_pps_start; - dp_on_pps <= '1'; + -- Start asynchronously by making dp_on high + proc_common_wait_until_hi_lo(clk, expected_sync); + tb_state <= s_pps_start; + dp_on_pps <= '0'; dp_on <= '1'; - proc_common_wait_some_cycles(clk, 10); - pps <= '1'; - proc_common_wait_some_cycles(clk, 1); - pps <= '0'; - proc_common_wait_some_cycles(clk, 1000); - - -- Stop by making dp_on low - tb_state <= s_disable; - dp_on <= '0'; - dp_on_pps <= '0'; --No PPS trigger next time - proc_common_wait_some_cycles(clk, 1000); - - -- Start by making dp_on high - tb_state <= s_start; - dp_on <= '1'; - proc_common_wait_some_cycles(clk, 2500); - + verify_sync <= '0'; -- only verify visualy in wave window + proc_common_wait_some_cycles(clk, 10*g_pps_interval); + verify_sync <= '0'; -- Stop by making dp_on low tb_state <= s_disable; dp_on <= '0'; dp_on_pps <= '0'; - proc_common_wait_some_cycles(clk, 1000); - - -- Now start on next PPS and continue forever - init_bsn <= TO_UVEC(g_sync_offset, c_bsn_w); - tb_state <= s_pps_start; - dp_on_pps <= '1'; - dp_on <= '1'; - proc_common_wait_some_cycles(clk, 20); - pps <= '1'; - proc_common_wait_some_cycles(clk, 1); - pps <= '0'; - + proc_common_wait_some_cycles(clk, 3*g_pps_interval); + + -- Start synchronously by making dp_on high at pps + FOR i IN 0 TO 2 LOOP + -- Now start on PPS + proc_common_wait_until_hi_lo(clk, expected_sync); + v_bsn_time_offset := ((SSN + 1) * g_pps_interval) MOD g_block_size; + v_bsn_init := ((SSN + 1) * g_pps_interval) / g_block_size; + IF v_bsn_time_offset = 0 THEN + bsn_init <= TO_UVEC(v_bsn_init, c_bsn_w); + ELSE + bsn_init <= TO_UVEC(v_bsn_init+1, c_bsn_w); + END IF; + tb_state <= s_pps_start; + dp_on_pps <= '1'; + dp_on <= '1'; + verify_sync <= '1'; -- verify automatically in test bench + proc_common_wait_some_cycles(clk, 10*g_pps_interval); + verify_sync <= '0'; + -- Stop by making dp_on low + tb_state <= s_disable; + dp_on <= '0'; + dp_on_pps <= '0'; + proc_common_wait_some_cycles(clk, 3*g_pps_interval); + END LOOP; - proc_common_wait_some_cycles(clk, 10000); tb_end <= '1'; WAIT; END PROCESS; @@ -157,7 +192,7 @@ BEGIN -- Verification ----------------------------------------------------------------------------- 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_v2(c_sync_period, g_sync_offset, clk, verify_sync, bs_sosi.sync, bs_sosi.sop, bs_sosi.bsn, tb_bsn_cnt); -- Verify sync at sop and at expected BSN + proc_dp_verify_sync(clk, verify_sync, bs_sosi.sync, bs_sosi.sop, expected_sync_dly); -- Verify sync at sop and at expected_sync ----------------------------------------------------------------------------- -- DUT: dp_bsn_source_v2 @@ -165,18 +200,18 @@ BEGIN dut : ENTITY work.dp_bsn_source_v2 GENERIC MAP ( - g_block_size => c_block_size, - g_nof_clk_per_sync => g_clk_per_sync, + g_block_size => g_block_size, + g_nof_clk_per_sync => g_pps_interval, g_bsn_w => c_bsn_w ) PORT MAP ( rst => rst, clk => clk, - pps => pps, + pps => pps_sop, -- MM control dp_on => dp_on, dp_on_pps => dp_on_pps, - init_bsn => init_bsn, + bsn_init => bsn_init, -- Streaming src_out => bs_sosi ); diff --git a/libraries/base/dp/tb/vhdl/tb_dp_pkg.vhd b/libraries/base/dp/tb/vhdl/tb_dp_pkg.vhd index 4388148c8718e2508b47ef5eb4f10911b7678228..381a32262b5abb01aeb880676d4fe1a6f74bdbbb 100644 --- a/libraries/base/dp/tb/vhdl/tb_dp_pkg.vhd +++ b/libraries/base/dp/tb/vhdl/tb_dp_pkg.vhd @@ -466,6 +466,13 @@ PACKAGE tb_dp_pkg IS SIGNAL sop : IN STD_LOGIC; SIGNAL bsn : IN STD_LOGIC_VECTOR); +-- Verify the DUT output sync + PROCEDURE proc_dp_verify_sync(SIGNAL clk : IN STD_LOGIC; + SIGNAL verify_en : IN STD_LOGIC; + SIGNAL sync : IN STD_LOGIC; + SIGNAL sop : IN STD_LOGIC; + SIGNAL expected_sync : IN STD_LOGIC); + -- Verify the DUT output sync PROCEDURE proc_dp_verify_sync_v2(CONSTANT c_sync_period : IN NATURAL; CONSTANT c_sync_offset : IN NATURAL; @@ -2233,6 +2240,35 @@ PACKAGE BODY tb_dp_pkg IS END proc_dp_verify_sync; + ------------------------------------------------------------------------------ + -- PROCEDURE: Verify the DUT output sync + -- . sync is defined such that it can only be active at sop + ------------------------------------------------------------------------------ + PROCEDURE proc_dp_verify_sync(SIGNAL clk : IN STD_LOGIC; + SIGNAL verify_en : IN STD_LOGIC; + SIGNAL sync : IN STD_LOGIC; + SIGNAL sop : IN STD_LOGIC; + SIGNAL expected_sync : IN STD_LOGIC) IS + BEGIN + IF rising_edge(clk) THEN + IF verify_en='1' THEN + -- Check for unexpected sync + IF sync='1' THEN + ASSERT expected_sync='1' + REPORT "Error: Unexpected sync at BSN" SEVERITY ERROR; + ASSERT sop = '1' + REPORT "Error: Unexpected sync at inactive sop" SEVERITY ERROR; + END IF; + -- Check for missing sync + IF sop='1' AND expected_sync='1' THEN + ASSERT sync = '1' + REPORT "Error: Missing sync" SEVERITY ERROR; + END IF; + END IF; + END IF; + END proc_dp_verify_sync; + + ------------------------------------------------------------------------------ -- PROCEDURE: Verify the DUT output sync -- . sync is defined such that it can only be active at sop @@ -2248,24 +2284,24 @@ PACKAGE BODY tb_dp_pkg IS SIGNAL tb_bsn_cnt : INOUT INTEGER) IS CONSTANT c_bsn_w : NATURAL := sel_a_b(bsn'LENGTH>31, 31, bsn'LENGTH); -- use maximally 31 bit of BSN slv to allow calculations with integers - VARIABLE v_valid_sync_period : BOOLEAN; - VARIABLE v_tb_bsn_cnt : INTEGER; + VARIABLE v_expected_sync : BOOLEAN; + VARIABLE v_tb_bsn_cnt : INTEGER; BEGIN IF rising_edge(clk) THEN IF verify_en='1' THEN + -- Determine whether sync is expected at this bsn - v_valid_sync_period := FALSE; + v_expected_sync := FALSE; v_tb_bsn_cnt := tb_bsn_cnt; -- assign signal to variable -- on sync check if tb_bsn_cnt is a valid value -- valid is c_sync_period or c_sync_period-1 IF sync='1' THEN IF v_tb_bsn_cnt=c_sync_period OR v_tb_bsn_cnt=c_sync_period-1 THEN - v_valid_sync_period := TRUE; + v_expected_sync := TRUE; --REPORT "bsn count valid " & int_to_str(v_tb_bsn_cnt); ELSE - v_valid_sync_period := FALSE; - REPORT "bsn count not valid " & int_to_str(v_tb_bsn_cnt) SEVERITY ERROR; + v_expected_sync := FALSE; END IF; v_tb_bsn_cnt := 0; -- reset tb_bsn_cnt @@ -2285,13 +2321,13 @@ PACKAGE BODY tb_dp_pkg IS -- Check for unexpected sync IF sync='1' THEN - ASSERT v_valid_sync_period = TRUE - REPORT "Error: Unexpected sync at BSN" SEVERITY ERROR; + ASSERT v_expected_sync = TRUE + REPORT "Error: Unexpected BSN count " & int_to_str(v_tb_bsn_cnt) SEVERITY ERROR; ASSERT sop = '1' REPORT "Error: Unexpected sync at inactive sop" SEVERITY ERROR; END IF; -- Check for missing sync - IF sop='1' AND v_valid_sync_period=TRUE THEN + IF sop='1' AND v_expected_sync=TRUE THEN ASSERT sync = '1' REPORT "Error: Missing sync" SEVERITY ERROR; END IF; diff --git a/libraries/base/dp/tb/vhdl/tb_mms_dp_bsn_source_v2.vhd b/libraries/base/dp/tb/vhdl/tb_mms_dp_bsn_source_v2.vhd index 5984c4d6af1551d1a1cc1177eb6b084105fdc858..7d40dff868aa8df39ea18f1f61bd62ea719e65bc 100644 --- a/libraries/base/dp/tb/vhdl/tb_mms_dp_bsn_source_v2.vhd +++ b/libraries/base/dp/tb/vhdl/tb_mms_dp_bsn_source_v2.vhd @@ -52,7 +52,7 @@ ARCHITECTURE tb OF tb_mms_dp_bsn_source_v2 IS CONSTANT c_block_size : NATURAL := 100; CONSTANT c_nof_block_per_sync : NATURAL := 15; CONSTANT c_sync_interval : NATURAL := c_nof_block_per_sync * c_block_size; - CONSTANT c_init_bsn : NATURAL := c_nof_block_per_sync; + CONSTANT c_bsn_init : NATURAL := c_nof_block_per_sync; CONSTANT c_mm_addr_dp_on : NATURAL := 0; CONSTANT c_mm_addr_nof_block_per_sync : NATURAL := 1; @@ -90,7 +90,7 @@ BEGIN proc_common_wait_some_cycles(clk, 10); -- Write initial BSN and number of block per sync interval - proc_mem_mm_bus_wr(c_mm_addr_bsn_lo, c_init_bsn, clk, mm_miso, mm_mosi); + proc_mem_mm_bus_wr(c_mm_addr_bsn_lo, c_bsn_init, clk, mm_miso, mm_mosi); proc_mem_mm_bus_wr(c_mm_addr_bsn_hi, 0, clk, mm_miso, mm_mosi); -- must also write hi part to trigger transfer accross clock domain proc_mem_mm_bus_wr(c_mm_addr_nof_block_per_sync, c_nof_block_per_sync, clk, mm_miso, mm_mosi); proc_common_wait_some_cycles(clk, c_cross_clock_domain_latency); diff --git a/libraries/base/dp/tb/vhdl/tb_tb_dp_bsn_source_v2.vhd b/libraries/base/dp/tb/vhdl/tb_tb_dp_bsn_source_v2.vhd index d1c16412253c030cf4e65a126000a7e840d70f7d..2e4e682cd0c78aa7ef706b23e65aae1be75393ac 100644 --- a/libraries/base/dp/tb/vhdl/tb_tb_dp_bsn_source_v2.vhd +++ b/libraries/base/dp/tb/vhdl/tb_tb_dp_bsn_source_v2.vhd @@ -35,6 +35,10 @@ END tb_tb_dp_bsn_source_v2; ARCHITECTURE tb OF tb_tb_dp_bsn_source_v2 IS SIGNAL tb_end : STD_LOGIC := '0'; -- declare tb_end to avoid 'No objects found' error on 'when -label tb_end' BEGIN + -- from tb_dp_bsn_source_v2.vhd + -- + -- g_sync_offset : NATURAL := 0 + -- g_clk_per_sync : NATURAL := 240 -- (sync_offset, clk_per_sync) -- test different clk_per_sync