diff --git a/libraries/base/dp/hdllib.cfg b/libraries/base/dp/hdllib.cfg index 93a162a26a1a72b8f4329bfc08213f36eddc46f8..b5890bb8eb13e7910a555888274c1a32b5b94567 100644 --- a/libraries/base/dp/hdllib.cfg +++ b/libraries/base/dp/hdllib.cfg @@ -74,8 +74,11 @@ synth_files = src/vhdl/dp_block_gen.vhd src/vhdl/dp_block_gen_valid_arr.vhd src/vhdl/dp_bsn_source.vhd + src/vhdl/dp_bsn_source_v2.vhd src/vhdl/dp_bsn_source_reg.vhd + src/vhdl/dp_bsn_source_reg_v2.vhd src/vhdl/mms_dp_bsn_source.vhd + src/vhdl/mms_dp_bsn_source_v2.vhd src/vhdl/dp_bsn_scheduler.vhd src/vhdl/dp_bsn_scheduler_reg.vhd src/vhdl/mms_dp_bsn_scheduler.vhd @@ -185,7 +188,9 @@ test_bench_files = tb/vhdl/tb_mms_dp_bsn_align.vhd tb/vhdl/tb_dp_bsn_monitor.vhd tb/vhdl/tb_dp_bsn_source.vhd + tb/vhdl/tb_dp_bsn_source_v2.vhd tb/vhdl/tb_mms_dp_bsn_source.vhd + tb/vhdl/tb_mms_dp_bsn_source_v2.vhd tb/vhdl/tb_dp_demux.vhd tb/vhdl/tb2_dp_demux.vhd tb/vhdl/tb3_dp_demux.vhd @@ -253,6 +258,7 @@ test_bench_files = tb/vhdl/tb_tb_dp_block_gen.vhd tb/vhdl/tb_tb_dp_block_gen_valid_arr.vhd tb/vhdl/tb_tb_dp_bsn_align.vhd + tb/vhdl/tb_tb_dp_bsn_source_v2.vhd tb/vhdl/tb_tb_dp_concat.vhd tb/vhdl/tb_tb_dp_demux.vhd tb/vhdl/tb_tb2_dp_demux.vhd @@ -305,6 +311,7 @@ regression_test_vhdl = tb/vhdl/tb_dp_shiftreg.vhd tb/vhdl/tb_dp_bsn_source.vhd tb/vhdl/tb_mms_dp_bsn_source.vhd + tb/vhdl/tb_mms_dp_bsn_source_v2.vhd tb/vhdl/tb_tb_dp_block_select.vhd tb/vhdl/tb_tb_dp_block_reshape.vhd @@ -312,6 +319,7 @@ regression_test_vhdl = tb/vhdl/tb_tb_dp_block_gen.vhd tb/vhdl/tb_tb_dp_block_gen_valid_arr.vhd tb/vhdl/tb_tb_dp_bsn_align.vhd + tb/vhdl/tb_tb_dp_bsn_source_v2.vhd tb/vhdl/tb_tb_dp_concat.vhd tb/vhdl/tb_tb_dp_demux.vhd tb/vhdl/tb_tb2_dp_demux.vhd 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 new file mode 100644 index 0000000000000000000000000000000000000000..eb5600b1832a4b802f2271f09ce347e7b3efb083 --- /dev/null +++ b/libraries/base/dp/src/vhdl/dp_bsn_source_reg_v2.vhd @@ -0,0 +1,339 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2012 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +-- RO read only (no VHDL present to access HW in write mode) +-- WO write only (no VHDL present to access HW in read mode) +-- WE write event (=WO) +-- WR write control, read control +-- RW read status, write control +-- RC read, clear on read +-- FR FIFO read +-- FW FIFO write +-- +-- wi Bits R/W Name Default Description +-- ==================================================================================== +-- 0 [0] RW dp_on 0x0 WR '1' enables DP (on PPS when dp_on_pps=1) +-- 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 bsn_init, read current bsn +-- 3 [31..0] RW bsn[63..32] 0x0 write bsn_init, read current bsn +-- 4 [31..0] RW bsn_time_offset 0x0 +-- ==================================================================================== + +LIBRARY IEEE, common_lib; +USE IEEE.STD_LOGIC_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; + +ENTITY dp_bsn_source_reg_v2 IS + GENERIC ( + g_cross_clock_domain : BOOLEAN := TRUE; -- use FALSE when mm_clk and st_clk are the same, else use TRUE to cross the clock domain + g_nof_clk_per_sync : NATURAL := 200 * 10**6 + ); + PORT ( + -- Clocks and reset + mm_rst : IN STD_LOGIC; -- reset synchronous with mm_clk + mm_clk : IN STD_LOGIC; -- memory-mapped bus clock + st_rst : IN STD_LOGIC; -- reset synchronous with st_clk + st_clk : IN STD_LOGIC; -- other clock domain clock + + -- Memory Mapped Slave in mm_clk domain + sla_in : IN t_mem_mosi; -- actual ranges defined by c_mm_reg + sla_out : OUT t_mem_miso; -- actual ranges defined by c_mm_reg + + -- MM registers in st_clk domain + st_on : OUT STD_LOGIC := '1'; -- level + 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_bsn_init : OUT STD_LOGIC_VECTOR; -- wr init BSN + st_current_bsn : IN STD_LOGIC_VECTOR; -- rd current BSN + st_bsn_time_offset : OUT STD_LOGIC_VECTOR; + st_current_bsn_time_offset : IN STD_LOGIC_VECTOR + ); +END dp_bsn_source_reg_v2; + + +ARCHITECTURE rtl OF dp_bsn_source_reg_v2 IS + + CONSTANT c_bsn_w : NATURAL := st_bsn_init'LENGTH; + CONSTANT c_bsn_time_offset_w : NATURAL := st_bsn_time_offset'LENGTH; + + -- Define the actual size of the MM slave register + CONSTANT c_mm_reg : t_c_mem := (latency => 1, + adr_w => 3, + dat_w => c_word_w, -- Use MM bus data width = c_word_w = 32 for all MM registers + nof_dat => 3**2, + init_sl => '0'); + + -- Registers in mm_clk domain + SIGNAL mm_on : STD_LOGIC; + SIGNAL mm_on_pps : STD_LOGIC; + SIGNAL mm_on_ctrl : STD_LOGIC_VECTOR(1 DOWNTO 0); -- = mm_on_pps & mm_on + SIGNAL st_on_ctrl : STD_LOGIC_VECTOR(1 DOWNTO 0); -- = st_on_pps & st_on + SIGNAL mm_on_status : STD_LOGIC; + + SIGNAL mm_nof_clk_per_sync : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); + + 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'); + + SIGNAL mm_bsn_time_offset : STD_LOGIC_VECTOR(c_bsn_time_offset_w-1 DOWNTO 0) := (OTHERS=>'0'); + SIGNAL mm_bsn_time_offset_wr : STD_LOGIC; + SIGNAL mm_current_bsn_time_offset : STD_LOGIC_VECTOR(c_bsn_time_offset_w-1 DOWNTO 0) := (OTHERS=>'0'); + + -- Registers in st_clk domain + +BEGIN + + ------------------------------------------------------------------------------ + -- MM register access in the mm_clk domain + -- . Hardcode the shared MM slave register directly in RTL instead of using + -- the common_reg_r_w instance. Directly using RTL is easier when the large + -- MM register has multiple different fields and with different read and + -- write options per field in one MM register. + ------------------------------------------------------------------------------ + + p_mm_reg : PROCESS (mm_rst, mm_clk) + BEGIN + IF mm_rst = '1' THEN + -- Read access + sla_out <= c_mem_miso_rst; + -- Access event, register values + mm_on <= '0'; + mm_on_pps <= '0'; + mm_nof_clk_per_sync <= TO_UVEC(g_nof_clk_per_sync, c_word_w); + mm_bsn_init <= (OTHERS=>'0'); + mm_bsn_init_wr <= '0'; + mm_current_bsn_hi <= (OTHERS=>'0'); + mm_bsn_time_offset <= (OTHERS=>'0'); + mm_bsn_time_offset_wr <= '0'; + ELSIF rising_edge(mm_clk) THEN + -- Read access defaults + sla_out.rdval <= '0'; + + -- Access event defaults + mm_bsn_init_wr <= '0'; + mm_bsn_time_offset_wr <= '0'; + + -- Write access: set register value + IF sla_in.wr = '1' THEN + CASE TO_UINT(sla_in.address(c_mm_reg.adr_w-1 DOWNTO 0)) IS + -- Write Block Sync + WHEN 0 => + mm_on <= sla_in.wrdata(0); + mm_on_pps <= sla_in.wrdata(1); + WHEN 1 => + mm_nof_clk_per_sync <= sla_in.wrdata(31 DOWNTO 0); + + -- Write init BSN + WHEN 2 => + mm_bsn_init(31 DOWNTO 0) <= sla_in.wrdata(31 DOWNTO 0); + WHEN 3 => + mm_bsn_init(63 DOWNTO 32) <= sla_in.wrdata(31 DOWNTO 0); + mm_bsn_init_wr <= '1'; + + -- write bsn_time_offset + WHEN 4 => + mm_bsn_time_offset(c_bsn_time_offset_w-1 DOWNTO 0) <= sla_in.wrdata(c_bsn_time_offset_w-1 DOWNTO 0); + mm_bsn_time_offset_wr <= '1'; + + WHEN OTHERS => NULL; -- not used MM addresses + END CASE; + + -- Read access: get register value + ELSIF sla_in.rd = '1' THEN + sla_out <= c_mem_miso_rst; -- set unused rddata bits to '0' when read + sla_out.rdval <= '1'; -- c_mm_reg.latency = 1 + CASE TO_UINT(sla_in.address(c_mm_reg.adr_w-1 DOWNTO 0)) IS + -- Read Block Sync + WHEN 0 => + sla_out.rddata(0) <= mm_on_status; + sla_out.rddata(1) <= mm_on_pps; + WHEN 1 => + sla_out.rddata(31 DOWNTO 0) <= mm_nof_clk_per_sync; + + -- Read current BSN + WHEN 2 => + sla_out.rddata(31 DOWNTO 0) <= mm_current_bsn(31 DOWNTO 0); + mm_current_bsn_hi <= mm_current_bsn(63 DOWNTO 32); -- first read low part and preserve high part + WHEN 3 => + sla_out.rddata(31 DOWNTO 0) <= mm_current_bsn_hi; + + -- Read current bsn_time_offset + WHEN 4 => + sla_out.rddata(c_bsn_time_offset_w-1 DOWNTO 0) <= mm_current_bsn_time_offset(c_bsn_time_offset_w-1 DOWNTO 0); + + WHEN OTHERS => NULL; -- not used MM addresses + END CASE; + END IF; + END IF; + END PROCESS; + + ------------------------------------------------------------------------------ + -- Transfer register value between mm_clk and st_clk domain. + -- If the function of the register ensures that the value will not be used + -- immediately when it was set, then the transfer between the clock domains + -- can be done by wires only. Otherwise if the change in register value can + -- have an immediate effect then the bit or word value needs to be transfered + -- using: + -- + -- . common_async --> for single-bit level signal + -- . common_spulse --> for single-bit pulse signal + -- . common_reg_cross_domain --> for a multi-bit (a word) signal + -- + -- Typically always use a crossing component for the single bit signals (to + -- be on the save side) and only use a crossing component for the word + -- signals if it is necessary (to avoid using more logic than necessary). + ------------------------------------------------------------------------------ + + no_cross : IF g_cross_clock_domain = FALSE GENERATE -- so mm_clk = st_clk + st_on <= mm_on; + st_on_pps <= mm_on_pps; + st_nof_clk_per_sync <= mm_nof_clk_per_sync; + st_bsn_init <= mm_bsn_init(c_bsn_w-1 DOWNTO 0); + st_bsn_time_offset <= mm_bsn_time_offset(c_bsn_time_offset_w-1 DOWNTO 0); + + p_st_clk : PROCESS(st_rst, st_clk) + BEGIN + IF st_rst='1' THEN + st_bsn_init <= TO_UVEC(0, c_bsn_w); + st_bsn_time_offset <= TO_UVEC(0, c_bsn_time_offset_w); + ELSIF rising_edge(st_clk) THEN + 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; + IF mm_bsn_time_offset_wr='1' THEN + st_bsn_time_offset <= mm_bsn_time_offset(c_bsn_time_offset_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; + + mm_current_bsn(c_bsn_w-1 DOWNTO 0) <= st_current_bsn; -- MM user may read current_bsn twice to avoid small chance that the high part of the double word changed (i.e. incremented) + mm_current_bsn_time_offset(c_bsn_time_offset_w-1 DOWNTO 0) <= st_current_bsn_time_offset; + END GENERATE; -- no_cross + + gen_cross : IF g_cross_clock_domain = TRUE GENERATE + -- Block sync registers + u_dp_on_ctrl : ENTITY common_lib.common_reg_cross_domain + PORT MAP ( + in_rst => mm_rst, + in_clk => mm_clk, + in_dat => mm_on_ctrl, + in_done => OPEN, -- pulses when no more pending in_new + out_rst => st_rst, + out_clk => st_clk, + out_dat => st_on_ctrl, + out_new => OPEN + ); + + mm_on_ctrl(0) <= mm_on; + mm_on_ctrl(1) <= mm_on_pps; + + st_on <= st_on_ctrl(0); + st_on_pps <= st_on_ctrl(1); + + u_mm_on_status : ENTITY common_lib.common_async + GENERIC MAP ( + g_rst_level => '0' + ) + PORT MAP ( + rst => mm_rst, + clk => mm_clk, + din => st_on_status, + dout => mm_on_status + ); + + -- write occurs with sufficient margin before it is used, still use common_reg_cross_domain nonetheless + u_nof_block_per_sync : ENTITY common_lib.common_reg_cross_domain + PORT MAP ( + in_rst => mm_rst, + in_clk => mm_clk, + in_dat => mm_nof_clk_per_sync, + in_done => OPEN, -- pulses when no more pending in_new + out_rst => st_rst, + out_clk => st_clk, + out_dat => st_nof_clk_per_sync, + out_new => OPEN + ); + + -- write occurs with sufficient margin before it is used, still use common_reg_cross_domain nonetheless + u_bsn_init : ENTITY common_lib.common_reg_cross_domain + PORT MAP ( + in_rst => mm_rst, + in_clk => mm_clk, + 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_bsn_init, + out_new => OPEN + ); + + -- thanks to mm_current_bsn_hi the double word can be read reliably + u_current_bsn : ENTITY common_lib.common_reg_cross_domain + PORT MAP ( + in_rst => st_rst, + in_clk => st_clk, + in_new => '1', -- could use t_dp_sosi sop here to indicate in_new, but using default '1' is fine too + in_dat => st_current_bsn, + in_done => OPEN, -- pulses when no more pending in_new + out_rst => mm_rst, + out_clk => mm_clk, + out_dat => mm_current_bsn(c_bsn_w-1 DOWNTO 0), + out_new => OPEN + ); + + -- write occurs with sufficient margin before it is used, still use common_reg_cross_domain nonetheless + u_bsn_time_offset : ENTITY common_lib.common_reg_cross_domain + PORT MAP ( + in_rst => mm_rst, + in_clk => mm_clk, + in_new => mm_bsn_time_offset_wr, -- use wr of mm_bsn_time_offset high part for in_new to ensure proper transfer of double word + in_dat => mm_bsn_time_offset(c_bsn_time_offset_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_bsn_time_offset, + out_new => OPEN + ); + + -- write occurs with sufficient margin before it is used, still use common_reg_cross_domain nonetheless + u_current_bsn_offset : ENTITY common_lib.common_reg_cross_domain + PORT MAP ( + in_rst => st_rst, + in_clk => st_clk, + in_new => '1', + in_dat => st_current_bsn_time_offset, + in_done => OPEN, -- pulses when no more pending in_new + out_rst => mm_rst, + out_clk => mm_clk, + out_dat => mm_current_bsn_time_offset(c_bsn_time_offset_w-1 DOWNTO 0), + out_new => OPEN + ); + + END GENERATE; -- gen_cross + +END rtl; diff --git a/libraries/base/dp/src/vhdl/dp_bsn_source_v2.vhd b/libraries/base/dp/src/vhdl/dp_bsn_source_v2.vhd new file mode 100644 index 0000000000000000000000000000000000000000..f73edbf022860bb34582210adf067f6f0e8fab46 --- /dev/null +++ b/libraries/base/dp/src/vhdl/dp_bsn_source_v2.vhd @@ -0,0 +1,240 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2012 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +-- Purpose : +-- Start a periodic block sync interval and maintain a block sequence +-- number +-- Description: +-- When dp_on is low then all outputs are low. When dp_on is high, the +-- output sync starts pulsing after bsn_time_offset (in clk cycles) with +-- a period of g_block_size number of clk cycles and the output valid, +-- sop and eop will be active. +-- Alternatively, one can assert dp_on while dp_on_pps is high to +-- start the data path on the next PPS. +-- 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, added bsn_time_offset +-- + +LIBRARY IEEE, common_lib; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; +USE common_lib.common_pkg.ALL; +USE work.dp_stream_pkg.ALL; + +ENTITY dp_bsn_source_v2 IS + GENERIC ( + g_block_size : NATURAL := 256; + g_nof_clk_per_sync : NATURAL := 200 * 10**6; + g_bsn_w : NATURAL := 48; + g_bsn_time_offset_w : NATURAL := 10 + ); + PORT ( + rst : IN STD_LOGIC; + clk : IN STD_LOGIC; + pps : IN STD_LOGIC := '1'; + + dp_on : IN STD_LOGIC; + dp_on_pps : IN STD_LOGIC; + + dp_on_status : OUT STD_LOGIC; + + nof_clk_per_sync : IN STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0) := TO_UVEC(g_nof_clk_per_sync, c_word_w); + bsn_init : IN STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0) := (OTHERS=>'0'); + bsn_time_offset : IN STD_LOGIC_VECTOR(g_bsn_time_offset_w-1 DOWNTO 0) := (OTHERS=>'0'); + current_bsn_time_offset : OUT STD_LOGIC_VECTOR(g_bsn_time_offset_w-1 DOWNTO 0); -- output for monitoring purpose in test bench. + + src_out : OUT t_dp_sosi -- only uses sync, bsn[], valid, sop and eop + ); +END dp_bsn_source_v2; + + +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'); + + -- 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; + SIGNAL prev_state : t_state_enum; + + 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 i_src_out : t_dp_sosi := c_dp_sosi_init; + SIGNAL nxt_src_out : t_dp_sosi; + + SIGNAL i_dp_on_status : STD_LOGIC; + SIGNAL nxt_dp_on_status : STD_LOGIC; + + SIGNAL nxt_bsn_time_offset_cnt : STD_LOGIC_VECTOR(g_bsn_time_offset_w-1 DOWNTO 0); + SIGNAL bsn_time_offset_cnt : STD_LOGIC_VECTOR(g_bsn_time_offset_w-1 DOWNTO 0); + + SIGNAL i_current_bsn_time_offset : STD_LOGIC_VECTOR(g_bsn_time_offset_w-1 DOWNTO 0); + SIGNAL nxt_current_bsn_time_offset : STD_LOGIC_VECTOR(g_bsn_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); + SIGNAL nxt_sync : STD_LOGIC; + SIGNAL sync : STD_LOGIC; + +BEGIN + + src_out <= i_src_out; + dp_on_status <= i_dp_on_status; + current_bsn_time_offset <= i_current_bsn_time_offset; + + p_state : PROCESS(state, i_src_out, block_size_cnt, clk_cnt, sync, i_dp_on_status, bsn_time_offset_cnt, bsn_time_offset, nof_clk_per_sync, bsn_init, dp_on, dp_on_pps, pps, prev_state) + 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_bsn_time_offset_cnt <= bsn_time_offset_cnt; + nxt_current_bsn_time_offset <= bsn_time_offset; + + + IF UNSIGNED(clk_cnt) = UNSIGNED(nof_clk_per_sync) - 1 THEN + nxt_clk_cnt <= (OTHERS=>'0'); + nxt_sync <= '1'; -- will set src_out.sync on next src_out.sop + END IF; + + CASE state IS + + 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'; -- ensure issue sync at first sync interval for start at PPS. + 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_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 => + nxt_dp_on_status <= '1'; + nxt_src_out.sop <= '1'; + nxt_src_out.valid <= '1'; + nxt_state <= s_dp_on; + nxt_block_size_cnt <= (OTHERS=>'0'); + IF prev_state = s_dp_on_eop THEN + 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'; + 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_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 + nxt_state <= s_dp_off; + + END CASE; + END PROCESS; + + + p_clk : PROCESS(rst, clk) + BEGIN + IF rst='1' THEN + prev_state <= s_init; + state <= s_init; + i_src_out <= c_dp_sosi_rst; + clk_cnt <= (OTHERS=>'0'); + sync <= '0'; + block_size_cnt <= (OTHERS=>'0'); + i_dp_on_status <= '0'; + bsn_time_offset_cnt <= (OTHERS=>'0'); + ELSIF rising_edge(clk) THEN + prev_state <= state; + state <= nxt_state; + i_src_out <= nxt_src_out; + clk_cnt <= nxt_clk_cnt; + sync <= nxt_sync; + block_size_cnt <= nxt_block_size_cnt; + i_dp_on_status <= nxt_dp_on_status; + bsn_time_offset_cnt <= nxt_bsn_time_offset_cnt; + i_current_bsn_time_offset <= nxt_current_bsn_time_offset; + END IF; + END PROCESS; + +END rtl; + + 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 new file mode 100644 index 0000000000000000000000000000000000000000..9d096d2a96a0c3943ce7a037d5565206d7e823bf --- /dev/null +++ b/libraries/base/dp/src/vhdl/mms_dp_bsn_source_v2.vhd @@ -0,0 +1,131 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2012 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +-- Purpose : MMS for dp_bsn_source +-- Description: See dp_bsn_source.vhd + +LIBRARY IEEE, common_lib; +USE IEEE.STD_LOGIC_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE work.dp_stream_pkg.ALL; + + +ENTITY mms_dp_bsn_source_v2 IS + GENERIC ( + g_cross_clock_domain : BOOLEAN := TRUE; -- use FALSE when mm_clk and st_clk are the same, else use TRUE to cross the clock domain + g_block_size : NATURAL := 256; -- 1024 samples @ 800M / 4 = 256 4 sample words @ 200 M + g_nof_clk_per_sync : NATURAL := 200 * 10**6; -- ; + g_bsn_w : NATURAL := 48; + g_bsn_time_offset_w : NATURAL := 10 + ); + PORT ( + -- Clocks and reset + mm_rst : IN STD_LOGIC; -- reset synchronous with mm_clk + mm_clk : IN STD_LOGIC; -- memory-mapped bus clock + dp_rst : IN STD_LOGIC; -- reset synchronous with st_clk + dp_clk : IN STD_LOGIC; -- other clock domain clock + dp_pps : IN STD_LOGIC := '1'; -- external PPS in captured in dp_clk domain + + -- Memory-mapped clock domain + reg_mosi : IN t_mem_mosi; -- actual ranges defined by c_mm_reg + reg_miso : OUT t_mem_miso; -- actual ranges defined by c_mm_reg + + -- Streaming clock domain + bs_sosi : OUT t_dp_sosi + ); +END mms_dp_bsn_source_v2; + + +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 bsn_init : STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0); + SIGNAL bsn_time_offset : STD_LOGIC_VECTOR(g_bsn_time_offset_w-1 DOWNTO 0); + + SIGNAL i_bs_sosi : t_dp_sosi; + + SIGNAL dp_on_status : STD_LOGIC; + + SIGNAL capture_bsn : STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0) := (OTHERS=>'0'); + SIGNAL current_bsn_time_offset : STD_LOGIC_VECTOR(g_bsn_time_offset_w-1 DOWNTO 0); + +BEGIN + + bs_sosi <= i_bs_sosi; + + u_mm_reg : ENTITY work.dp_bsn_source_reg_v2 + GENERIC MAP ( + g_cross_clock_domain => g_cross_clock_domain, + g_nof_clk_per_sync => g_nof_clk_per_sync + ) + PORT MAP ( + -- Clocks and reset + mm_rst => mm_rst, + mm_clk => mm_clk, + st_rst => dp_rst, + st_clk => dp_clk, + + -- Memory Mapped Slave in mm_clk domain + sla_in => reg_mosi, + sla_out => reg_miso, + + -- MM registers in st_clk domain + st_on => dp_on, + st_on_pps => dp_on_pps, + st_on_status => dp_on_status, + st_nof_clk_per_sync => nof_clk_per_sync, + st_bsn_init => bsn_init, + st_current_bsn => capture_bsn, + st_bsn_time_offset => bsn_time_offset, + st_current_bsn_time_offset => current_bsn_time_offset + ); + + u_bsn_source : ENTITY work.dp_bsn_source_v2 + GENERIC MAP ( + g_block_size => g_block_size, + g_nof_clk_per_sync => g_nof_clk_per_sync, + g_bsn_w => g_bsn_w + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + pps => dp_pps, + -- MM control + dp_on => dp_on, + dp_on_pps => dp_on_pps, + dp_on_status => dp_on_status, + bsn_init => bsn_init, + nof_clk_per_sync => nof_clk_per_sync, + bsn_time_offset => bsn_time_offset, + current_bsn_time_offset => current_bsn_time_offset, + -- Streaming + src_out => i_bs_sosi + ); + + --capture_bsn <= i_bs_sosi.bsn; -- capture current BSN + --capture_bsn <= i_bs_sosi.bsn WHEN rising_edge(dp_clk) AND dp_pps='1'; -- capture BSN at external PPS + capture_bsn <= i_bs_sosi.bsn WHEN rising_edge(dp_clk) AND i_bs_sosi.sync='1'; -- capture BSN at internal sync + +END str; + 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 new file mode 100644 index 0000000000000000000000000000000000000000..2e701d81502e0eb51d9ced01318b5187a8fde452 --- /dev/null +++ b/libraries/base/dp/tb/vhdl/tb_dp_bsn_source_v2.vhd @@ -0,0 +1,244 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2011 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +-- Author: P. Donker +-- Verify if eop and sop come in pairs and if sync is at sop and at expected_sync puls. +-- The tb is using a SSN (second sample number) and BSN (block sample number) generator as reference +-- for the test, it uses g_pps_interval and g_block_size for generator timing settings. +-- Start/Stop BSN source tests: +-- 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. +-- +-- [doc] = https://support.astron.nl/confluence/display/L2M/L6+FWLIB+Design+Document%3A+BSN+source+with+offset + +-- Usage: +-- > as 10 +-- > run -all +-- . sop, eop are verified automatically +-- . sync and bsn are verified automatically +-- and then manually verify on/off in Wave window + +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_bsn_source_v2 IS + GENERIC ( + 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_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 ( + s_disable, + s_start, + s_pps_start + ); + + SIGNAL tb_state : t_state_enum; + + SIGNAL tb_end : STD_LOGIC := '0'; + SIGNAL rst : STD_LOGIC := '1'; + SIGNAL clk : STD_LOGIC := '1'; + + -- DUT + SIGNAL dp_on : 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 bs_sosi : t_dp_sosi; + + -- Verify + 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 + + ----------------------------------------------------------------------------- + -- Stimuli + ----------------------------------------------------------------------------- + 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_high(clk, pps_sop); + IF bsn_sop = '1' THEN + expected_sync <= '1'; + expected_bsn <= BSN+1; + expected_offset_bsn <= 0; + ELSE + proc_common_wait_until_high(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'; + + dp_on <= '0'; + dp_on_pps <= '0'; + + -- Get synchronous to clk + proc_common_wait_until_low(clk, rst); + proc_common_wait_some_cycles(clk, 500); + + -- Start asynchronously by making dp_on high + proc_common_wait_until_high(clk, expected_sync_dly); + tb_state <= s_pps_start; + dp_on_pps <= '0'; + dp_on <= '1'; + 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'; + + -- 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 + FOR i IN 0 TO 2 LOOP + -- Now start on PPS + proc_common_wait_until_high(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'; + + -- 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; + + tb_end <= '1'; + WAIT; + END PROCESS; + + + ----------------------------------------------------------------------------- + -- 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(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 + ----------------------------------------------------------------------------- + + dut : ENTITY work.dp_bsn_source_v2 + GENERIC MAP ( + 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_sop, + -- MM control + dp_on => dp_on, + dp_on_pps => dp_on_pps, + bsn_init => bsn_init, + -- Streaming + src_out => bs_sosi + ); + +END tb; diff --git a/libraries/base/dp/tb/vhdl/tb_dp_pkg.vhd b/libraries/base/dp/tb/vhdl/tb_dp_pkg.vhd index f3955889bab0b15aed221174b8c59d26642ab617..381a32262b5abb01aeb880676d4fe1a6f74bdbbb 100644 --- a/libraries/base/dp/tb/vhdl/tb_dp_pkg.vhd +++ b/libraries/base/dp/tb/vhdl/tb_dp_pkg.vhd @@ -25,6 +25,7 @@ USE IEEE.std_logic_1164.ALL; USE IEEE.numeric_std.ALL; USE common_lib.common_pkg.ALL; USE common_lib.common_lfsr_sequences_pkg.ALL; +USE common_lib.common_str_pkg.ALL; USE common_lib.tb_common_pkg.ALL; USE work.dp_stream_pkg.ALL; @@ -74,7 +75,7 @@ PACKAGE tb_dp_pkg IS CONSTANT c_dp_error_w : NATURAL := c_dp_stream_error_w; TYPE t_dp_data_arr IS ARRAY (NATURAL RANGE <>) OF STD_LOGIC_VECTOR(c_dp_data_w-1 DOWNTO 0); - + -- The state name tells what kind of test is done in the sync interval TYPE t_dp_state_enum IS ( s_idle, @@ -94,22 +95,22 @@ PACKAGE tb_dp_pkg IS e_equal, e_at_least ); - + -- always active, random or pulse flow control TYPE t_dp_flow_control_enum IS ( e_active, e_random, - e_pulse + e_pulse ); - + TYPE t_dp_flow_control_enum_arr IS ARRAY (NATURAL RANGE <>) OF t_dp_flow_control_enum; - + CONSTANT c_dp_flow_control_enum_arr : t_dp_flow_control_enum_arr := (e_active, e_random, e_pulse); -- array all possible values that can be iterated over - + ------------------------------------------------------------------------------ -- Stream source functions ------------------------------------------------------------------------------ - + -- Block data generator with feedforward throttle control -- !!! old style: sync before sop -- !!! used by tb_dp_packetizing, do not use for new DP components @@ -125,7 +126,7 @@ PACKAGE tb_dp_pkg IS SIGNAL cnt_sync : OUT STD_LOGIC; SIGNAL cnt_val : OUT STD_LOGIC; SIGNAL cnt_dat : INOUT STD_LOGIC_VECTOR); - + -- Block data generator with ready flow control and symbols counter PROCEDURE proc_dp_gen_block_data(CONSTANT c_ready_latency : IN NATURAL; -- 0, 1 are supported by proc_dp_stream_ready_latency() CONSTANT c_use_data : IN BOOLEAN; -- when TRUE use data field, else use re, im fields, and keep unused fields at 'X' @@ -143,7 +144,7 @@ PACKAGE tb_dp_pkg IS SIGNAL in_en : IN STD_LOGIC; -- when '0' then no valid output even when src_in is ready SIGNAL src_in : IN t_dp_siso; SIGNAL src_out : OUT t_dp_sosi); - + -- Increment only sosi.data, keep complex re,im = 0 PROCEDURE proc_dp_gen_block_data(CONSTANT c_data_w : IN NATURAL; -- data width for the data field CONSTANT c_symbol_init : IN NATURAL; -- init counter for the data in the data field @@ -156,7 +157,7 @@ PACKAGE tb_dp_pkg IS SIGNAL in_en : IN STD_LOGIC; -- when '0' then no valid output even when src_in is ready SIGNAL src_in : IN t_dp_siso; SIGNAL src_out : OUT t_dp_sosi); - + -- Increment only sosi.re, im, keep data = 0 PROCEDURE proc_dp_gen_block_complex(CONSTANT c_data_w : IN NATURAL; -- data width for the re, im field CONSTANT c_symbol_re_init : IN NATURAL; -- init counter for symbols in re field @@ -170,7 +171,7 @@ PACKAGE tb_dp_pkg IS SIGNAL in_en : IN STD_LOGIC; -- when '0' then no valid output even when src_in is ready SIGNAL src_in : IN t_dp_siso; SIGNAL src_out : OUT t_dp_sosi); - + -- Handle stream ready signal, only support RL=0 or 1. PROCEDURE proc_dp_stream_ready_latency(CONSTANT c_latency : IN NATURAL; SIGNAL clk : IN STD_LOGIC; @@ -184,13 +185,13 @@ PACKAGE tb_dp_pkg IS SIGNAL out_valid : OUT STD_LOGIC; SIGNAL out_sop : OUT STD_LOGIC; SIGNAL out_eop : OUT STD_LOGIC); - + -- Initialize the data per symbol FUNCTION func_dp_data_init(c_data_w, c_symbol_w, init : NATURAL) RETURN STD_LOGIC_VECTOR; - + -- Increment the data per symbol FUNCTION func_dp_data_incr(c_data_w, c_symbol_w : NATURAL; data : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR; - + -- Generate a counter data with valid PROCEDURE proc_dp_gen_data(CONSTANT c_ready_latency : IN NATURAL; -- 0, 1 are supported by proc_dp_stream_ready_latency() CONSTANT c_data_w : IN NATURAL; @@ -202,16 +203,16 @@ PACKAGE tb_dp_pkg IS SIGNAL src_out : OUT t_dp_sosi); -- As above but with counter max - PROCEDURE proc_dp_gen_data(CONSTANT c_ready_latency : IN NATURAL; + PROCEDURE proc_dp_gen_data(CONSTANT c_ready_latency : IN NATURAL; CONSTANT c_data_w : IN NATURAL; CONSTANT c_data_init : IN NATURAL; - CONSTANT c_data_max : IN NATURAL; + CONSTANT c_data_max : IN NATURAL; SIGNAL rst : IN STD_LOGIC; SIGNAL clk : IN STD_LOGIC; SIGNAL in_en : IN STD_LOGIC; SIGNAL src_in : IN t_dp_siso; SIGNAL src_out : OUT t_dp_sosi); - + -- Generate a frame with symbols counter PROCEDURE proc_dp_gen_frame(CONSTANT c_ready_latency : IN NATURAL; -- 0, 1 are supported by proc_dp_stream_ready_latency() CONSTANT c_data_w : IN NATURAL; @@ -236,7 +237,7 @@ PACKAGE tb_dp_pkg IS SIGNAL in_en : IN STD_LOGIC; SIGNAL cnt_val : INOUT STD_LOGIC; SIGNAL cnt_dat : INOUT STD_LOGIC_VECTOR); - + -- Transmit data PROCEDURE proc_dp_tx_data(CONSTANT c_ready_latency : IN NATURAL; SIGNAL rst : IN STD_LOGIC; @@ -247,14 +248,14 @@ PACKAGE tb_dp_pkg IS SIGNAL tx_val : INOUT STD_LOGIC_VECTOR; SIGNAL out_data : OUT STD_LOGIC_VECTOR; SIGNAL out_val : OUT STD_LOGIC); - + -- Transmit data control (use for sop, eop) PROCEDURE proc_dp_tx_ctrl(CONSTANT c_offset : IN NATURAL; CONSTANT c_period : IN NATURAL; SIGNAL data : IN STD_LOGIC_VECTOR; SIGNAL valid : IN STD_LOGIC; SIGNAL ctrl : OUT STD_LOGIC); - + -- Define sync interval PROCEDURE proc_dp_sync_interval(SIGNAL clk : IN STD_LOGIC; SIGNAL sync : OUT STD_LOGIC); @@ -272,55 +273,55 @@ PACKAGE tb_dp_pkg IS ------------------------------------------------------------------------------ -- Stream sink functions ------------------------------------------------------------------------------ - + -- Stimuli for out_ready PROCEDURE proc_dp_out_ready(SIGNAL rst : IN STD_LOGIC; SIGNAL clk : IN STD_LOGIC; SIGNAL sync : IN STD_LOGIC; SIGNAL lfsr : INOUT STD_LOGIC_VECTOR; SIGNAL out_ready : OUT STD_LOGIC); - + -- DUT output verify enable PROCEDURE proc_dp_verify_en(CONSTANT c_delay : IN NATURAL; SIGNAL rst : IN STD_LOGIC; SIGNAL clk : IN STD_LOGIC; SIGNAL sync : IN STD_LOGIC; SIGNAL verify_en : OUT STD_LOGIC); - + PROCEDURE proc_dp_verify_en(CONSTANT c_continuous : IN BOOLEAN; SIGNAL clk : IN STD_LOGIC; SIGNAL valid : IN STD_LOGIC; SIGNAL sop : IN STD_LOGIC; SIGNAL eop : IN STD_LOGIC; SIGNAL verify_en : OUT STD_LOGIC); - + -- Run and verify for some cycles PROCEDURE proc_dp_verify_run_some_cycles(CONSTANT nof_pre_clk : IN NATURAL; CONSTANT nof_verify_clk : IN NATURAL; CONSTANT nof_post_clk : IN NATURAL; SIGNAL clk : IN STD_LOGIC; SIGNAL verify_en : OUT STD_LOGIC); - + -- Verify the expected value PROCEDURE proc_dp_verify_value(CONSTANT c_str : IN STRING; CONSTANT mode : IN t_dp_value_enum; SIGNAL clk : IN STD_LOGIC; SIGNAL en : IN STD_LOGIC; - SIGNAL exp : IN STD_LOGIC_VECTOR; + SIGNAL exp : IN STD_LOGIC_VECTOR; SIGNAL res : IN STD_LOGIC_VECTOR); - + PROCEDURE proc_dp_verify_value(CONSTANT mode : IN t_dp_value_enum; SIGNAL clk : IN STD_LOGIC; SIGNAL en : IN STD_LOGIC; - SIGNAL exp : IN STD_LOGIC_VECTOR; + SIGNAL exp : IN STD_LOGIC_VECTOR; SIGNAL res : IN STD_LOGIC_VECTOR); - + PROCEDURE proc_dp_verify_value(CONSTANT c_str : IN STRING; SIGNAL clk : IN STD_LOGIC; SIGNAL en : IN STD_LOGIC; - SIGNAL exp : IN STD_LOGIC; + SIGNAL exp : IN STD_LOGIC; SIGNAL res : IN STD_LOGIC); - + -- Verify output global and local BSN -- . incrementing or replicated global BSN -- . incrementing local BSN that starts at 1 @@ -336,7 +337,7 @@ PACKAGE tb_dp_pkg IS SIGNAL cnt_replicated_global_bsn : INOUT NATURAL; SIGNAL prev_out_bsn_global : INOUT STD_LOGIC_VECTOR; SIGNAL prev_out_bsn_local : INOUT STD_LOGIC_VECTOR); - + -- Verify incrementing data -- . wrap at c_out_data_max when >0, else no wrap when c_out_data_max=0 -- . default increment by +1, but also allow an increment by +c_out_data_gap @@ -350,7 +351,7 @@ PACKAGE tb_dp_pkg IS SIGNAL out_val : IN STD_LOGIC; SIGNAL out_data : IN STD_LOGIC_VECTOR; SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR); - + -- Verify the DUT incrementing output data that wraps in range 0 ... c_out_data_max PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING; CONSTANT c_ready_latency : IN NATURAL; @@ -361,7 +362,7 @@ PACKAGE tb_dp_pkg IS SIGNAL out_val : IN STD_LOGIC; SIGNAL out_data : IN STD_LOGIC_VECTOR; SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR); - + -- Verify the DUT incrementing output data, fixed increment +1 PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING; CONSTANT c_ready_latency : IN NATURAL; @@ -371,7 +372,7 @@ PACKAGE tb_dp_pkg IS SIGNAL out_val : IN STD_LOGIC; -- by using sop or eop proc_dp_verify_data() can also be used to verify other SOSI fields like bsn, error, channel, empty SIGNAL out_data : IN STD_LOGIC_VECTOR; SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR); - + -- Verify incrementing data with RL > 0 or no flow control, support wrap at maximum and increment gap PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING; CONSTANT c_out_data_max : IN UNSIGNED; @@ -381,7 +382,7 @@ PACKAGE tb_dp_pkg IS SIGNAL out_val : IN STD_LOGIC; SIGNAL out_data : IN STD_LOGIC_VECTOR; SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR); - + PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING; CONSTANT c_out_data_max : IN NATURAL; CONSTANT c_out_data_gap : IN NATURAL; @@ -390,7 +391,7 @@ PACKAGE tb_dp_pkg IS SIGNAL out_val : IN STD_LOGIC; SIGNAL out_data : IN STD_LOGIC_VECTOR; SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR); - + PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING; CONSTANT c_out_data_max : IN NATURAL; SIGNAL clk : IN STD_LOGIC; @@ -398,7 +399,7 @@ PACKAGE tb_dp_pkg IS SIGNAL out_val : IN STD_LOGIC; SIGNAL out_data : IN STD_LOGIC_VECTOR; SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR); - + -- Verify incrementing data with RL > 0 or no flow control, fixed increment +1 PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING; SIGNAL clk : IN STD_LOGIC; @@ -406,7 +407,7 @@ PACKAGE tb_dp_pkg IS SIGNAL out_val : IN STD_LOGIC; SIGNAL out_data : IN STD_LOGIC_VECTOR; SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR); - + -- Verify the DUT output symbols PROCEDURE proc_dp_verify_symbols(CONSTANT c_ready_latency : IN NATURAL; CONSTANT c_data_w : IN NATURAL; @@ -419,7 +420,7 @@ PACKAGE tb_dp_pkg IS SIGNAL out_data : IN STD_LOGIC_VECTOR; SIGNAL out_empty : IN STD_LOGIC_VECTOR; SIGNAL prev_out_data : INOUT STD_LOGIC_VECTOR); - + -- Verify the DUT output data with empty PROCEDURE proc_dp_verify_data_empty(CONSTANT c_ready_latency : IN NATURAL; CONSTANT c_last_word : IN NATURAL; @@ -436,26 +437,26 @@ PACKAGE tb_dp_pkg IS SIGNAL out_data_3 : INOUT STD_LOGIC_VECTOR; SIGNAL out_empty : IN STD_LOGIC_VECTOR; SIGNAL out_empty_1 : INOUT STD_LOGIC_VECTOR); - + PROCEDURE proc_dp_verify_other_sosi(CONSTANT c_str : IN STRING; CONSTANT c_exp_data : IN STD_LOGIC_VECTOR; SIGNAL clk : IN STD_LOGIC; SIGNAL verify_en : IN STD_LOGIC; SIGNAL res_data : IN STD_LOGIC_VECTOR); - + PROCEDURE proc_dp_verify_valid(CONSTANT c_ready_latency : IN NATURAL; SIGNAL clk : IN STD_LOGIC; SIGNAL verify_en : IN STD_LOGIC; SIGNAL out_ready : IN STD_LOGIC; SIGNAL prev_out_ready : INOUT STD_LOGIC_VECTOR; SIGNAL out_val : IN STD_LOGIC); - + PROCEDURE proc_dp_verify_valid(SIGNAL clk : IN STD_LOGIC; SIGNAL verify_en : IN STD_LOGIC; SIGNAL out_ready : IN STD_LOGIC; SIGNAL prev_out_ready : INOUT STD_LOGIC; SIGNAL out_val : IN STD_LOGIC); - + -- Verify the DUT output sync PROCEDURE proc_dp_verify_sync(CONSTANT c_sync_period : IN NATURAL; CONSTANT c_sync_offset : IN NATURAL; @@ -464,7 +465,24 @@ PACKAGE tb_dp_pkg IS SIGNAL sync : IN STD_LOGIC; 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; + SIGNAL clk : IN STD_LOGIC; + SIGNAL verify_en : IN STD_LOGIC; + SIGNAL sync : IN STD_LOGIC; + SIGNAL sop : IN STD_LOGIC; + SIGNAL bsn : IN STD_LOGIC_VECTOR; + SIGNAL tb_bsn_cnt : INOUT INTEGER); + -- Verify the DUT output sop and eop PROCEDURE proc_dp_verify_sop_and_eop(CONSTANT c_ready_latency : IN NATURAL; CONSTANT c_verify_valid : IN BOOLEAN; @@ -474,7 +492,7 @@ PACKAGE tb_dp_pkg IS SIGNAL out_sop : IN STD_LOGIC; SIGNAL out_eop : IN STD_LOGIC; SIGNAL hold_sop : INOUT STD_LOGIC); - + PROCEDURE proc_dp_verify_sop_and_eop(CONSTANT c_ready_latency : IN NATURAL; SIGNAL clk : IN STD_LOGIC; SIGNAL out_ready : IN STD_LOGIC; @@ -482,13 +500,13 @@ PACKAGE tb_dp_pkg IS SIGNAL out_sop : IN STD_LOGIC; SIGNAL out_eop : IN STD_LOGIC; SIGNAL hold_sop : INOUT STD_LOGIC); - + PROCEDURE proc_dp_verify_sop_and_eop(SIGNAL clk : IN STD_LOGIC; SIGNAL out_val : IN STD_LOGIC; SIGNAL out_sop : IN STD_LOGIC; SIGNAL out_eop : IN STD_LOGIC; SIGNAL hold_sop : INOUT STD_LOGIC); - + PROCEDURE proc_dp_verify_block_size(CONSTANT c_ready_latency : IN NATURAL; SIGNAL alt_size : IN NATURAL; -- alternative size (eg. use exp_size'last_value) SIGNAL exp_size : IN NATURAL; -- expected size @@ -498,7 +516,7 @@ PACKAGE tb_dp_pkg IS SIGNAL out_sop : IN STD_LOGIC; SIGNAL out_eop : IN STD_LOGIC; SIGNAL cnt_size : INOUT NATURAL); - + PROCEDURE proc_dp_verify_block_size(CONSTANT c_ready_latency : IN NATURAL; SIGNAL exp_size : IN NATURAL; -- expected size SIGNAL clk : IN STD_LOGIC; @@ -507,7 +525,7 @@ PACKAGE tb_dp_pkg IS SIGNAL out_sop : IN STD_LOGIC; SIGNAL out_eop : IN STD_LOGIC; SIGNAL cnt_size : INOUT NATURAL); - + PROCEDURE proc_dp_verify_block_size(SIGNAL alt_size : IN NATURAL; -- alternative size (eg. use exp_size'last_value) SIGNAL exp_size : IN NATURAL; -- expected size SIGNAL clk : IN STD_LOGIC; @@ -515,21 +533,21 @@ PACKAGE tb_dp_pkg IS SIGNAL out_sop : IN STD_LOGIC; SIGNAL out_eop : IN STD_LOGIC; SIGNAL cnt_size : INOUT NATURAL); - + PROCEDURE proc_dp_verify_block_size(SIGNAL exp_size : IN NATURAL; -- expected size SIGNAL clk : IN STD_LOGIC; SIGNAL out_val : IN STD_LOGIC; SIGNAL out_sop : IN STD_LOGIC; SIGNAL out_eop : IN STD_LOGIC; SIGNAL cnt_size : INOUT NATURAL); - + -- Verify the DUT output invalid between frames PROCEDURE proc_dp_verify_gap_invalid(SIGNAL clk : IN STD_LOGIC; SIGNAL in_val : IN STD_LOGIC; SIGNAL in_sop : IN STD_LOGIC; SIGNAL in_eop : IN STD_LOGIC; SIGNAL out_gap : INOUT STD_LOGIC); -- declare initial gap signal = '1' - + -- Verify the DUT output control (use for sop, eop) PROCEDURE proc_dp_verify_ctrl(CONSTANT c_offset : IN NATURAL; CONSTANT c_period : IN NATURAL; @@ -539,21 +557,21 @@ PACKAGE tb_dp_pkg IS SIGNAL data : IN STD_LOGIC_VECTOR; SIGNAL valid : IN STD_LOGIC; SIGNAL ctrl : IN STD_LOGIC); - + -- Wait for stream valid PROCEDURE proc_dp_stream_valid(SIGNAL clk : IN STD_LOGIC; SIGNAL in_valid : IN STD_LOGIC); - + -- Wait for stream valid AND sop PROCEDURE proc_dp_stream_valid_sop(SIGNAL clk : IN STD_LOGIC; SIGNAL in_valid : IN STD_LOGIC; SIGNAL in_sop : IN STD_LOGIC); - + -- Wait for stream valid AND eop PROCEDURE proc_dp_stream_valid_eop(SIGNAL clk : IN STD_LOGIC; SIGNAL in_valid : IN STD_LOGIC; SIGNAL in_eop : IN STD_LOGIC); - + END tb_dp_pkg; @@ -579,11 +597,11 @@ PACKAGE BODY tb_dp_pkg IS BEGIN sync_nr <= 0; block_nr <= 0; - - cnt_sync <= '0'; + + cnt_sync <= '0'; cnt_val <= '0'; cnt_dat <= (cnt_dat'RANGE=>'1'); -- -1, so first valid cnt_dat starts at 0 - + -- allow some clock cycles before start after rst release WAIT UNTIL rst='0'; FOR I IN 0 TO c_start_delay-1 LOOP WAIT UNTIL rising_edge(clk); END LOOP; @@ -593,7 +611,7 @@ PACKAGE BODY tb_dp_pkg IS WAIT UNTIL rising_edge(clk); cnt_sync <= '0'; FOR I IN 1 TO c_gap_size-1 LOOP WAIT UNTIL rising_edge(clk); END LOOP; - + WHILE TRUE LOOP -- output block IF c_throttle_num >= c_throttle_den THEN @@ -629,14 +647,14 @@ PACKAGE BODY tb_dp_pkg IS FOR I IN 1 TO c_gap_size-1 LOOP WAIT UNTIL rising_edge(clk); END LOOP; -- next block block_nr <= block_nr+1; - END LOOP; + END LOOP; END proc_dp_gen_block_data; - - + + ------------------------------------------------------------------------------ -- PROCEDURE: Block data generator with ready flow control and symbols counter -- . dependent on in_en and src_in.ready - -- . optional sync pulse at end of frame + -- . optional sync pulse at end of frame ------------------------------------------------------------------------------ PROCEDURE proc_dp_gen_block_data(CONSTANT c_ready_latency : IN NATURAL; -- 0, 1 are supported by proc_dp_stream_ready_latency() CONSTANT c_use_data : IN BOOLEAN; -- when TRUE use data field, else use re, im fields, and keep unused fields at 'X' @@ -686,7 +704,7 @@ PACKAGE BODY tb_dp_pkg IS IF c_use_data=FALSE THEN src_out.im <= RESIZE_DP_DSP_DATA(v_im); END IF; proc_dp_stream_ready_latency(c_ready_latency, clk, src_in.ready, in_en, '0', '1', '0', '0', src_out.sync, src_out.valid, src_out.sop, src_out.eop); END LOOP; - + -- . eop v_data := func_dp_data_incr(c_data_w, c_symbol_w, v_data); v_re := func_dp_data_incr(c_data_w, c_symbol_w, v_re); @@ -704,7 +722,7 @@ PACKAGE BODY tb_dp_pkg IS proc_common_wait_some_cycles(clk, c_nof_data); END IF; END proc_dp_gen_block_data; - + -- Increment only sosi.data, keep complex re,im = 0 PROCEDURE proc_dp_gen_block_data(CONSTANT c_data_w : IN NATURAL; -- data width for the data field CONSTANT c_symbol_init : IN NATURAL; -- init counter for the data in the data field @@ -720,7 +738,7 @@ PACKAGE BODY tb_dp_pkg IS BEGIN proc_dp_gen_block_data(1, TRUE, c_data_w, c_data_w, c_symbol_init, 0, 0, c_nof_symbols, c_channel, c_error, c_sync, c_bsn, clk, in_en, src_in, src_out); END proc_dp_gen_block_data; - + -- Increment only sosi.re, im, keep data = 0 PROCEDURE proc_dp_gen_block_complex(CONSTANT c_data_w : IN NATURAL; -- data width for the re, im field CONSTANT c_symbol_re_init : IN NATURAL; -- init counter for symbols in re field @@ -737,7 +755,7 @@ PACKAGE BODY tb_dp_pkg IS BEGIN proc_dp_gen_block_data(1, FALSE, c_data_w, c_data_w, 0, c_symbol_re_init, c_symbol_im_init, c_nof_symbols, c_channel, c_error, c_sync, c_bsn, clk, in_en, src_in, src_out); END proc_dp_gen_block_complex; - + ------------------------------------------------------------------------------ -- PROCEDURE: Handle stream ready signal -- . output active when src_in is ready and in_en='1' @@ -761,12 +779,12 @@ PACKAGE BODY tb_dp_pkg IS out_valid <= '0'; out_sop <= '0'; out_eop <= '0'; - + -- Skip cycles until in_en='1' WHILE in_en='0' LOOP WAIT UNTIL rising_edge(clk); END LOOP; - + -- Active output when ready -- . RL = 0 IF c_latency=0 THEN @@ -781,7 +799,7 @@ PACKAGE BODY tb_dp_pkg IS END LOOP; -- ready has acknowledged the valid output END IF; - + -- . RL = 1 IF c_latency=1 THEN -- no valid output until request @@ -795,7 +813,7 @@ PACKAGE BODY tb_dp_pkg IS out_eop <= c_eop; WAIT UNTIL rising_edge(clk); END IF; - + -- Return with no active output out_sync <= '0'; out_valid <= '0'; @@ -803,7 +821,7 @@ PACKAGE BODY tb_dp_pkg IS out_eop <= '0'; END proc_dp_stream_ready_latency; - + ------------------------------------------------------------------------------ -- FUNCTION: Initialize the data per symbol -- . use big endian @@ -822,8 +840,8 @@ PACKAGE BODY tb_dp_pkg IS END LOOP; RETURN v_data; END func_dp_data_init; - - + + ------------------------------------------------------------------------------ -- FUNCTION: Increment the data per symbol -- . use big endian @@ -844,8 +862,8 @@ PACKAGE BODY tb_dp_pkg IS END LOOP; RETURN v_data; END func_dp_data_incr; - - + + ------------------------------------------------------------------------------ -- PROCEDURE: Generate counter data with valid -- . Output counter data dependent on in_en and src_in.ready @@ -878,10 +896,10 @@ PACKAGE BODY tb_dp_pkg IS -- . Output counter data dependent on in_en and src_in.ready -- . with maximum count value ------------------------------------------------------------------------------ - PROCEDURE proc_dp_gen_data(CONSTANT c_ready_latency : IN NATURAL; + PROCEDURE proc_dp_gen_data(CONSTANT c_ready_latency : IN NATURAL; CONSTANT c_data_w : IN NATURAL; CONSTANT c_data_init : IN NATURAL; - CONSTANT c_data_max : IN NATURAL; + CONSTANT c_data_max : IN NATURAL; SIGNAL rst : IN STD_LOGIC; SIGNAL clk : IN STD_LOGIC; SIGNAL in_en : IN STD_LOGIC; -- when '0' then no valid output even when src_in is ready @@ -904,8 +922,8 @@ PACKAGE BODY tb_dp_pkg IS END LOOP; END IF; END proc_dp_gen_data; - - + + ------------------------------------------------------------------------------ -- PROCEDURE: Generate a frame with symbols counter -- . dependent on in_en and src_in.ready @@ -954,8 +972,8 @@ PACKAGE BODY tb_dp_pkg IS src_out.sop <= '0'; src_out.eop <= '0'; END proc_dp_gen_frame; - - + + ------------------------------------------------------------------------------ -- PROCEDURE: Input data counter ------------------------------------------------------------------------------ @@ -972,7 +990,7 @@ PACKAGE BODY tb_dp_pkg IS END IF; END IF; END proc_dp_cnt_dat; - + PROCEDURE proc_dp_cnt_dat(SIGNAL rst : IN STD_LOGIC; SIGNAL clk : IN STD_LOGIC; SIGNAL in_en : IN STD_LOGIC; @@ -990,7 +1008,7 @@ PACKAGE BODY tb_dp_pkg IS END IF; END IF; END proc_dp_cnt_dat; - + ------------------------------------------------------------------------------ -- PROCEDURE: Transmit data ------------------------------------------------------------------------------ @@ -1008,7 +1026,7 @@ PACKAGE BODY tb_dp_pkg IS -- TX data array for output ready latency [c_ready_latency], index [0] for zero latency combinatorial tx_data(0) <= cnt_dat; tx_val( 0) <= cnt_val; - + IF rst='1' THEN tx_data(1 TO c_ready_latency+c_void) <= (1 TO c_ready_latency+c_void=>(OTHERS=>'0')); tx_val( 1 TO c_ready_latency+c_void) <= (1 TO c_ready_latency+c_void=>'0'); @@ -1016,12 +1034,12 @@ PACKAGE BODY tb_dp_pkg IS tx_data(1 TO c_ready_latency+c_void) <= tx_data(0 TO c_ready_latency+c_void-1); tx_val( 1 TO c_ready_latency+c_void) <= tx_val( 0 TO c_ready_latency+c_void-1); END IF; - + out_data <= tx_data(c_ready_latency); out_val <= tx_val(c_ready_latency); END proc_dp_tx_data; - - + + ------------------------------------------------------------------------------ -- PROCEDURE: Transmit data control (use for sop, eop) ------------------------------------------------------------------------------ @@ -1038,8 +1056,8 @@ PACKAGE BODY tb_dp_pkg IS ctrl <= '1'; END IF; END proc_dp_tx_ctrl; - - + + ------------------------------------------------------------------------------ -- PROCEDURE: Define test sync interval ------------------------------------------------------------------------------ @@ -1052,7 +1070,7 @@ PACKAGE BODY tb_dp_pkg IS WAIT UNTIL rising_edge(clk); END proc_dp_sync_interval; - + ------------------------------------------------------------------------------ -- PROCEDURE: Stimuli for cnt_en ------------------------------------------------------------------------------ @@ -1200,7 +1218,7 @@ PACKAGE BODY tb_dp_pkg IS END LOOP; cnt_en <= '1'; FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP; - + -- . 2-1 toggle cnt_en <= '0'; FOR I IN 1 TO c_dp_nof_toggle LOOP @@ -1238,7 +1256,7 @@ PACKAGE BODY tb_dp_pkg IS END LOOP; cnt_en <= '1'; FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP; - + -- . 3-1 toggle cnt_en <= '0'; FOR I IN 1 TO c_dp_nof_toggle LOOP @@ -1251,7 +1269,7 @@ PACKAGE BODY tb_dp_pkg IS END LOOP; cnt_en <= '1'; FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP; - + -- . 2-3 toggle cnt_en <= '0'; FOR I IN 1 TO c_dp_nof_toggle LOOP @@ -1265,7 +1283,7 @@ PACKAGE BODY tb_dp_pkg IS END LOOP; cnt_en <= '1'; FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP; - + -- . 3-2 toggle cnt_en <= '0'; FOR I IN 1 TO c_dp_nof_toggle LOOP @@ -1279,7 +1297,7 @@ PACKAGE BODY tb_dp_pkg IS END LOOP; cnt_en <= '1'; FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP; - + ---------------------------------------------------------------------------- -- Interval 6 ---------------------------------------------------------------------------- @@ -1287,7 +1305,7 @@ PACKAGE BODY tb_dp_pkg IS state <= s_toggle_both; cnt_en <= '1'; FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP; - + FOR I IN 1 TO c_dp_nof_both LOOP cnt_en <= '0'; FOR J IN 1 TO I LOOP WAIT UNTIL rising_edge(clk); END LOOP; @@ -1302,7 +1320,7 @@ PACKAGE BODY tb_dp_pkg IS WAIT UNTIL sync='1'; state <= s_pulse_cnt_en; FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP; - + FOR I IN 1 TO 15 LOOP FOR J IN 1 TO 15 LOOP cnt_en <= '0'; @@ -1314,7 +1332,7 @@ PACKAGE BODY tb_dp_pkg IS END LOOP; cnt_en <= '1'; FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP; - + ---------------------------------------------------------------------------- -- Interval 8 ---------------------------------------------------------------------------- @@ -1322,20 +1340,20 @@ PACKAGE BODY tb_dp_pkg IS state <= s_chirp_out_ready; cnt_en <= '1'; FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP; - + ---------------------------------------------------------------------------- -- Interval 9 ---------------------------------------------------------------------------- WAIT UNTIL sync='1'; state <= s_random; cnt_en <= '1'; - + FOR I IN 0 TO c_dp_sync_interval - c_dp_test_interval LOOP lfsr <= func_common_random(lfsr); cnt_en <= lfsr(lfsr'HIGH); WAIT UNTIL rising_edge(clk); END LOOP; - + ---------------------------------------------------------------------------- -- Done ---------------------------------------------------------------------------- @@ -1343,13 +1361,13 @@ PACKAGE BODY tb_dp_pkg IS state <= s_done; WAIT UNTIL rising_edge(clk); cnt_en <= '0'; - + -- pulse done FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP; done <= '1'; WAIT UNTIL rising_edge(clk); done <= '0'; - + ---------------------------------------------------------------------------- -- Testbench end ---------------------------------------------------------------------------- @@ -1438,7 +1456,7 @@ PACKAGE BODY tb_dp_pkg IS WAIT UNTIL rising_edge(clk); out_ready <= '1'; FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP; - + -- . 7 cycle out_ready <= '0'; WAIT UNTIL rising_edge(clk); @@ -1450,7 +1468,7 @@ PACKAGE BODY tb_dp_pkg IS WAIT UNTIL rising_edge(clk); out_ready <= '1'; FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP; - + ---------------------------------------------------------------------------- -- Interval 3 ---------------------------------------------------------------------------- @@ -1525,7 +1543,7 @@ PACKAGE BODY tb_dp_pkg IS END LOOP; out_ready <= '1'; FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP; - + -- . 3-1 toggle out_ready <= '0'; FOR I IN 1 TO c_dp_nof_toggle LOOP @@ -1580,7 +1598,7 @@ PACKAGE BODY tb_dp_pkg IS WAIT UNTIL sync='1'; out_ready <= '1'; FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP; - + FOR I IN 1 TO c_dp_nof_both LOOP out_ready <= '0'; FOR J IN I TO c_dp_nof_both LOOP WAIT UNTIL rising_edge(clk); END LOOP; @@ -1613,30 +1631,30 @@ PACKAGE BODY tb_dp_pkg IS END LOOP; out_ready <= '1'; FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP; - + ---------------------------------------------------------------------------- -- Interval 9 : Random ---------------------------------------------------------------------------- WAIT UNTIL sync='1'; out_ready <= '1'; - + FOR I IN 0 TO c_dp_sync_interval - c_dp_test_interval LOOP lfsr <= func_common_random(lfsr); out_ready <= lfsr(lfsr'HIGH); WAIT UNTIL rising_edge(clk); END LOOP; - + ---------------------------------------------------------------------------- -- Done ---------------------------------------------------------------------------- WAIT; END proc_dp_out_ready; - + ------------------------------------------------------------------------------ -- PROCEDURE: DUT output verify enable ------------------------------------------------------------------------------ - + -- Fixed delay until verify_en active PROCEDURE proc_dp_verify_en(CONSTANT c_delay : IN NATURAL; SIGNAL rst : IN STD_LOGIC; @@ -1647,16 +1665,16 @@ PACKAGE BODY tb_dp_pkg IS verify_en <= '0'; WAIT UNTIL rst='0'; WAIT UNTIL rising_edge(clk); - + WAIT UNTIL sync='1'; -- Use c_delay delay before enabling the p_verify. FOR I IN 0 TO c_delay LOOP WAIT UNTIL rising_edge(clk); END LOOP; - + verify_en <= '1'; WAIT; END proc_dp_verify_en; - - + + -- Dynamicly depend on first valid data to make verify_en active PROCEDURE proc_dp_verify_en(CONSTANT c_continuous : IN BOOLEAN; SIGNAL clk : IN STD_LOGIC; @@ -1681,7 +1699,7 @@ PACKAGE BODY tb_dp_pkg IS END IF; END IF; END proc_dp_verify_en; - + -- Run and verify for some cycles PROCEDURE proc_dp_verify_run_some_cycles(CONSTANT nof_pre_clk : IN NATURAL; CONSTANT nof_verify_clk : IN NATURAL; @@ -1695,7 +1713,7 @@ PACKAGE BODY tb_dp_pkg IS verify_en <= '0'; proc_common_wait_some_cycles(clk, nof_post_clk); END proc_dp_verify_run_some_cycles; - + ------------------------------------------------------------------------------ -- PROCEDURE: Verify the expected value @@ -1705,7 +1723,7 @@ PACKAGE BODY tb_dp_pkg IS CONSTANT mode : IN t_dp_value_enum; SIGNAL clk : IN STD_LOGIC; SIGNAL en : IN STD_LOGIC; - SIGNAL exp : IN STD_LOGIC_VECTOR; + SIGNAL exp : IN STD_LOGIC_VECTOR; SIGNAL res : IN STD_LOGIC_VECTOR) IS BEGIN IF rising_edge(clk) THEN @@ -1723,16 +1741,16 @@ PACKAGE BODY tb_dp_pkg IS PROCEDURE proc_dp_verify_value(CONSTANT mode : IN t_dp_value_enum; SIGNAL clk : IN STD_LOGIC; SIGNAL en : IN STD_LOGIC; - SIGNAL exp : IN STD_LOGIC_VECTOR; + SIGNAL exp : IN STD_LOGIC_VECTOR; SIGNAL res : IN STD_LOGIC_VECTOR) IS BEGIN proc_dp_verify_value("", mode, clk, en, exp, res); END proc_dp_verify_value; - + PROCEDURE proc_dp_verify_value(CONSTANT c_str : IN STRING; SIGNAL clk : IN STD_LOGIC; SIGNAL en : IN STD_LOGIC; - SIGNAL exp : IN STD_LOGIC; + SIGNAL exp : IN STD_LOGIC; SIGNAL res : IN STD_LOGIC) IS BEGIN IF rising_edge(clk) THEN @@ -1743,7 +1761,7 @@ PACKAGE BODY tb_dp_pkg IS END IF; END IF; END proc_dp_verify_value; - + ------------------------------------------------------------------------------ -- PROCEDURE: Verify output global and local BSN ------------------------------------------------------------------------------ @@ -1751,7 +1769,7 @@ PACKAGE BODY tb_dp_pkg IS -- . incrementing or replicated global BSN -- . incrementing local BSN that starts at 1 -- - -- _ _ _ _ + -- _ _ _ _ -- sync __| |____________| |____________| |____________| |____________ -- _ _ _ _ _ _ _ _ _ _ _ _ -- sop __| |__| |__| |__| |__| |__| |__| |__| |__| |__| |__| |__| |__ c_block_per_sync = 3 @@ -1767,7 +1785,7 @@ PACKAGE BODY tb_dp_pkg IS -- global bsn 3 6 9 12 c_global_bsn_increment = 3, c_nof_replicated_global_bsn = 1 -- global bsn 3 3 9 9 c_global_bsn_increment = 6, c_nof_replicated_global_bsn = 2 -- local bsn - 1 2 - 1 2 - 1 2 - 1 2 range 1:c_block_per_sync-1 - -- + -- -- The verify_en should initially be set to '0' and gets enabled when -- sufficient BSN history is available to do the verification. -- @@ -1833,11 +1851,11 @@ PACKAGE BODY tb_dp_pkg IS END IF; END IF; END proc_dp_verify_bsn; - + ------------------------------------------------------------------------------ -- PROCEDURE: Verify the DUT output data ------------------------------------------------------------------------------ - + -- Verify incrementing data -- . wrap at c_out_data_max when >0, else no wrap when c_out_data_max=0 -- . default increment by 1, but also allow an increment by c_out_data_gap @@ -1876,7 +1894,7 @@ PACKAGE BODY tb_dp_pkg IS END IF; END IF; END proc_dp_verify_data; - + -- Verify incrementing data that wraps in range 0 ... c_out_data_max PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING; CONSTANT c_ready_latency : IN NATURAL; @@ -1890,7 +1908,7 @@ PACKAGE BODY tb_dp_pkg IS BEGIN proc_dp_verify_data(c_str, c_ready_latency, c_out_data_max, TO_UNSIGNED(1,1), clk, verify_en, out_ready, out_val, out_data, prev_out_data); END proc_dp_verify_data; - + -- Verify incrementing data PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING; CONSTANT c_ready_latency : IN NATURAL; @@ -1903,7 +1921,7 @@ PACKAGE BODY tb_dp_pkg IS BEGIN proc_dp_verify_data(c_str, c_ready_latency, TO_UNSIGNED(0,1), TO_UNSIGNED(1,1), clk, verify_en, out_ready, out_val, out_data, prev_out_data); END proc_dp_verify_data; - + -- Verify incrementing data with RL > 0 or no flow control PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING; CONSTANT c_out_data_max : IN UNSIGNED; @@ -1917,7 +1935,7 @@ PACKAGE BODY tb_dp_pkg IS -- Use out_val as void signal to pass on to unused out_ready, because a signal input can not connect a constant or variable proc_dp_verify_data(c_str, 1, c_out_data_max, c_out_data_gap, clk, verify_en, out_val, out_val, out_data, prev_out_data); END proc_dp_verify_data; - + PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING; CONSTANT c_out_data_max : IN NATURAL; CONSTANT c_out_data_gap : IN NATURAL; @@ -1930,7 +1948,7 @@ PACKAGE BODY tb_dp_pkg IS BEGIN proc_dp_verify_data(c_str, TO_UNSIGNED(c_out_data_max, c_data_w), TO_UNSIGNED(c_out_data_gap, c_data_w), clk, verify_en, out_val, out_data, prev_out_data); END proc_dp_verify_data; - + PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING; CONSTANT c_out_data_max : IN NATURAL; SIGNAL clk : IN STD_LOGIC; @@ -1942,7 +1960,7 @@ PACKAGE BODY tb_dp_pkg IS BEGIN proc_dp_verify_data(c_str, TO_UNSIGNED(c_out_data_max, c_data_w), TO_UNSIGNED(1, 1), clk, verify_en, out_val, out_data, prev_out_data); END proc_dp_verify_data; - + PROCEDURE proc_dp_verify_data(CONSTANT c_str : IN STRING; SIGNAL clk : IN STD_LOGIC; SIGNAL verify_en : IN STD_LOGIC; @@ -1953,7 +1971,7 @@ PACKAGE BODY tb_dp_pkg IS -- Use out_val as void signal to pass on to unused out_ready, because a signal input can not connect a constant or variable proc_dp_verify_data(c_str, 1, TO_UNSIGNED(0,1), TO_UNSIGNED(1,1), clk, verify_en, out_val, out_val, out_data, prev_out_data); END proc_dp_verify_data; - + ------------------------------------------------------------------------------ -- PROCEDURE: Verify incrementing symbols in data -- . for c_data_w = c_symbol_w proc_dp_verify_symbols() = proc_dp_verify_data() @@ -2011,8 +2029,8 @@ PACKAGE BODY tb_dp_pkg IS END IF; END IF; END proc_dp_verify_symbols; - - + + ------------------------------------------------------------------------------ -- PROCEDURE: Verify the DUT output data with empty -- . account for stream empty @@ -2098,9 +2116,9 @@ PACKAGE BODY tb_dp_pkg IS END IF; END IF; END IF; - END proc_dp_verify_data_empty; - - + END proc_dp_verify_data_empty; + + ------------------------------------------------------------------------------ -- PROCEDURE: Verify the DUT output other SOSI data -- . Suited to verify the empty, error, channel fields assuming that these @@ -2136,8 +2154,8 @@ PACKAGE BODY tb_dp_pkg IS END IF; END IF; END proc_dp_verify_other_sosi; - - + + ------------------------------------------------------------------------------ -- PROCEDURE: Verify the DUT output valid ------------------------------------------------------------------------------ @@ -2166,7 +2184,7 @@ PACKAGE BODY tb_dp_pkg IS END IF; END IF; END proc_dp_verify_valid; - + PROCEDURE proc_dp_verify_valid(SIGNAL clk : IN STD_LOGIC; SIGNAL verify_en : IN STD_LOGIC; SIGNAL out_ready : IN STD_LOGIC; @@ -2186,7 +2204,7 @@ PACKAGE BODY tb_dp_pkg IS END IF; END IF; END proc_dp_verify_valid; - + ------------------------------------------------------------------------------ -- PROCEDURE: Verify the DUT output sync -- . sync is defined such that it can only be active at sop @@ -2220,7 +2238,109 @@ PACKAGE BODY tb_dp_pkg IS 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 + ------------------------------------------------------------------------------ + 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 + -- . assume that the sync occures priodically at bsn MOD c_sync_period = c_sync_offset + ------------------------------------------------------------------------------ + PROCEDURE proc_dp_verify_sync_v2(CONSTANT c_sync_period : IN NATURAL; -- BSN sync period + CONSTANT c_sync_offset : IN NATURAL; -- BSN sync offset + SIGNAL clk : IN STD_LOGIC; + SIGNAL verify_en : IN STD_LOGIC; + SIGNAL sync : IN STD_LOGIC; + SIGNAL sop : IN STD_LOGIC; + SIGNAL bsn : IN STD_LOGIC_VECTOR; + 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_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_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_expected_sync := TRUE; + --REPORT "bsn count valid " & int_to_str(v_tb_bsn_cnt); + ELSE + v_expected_sync := FALSE; + END IF; + + v_tb_bsn_cnt := 0; -- reset tb_bsn_cnt + END IF; + + -- on sop increment tb_bsn_cnt by 1 + IF sop='1' THEN + v_tb_bsn_cnt := v_tb_bsn_cnt + 1; + END IF; + + -- if bsn = 0 (when in dp_off state) set tb_bsn_cnt also to 0 + IF TO_UINT(bsn(c_bsn_w-1 DOWNTO 0)) = c_sync_offset THEN + v_tb_bsn_cnt := 0; + END IF; + + tb_bsn_cnt <= v_tb_bsn_cnt; -- assign variable to signal + + -- Check for unexpected sync + IF sync='1' THEN + 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_expected_sync=TRUE THEN + ASSERT sync = '1' + REPORT "Error: Missing sync" SEVERITY ERROR; + END IF; + -- Check for missing sync + IF sop='1' THEN + ASSERT v_tb_bsn_cnt <= c_sync_period + REPORT "Error: bsn count " & int_to_str(v_tb_bsn_cnt) & " > " & int_to_str(c_sync_period) SEVERITY ERROR; + END IF; + + END IF; + END IF; + END proc_dp_verify_sync_v2; + ------------------------------------------------------------------------------ -- PROCEDURE: Verify the DUT output sop and eop @@ -2263,7 +2383,7 @@ PACKAGE BODY tb_dp_pkg IS END IF; END IF; END proc_dp_verify_sop_and_eop; - + PROCEDURE proc_dp_verify_sop_and_eop(CONSTANT c_ready_latency : IN NATURAL; SIGNAL clk : IN STD_LOGIC; SIGNAL out_ready : IN STD_LOGIC; @@ -2274,7 +2394,7 @@ PACKAGE BODY tb_dp_pkg IS BEGIN proc_dp_verify_sop_and_eop(c_ready_latency, TRUE, clk, out_ready, out_val, out_sop, out_eop, hold_sop); END proc_dp_verify_sop_and_eop; - + PROCEDURE proc_dp_verify_sop_and_eop(SIGNAL clk : IN STD_LOGIC; SIGNAL out_val : IN STD_LOGIC; SIGNAL out_sop : IN STD_LOGIC; @@ -2284,10 +2404,10 @@ PACKAGE BODY tb_dp_pkg IS -- Use out_val as void signal to pass on to unused out_ready, because a signal input can not connect a constant or variable proc_dp_verify_sop_and_eop(1, TRUE, clk, out_val, out_val, out_sop, out_eop, hold_sop); END proc_dp_verify_sop_and_eop; - + PROCEDURE proc_dp_verify_block_size(CONSTANT c_ready_latency : IN NATURAL; SIGNAL alt_size : IN NATURAL; -- alternative size - SIGNAL exp_size : IN NATURAL; -- expected size + SIGNAL exp_size : IN NATURAL; -- expected size SIGNAL clk : IN STD_LOGIC; SIGNAL out_ready : IN STD_LOGIC; SIGNAL out_val : IN STD_LOGIC; @@ -2314,7 +2434,7 @@ PACKAGE BODY tb_dp_pkg IS END IF; END IF; END proc_dp_verify_block_size; - + PROCEDURE proc_dp_verify_block_size(CONSTANT c_ready_latency : IN NATURAL; SIGNAL exp_size : IN NATURAL; SIGNAL clk : IN STD_LOGIC; @@ -2326,9 +2446,9 @@ PACKAGE BODY tb_dp_pkg IS BEGIN proc_dp_verify_block_size(c_ready_latency, exp_size, exp_size, clk, out_ready, out_val, out_sop, out_eop, cnt_size); END proc_dp_verify_block_size; - + PROCEDURE proc_dp_verify_block_size(SIGNAL alt_size : IN NATURAL; -- alternative size - SIGNAL exp_size : IN NATURAL; -- expected size + SIGNAL exp_size : IN NATURAL; -- expected size SIGNAL clk : IN STD_LOGIC; SIGNAL out_val : IN STD_LOGIC; SIGNAL out_sop : IN STD_LOGIC; @@ -2338,7 +2458,7 @@ PACKAGE BODY tb_dp_pkg IS -- Use out_val as void signal to pass on to unused out_ready, because a signal input can not connect a constant or variable proc_dp_verify_block_size(1, alt_size, exp_size, clk, out_val, out_val, out_sop, out_eop, cnt_size); END proc_dp_verify_block_size; - + PROCEDURE proc_dp_verify_block_size(SIGNAL exp_size : IN NATURAL; SIGNAL clk : IN STD_LOGIC; SIGNAL out_val : IN STD_LOGIC; @@ -2349,7 +2469,7 @@ PACKAGE BODY tb_dp_pkg IS -- Use out_val as void signal to pass on to unused out_ready, because a signal input can not connect a constant or variable proc_dp_verify_block_size(1, exp_size, exp_size, clk, out_val, out_val, out_sop, out_eop, cnt_size); END proc_dp_verify_block_size; - + ------------------------------------------------------------------------------ -- PROCEDURE: Verify the DUT output invalid between frames ------------------------------------------------------------------------------ @@ -2369,8 +2489,8 @@ PACKAGE BODY tb_dp_pkg IS END IF; END IF; END proc_dp_verify_gap_invalid; - - + + ------------------------------------------------------------------------------ -- PROCEDURE: Verify the DUT output control (use for sop, eop) ------------------------------------------------------------------------------ @@ -2399,8 +2519,8 @@ PACKAGE BODY tb_dp_pkg IS END IF; END IF; END proc_dp_verify_ctrl; - - + + ------------------------------------------------------------------------------ -- PROCEDURE: Wait for stream valid ------------------------------------------------------------------------------ @@ -2412,8 +2532,8 @@ PACKAGE BODY tb_dp_pkg IS WAIT UNTIL rising_edge(clk); END LOOP; END proc_dp_stream_valid; - - + + ------------------------------------------------------------------------------ -- PROCEDURE: Wait for stream valid AND sop ------------------------------------------------------------------------------ @@ -2427,7 +2547,7 @@ PACKAGE BODY tb_dp_pkg IS END LOOP; END proc_dp_stream_valid_sop; - + ------------------------------------------------------------------------------ -- PROCEDURE: Wait for stream valid AND eop ------------------------------------------------------------------------------ @@ -2440,5 +2560,5 @@ PACKAGE BODY tb_dp_pkg IS WAIT UNTIL rising_edge(clk); END LOOP; END proc_dp_stream_valid_eop; - + END tb_dp_pkg; 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 new file mode 100644 index 0000000000000000000000000000000000000000..88eda9967bd5ab232c057bde57d50bc998f610af --- /dev/null +++ b/libraries/base/dp/tb/vhdl/tb_mms_dp_bsn_source_v2.vhd @@ -0,0 +1,209 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2012 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- +-- Purpose: +-- . Test bench for mms_dp_bsn_source_v2 +-- Description: +-- . Verify DP on, off via MM +-- . Verify captured BSN via MM during a sync interval +-- . Verify changing of BSN_time_offset +-- +-- Usage: +-- > as 10 +-- > run -all +-- > view expanded bs_sosi in Wave window + +LIBRARY IEEE, common_lib, mm_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 common_lib.common_mem_pkg.ALL; +USE common_lib.tb_common_mem_pkg.ALL; +USE work.dp_stream_pkg.ALL; +USE work.tb_dp_pkg.ALL; + +ENTITY tb_mms_dp_bsn_source_v2 IS +END tb_mms_dp_bsn_source_v2; + +ARCHITECTURE tb OF tb_mms_dp_bsn_source_v2 IS + + CONSTANT c_bsn_time_offset_w : NATURAL := 10; + + CONSTANT c_clk_period : TIME := 10 ns; + + CONSTANT c_pps_interval : NATURAL := 1000; + CONSTANT c_cross_clock_domain_latency : NATURAL := 20; + + 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_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; + CONSTANT c_mm_addr_bsn_lo : NATURAL := 2; + CONSTANT c_mm_addr_bsn_hi : NATURAL := 3; + CONSTANT c_mm_addr_bsn_time_offset : NATURAL := 4; + + CONSTANT c_mm_dp_off : NATURAL := 0; -- DP off after finishing current block + CONSTANT c_mm_dp_on_immediate : NATURAL := 1; -- DP on immediate by setting bit 0 + CONSTANT c_mm_dp_on_at_pps : NATURAL := 3; -- DP on at next PPS by setting bits 1,0 + + SIGNAL tb_end : STD_LOGIC := '0'; + SIGNAL clk : STD_LOGIC := '1'; + SIGNAL rst : STD_LOGIC := '1'; + SIGNAL pps : STD_LOGIC := '0'; + + SIGNAL bs_sosi : t_dp_sosi; + + SIGNAL mm_dp_on_status : NATURAL; + SIGNAL mm_bsn : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0) := (OTHERS=>'0'); + SIGNAL mm_bsn_prev : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0) := (OTHERS=>'0'); + + SIGNAL mm_bsn_time_offset : STD_LOGIC_VECTOR(c_bsn_time_offset_w-1 DOWNTO 0) := (OTHERS=>'0'); + + SIGNAL mm_mosi : t_mem_mosi := c_mem_mosi_rst; + SIGNAL mm_miso : t_mem_miso; + +BEGIN + + clk <= (NOT clk) OR tb_end AFTER clk_period/2; + rst <= '1', '0' AFTER clk_period*7; + + proc_common_gen_pulse(1, c_pps_interval, '1', rst, clk, pps); + + p_mm_stimuli : PROCESS + BEGIN + WAIT UNTIL rst='0'; + 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_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); + + -------------------------------------------------------------------------- + -- DP on immediate + -------------------------------------------------------------------------- + + -- Wait until after PPS + proc_common_wait_until_hi_lo(clk, pps); + + -- Write DP on immediate + proc_mem_mm_bus_wr(c_mm_addr_dp_on, c_mm_dp_on_immediate, clk, mm_miso, mm_mosi); + proc_common_wait_some_cycles(clk, c_cross_clock_domain_latency); + + -- Read dp on status + proc_mem_mm_bus_rd(c_mm_addr_dp_on, clk, mm_miso, mm_mosi); + proc_mem_mm_bus_rd_latency(1, clk); + mm_dp_on_status <= TO_UINT(mm_miso.rddata(1 DOWNTO 0)); + proc_common_wait_some_cycles(clk, 1); + ASSERT mm_dp_on_status=c_mm_dp_on_immediate REPORT "Wrong DP on status, expected DP on immediate." SEVERITY ERROR; + + -- Read BSN twice in same PPS interval + proc_common_wait_some_cycles(clk, c_block_size); + + proc_mem_mm_bus_rd(c_mm_addr_bsn_lo, clk, mm_miso, mm_mosi); + proc_mem_mm_bus_rd_latency(1, clk); + mm_bsn(c_word_w-1 DOWNTO 0) <= mm_miso.rddata(c_word_w-1 DOWNTO 0); + proc_mem_mm_bus_rd(c_mm_addr_bsn_hi, clk, mm_miso, mm_mosi); + proc_mem_mm_bus_rd_latency(1, clk); + mm_bsn(2*c_word_w-1 DOWNTO c_word_w) <= mm_miso.rddata(c_word_w-1 DOWNTO 0); + + proc_common_wait_some_cycles(clk, c_block_size); + + mm_bsn_prev <= mm_bsn; + proc_mem_mm_bus_rd(c_mm_addr_bsn_lo, clk, mm_miso, mm_mosi); + proc_mem_mm_bus_rd_latency(1, clk); + mm_bsn(c_word_w-1 DOWNTO 0) <= mm_miso.rddata(c_word_w-1 DOWNTO 0); + proc_mem_mm_bus_rd(c_mm_addr_bsn_hi, clk, mm_miso, mm_mosi); + proc_mem_mm_bus_rd_latency(1, clk); + mm_bsn(2*c_word_w-1 DOWNTO c_word_w) <= mm_miso.rddata(c_word_w-1 DOWNTO 0); + proc_common_wait_some_cycles(clk, 1); + + -- Uncomment appropriate assert line dependent on fixed code for capture_bsn in mms_dp_bsn_source: + --ASSERT mm_bsn_prev<mm_bsn REPORT "Wrong BSN, expected incrementing BSN during PPS or sync interval." SEVERITY ERROR; + ASSERT mm_bsn_prev=mm_bsn REPORT "Wrong BSN, expected constant BSN during PPS or sync interval." SEVERITY ERROR; + + -- Run few sync intervals + proc_common_wait_some_cycles(clk, 3*c_sync_interval); + + -- Write DP off + proc_mem_mm_bus_wr(c_mm_addr_dp_on, c_mm_dp_off, clk, mm_miso, mm_mosi); + proc_common_wait_some_cycles(clk, c_block_size); + + -- Read dp on status + proc_mem_mm_bus_rd(c_mm_addr_dp_on, clk, mm_miso, mm_mosi); + proc_mem_mm_bus_rd_latency(1, clk); + mm_dp_on_status <= TO_UINT(mm_miso.rddata(1 DOWNTO 0)); + proc_common_wait_some_cycles(clk, 1); + ASSERT mm_dp_on_status=c_mm_dp_off REPORT "Wrong DP on status, expected DP off." SEVERITY ERROR; + + -- Set bsn_time_offset and read back 2 times 0 and 5 + proc_mem_mm_bus_wr(c_mm_addr_bsn_time_offset, 0, clk, mm_miso, mm_mosi); + proc_common_wait_some_cycles(clk, 2*c_cross_clock_domain_latency); + + proc_mem_mm_bus_rd(c_mm_addr_bsn_time_offset, clk, mm_miso, mm_mosi); + proc_mem_mm_bus_rd_latency(1, clk); + mm_bsn_time_offset(c_bsn_time_offset_w-1 DOWNTO 0) <= mm_miso.rddata(c_bsn_time_offset_w-1 DOWNTO 0); + proc_common_wait_some_cycles(clk, 1); + ASSERT TO_UINT(mm_bsn_time_offset(c_bsn_time_offset_w-1 DOWNTO 0))=0 REPORT "Wrong offset, expected 0" SEVERITY ERROR; + + proc_mem_mm_bus_wr(c_mm_addr_bsn_time_offset, 5, clk, mm_miso, mm_mosi); + proc_common_wait_some_cycles(clk, 2*c_cross_clock_domain_latency); + + proc_mem_mm_bus_rd(c_mm_addr_bsn_time_offset, clk, mm_miso, mm_mosi); + proc_mem_mm_bus_rd_latency(1, clk); + mm_bsn_time_offset(c_bsn_time_offset_w-1 DOWNTO 0) <= mm_miso.rddata(c_bsn_time_offset_w-1 DOWNTO 0); + proc_common_wait_some_cycles(clk, 1); + ASSERT TO_UINT(mm_bsn_time_offset(c_bsn_time_offset_w-1 DOWNTO 0))=5 REPORT "Wrong offset, expected 5" SEVERITY ERROR; + + proc_common_wait_some_cycles(clk, c_sync_interval); + tb_end <= '1'; + WAIT; + END PROCESS; + + u_dut : ENTITY work.mms_dp_bsn_source_v2 + GENERIC MAP ( + g_cross_clock_domain => TRUE, -- use FALSE when mm_clk and st_clk are the same, else use TRUE to cross the clock domain + g_block_size => c_block_size, + g_nof_clk_per_sync => 200 * 10**6, -- overrule via MM write + g_bsn_w => c_dp_stream_bsn_w + ) + PORT MAP ( + -- Clocks and reset + mm_rst => rst, + mm_clk => clk, + dp_rst => rst, + dp_clk => clk, + dp_pps => pps, + + -- Memory-mapped clock domain + reg_mosi => mm_mosi, -- actual ranges defined by c_mm_reg in dp_bsn_source_reg + reg_miso => mm_miso, -- actual ranges defined by c_mm_reg in dp_bsn_source_reg + + -- Streaming clock domain + bs_sosi => bs_sosi + ); + +END tb; + 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 new file mode 100644 index 0000000000000000000000000000000000000000..4c1700d33404cb7a9399ba52a7ed41642e12456a --- /dev/null +++ b/libraries/base/dp/tb/vhdl/tb_tb_dp_bsn_source_v2.vhd @@ -0,0 +1,55 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2010 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +LIBRARY IEEE; +USE IEEE.std_logic_1164.ALL; +USE work.tb_dp_pkg.ALL; + + +-- > as 2 +-- > run -all --> OK + +ENTITY tb_tb_dp_bsn_source_v2 IS +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_pps_interval : NATURAL := 240 + -- g_block_size : NATURAL := 32 + + -- (g_pps_interval, g_block_size) + -- test different clk_per_sync + u0_230 : ENTITY work.tb_dp_bsn_source_v2 GENERIC MAP (230, 32); + u0_240 : ENTITY work.tb_dp_bsn_source_v2 GENERIC MAP (240, 32); + u0_248 : ENTITY work.tb_dp_bsn_source_v2 GENERIC MAP (248, 32); + + -- test different block_size's + u1_1 : ENTITY work.tb_dp_bsn_source_v2 GENERIC MAP (240, 30); + u1_3 : ENTITY work.tb_dp_bsn_source_v2 GENERIC MAP (240, 32); + u1_4 : ENTITY work.tb_dp_bsn_source_v2 GENERIC MAP (240, 27); + +END tb; + \ No newline at end of file