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

Merge branch 'L2SDP-49' into 'master'

Resolve L2SDP-49

Closes L2SDP-49

See merge request desp/hdl!54
parents 53cd1386 4aba84c2
No related branches found
No related tags found
2 merge requests!100Removed text for XSub that is now written in Confluence Subband correlator...,!54Resolve L2SDP-49
...@@ -74,8 +74,11 @@ synth_files = ...@@ -74,8 +74,11 @@ synth_files =
src/vhdl/dp_block_gen.vhd src/vhdl/dp_block_gen.vhd
src/vhdl/dp_block_gen_valid_arr.vhd src/vhdl/dp_block_gen_valid_arr.vhd
src/vhdl/dp_bsn_source.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.vhd
src/vhdl/dp_bsn_source_reg_v2.vhd
src/vhdl/mms_dp_bsn_source.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.vhd
src/vhdl/dp_bsn_scheduler_reg.vhd src/vhdl/dp_bsn_scheduler_reg.vhd
src/vhdl/mms_dp_bsn_scheduler.vhd src/vhdl/mms_dp_bsn_scheduler.vhd
...@@ -185,7 +188,9 @@ test_bench_files = ...@@ -185,7 +188,9 @@ test_bench_files =
tb/vhdl/tb_mms_dp_bsn_align.vhd tb/vhdl/tb_mms_dp_bsn_align.vhd
tb/vhdl/tb_dp_bsn_monitor.vhd tb/vhdl/tb_dp_bsn_monitor.vhd
tb/vhdl/tb_dp_bsn_source.vhd tb/vhdl/tb_dp_bsn_source.vhd
tb/vhdl/tb_dp_bsn_source_v2.vhd
tb/vhdl/tb_mms_dp_bsn_source.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/tb_dp_demux.vhd
tb/vhdl/tb2_dp_demux.vhd tb/vhdl/tb2_dp_demux.vhd
tb/vhdl/tb3_dp_demux.vhd tb/vhdl/tb3_dp_demux.vhd
...@@ -253,6 +258,7 @@ test_bench_files = ...@@ -253,6 +258,7 @@ test_bench_files =
tb/vhdl/tb_tb_dp_block_gen.vhd tb/vhdl/tb_tb_dp_block_gen.vhd
tb/vhdl/tb_tb_dp_block_gen_valid_arr.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_align.vhd
tb/vhdl/tb_tb_dp_bsn_source_v2.vhd
tb/vhdl/tb_tb_dp_concat.vhd tb/vhdl/tb_tb_dp_concat.vhd
tb/vhdl/tb_tb_dp_demux.vhd tb/vhdl/tb_tb_dp_demux.vhd
tb/vhdl/tb_tb2_dp_demux.vhd tb/vhdl/tb_tb2_dp_demux.vhd
...@@ -305,6 +311,7 @@ regression_test_vhdl = ...@@ -305,6 +311,7 @@ regression_test_vhdl =
tb/vhdl/tb_dp_shiftreg.vhd tb/vhdl/tb_dp_shiftreg.vhd
tb/vhdl/tb_dp_bsn_source.vhd tb/vhdl/tb_dp_bsn_source.vhd
tb/vhdl/tb_mms_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_select.vhd
tb/vhdl/tb_tb_dp_block_reshape.vhd tb/vhdl/tb_tb_dp_block_reshape.vhd
...@@ -312,6 +319,7 @@ regression_test_vhdl = ...@@ -312,6 +319,7 @@ regression_test_vhdl =
tb/vhdl/tb_tb_dp_block_gen.vhd tb/vhdl/tb_tb_dp_block_gen.vhd
tb/vhdl/tb_tb_dp_block_gen_valid_arr.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_align.vhd
tb/vhdl/tb_tb_dp_bsn_source_v2.vhd
tb/vhdl/tb_tb_dp_concat.vhd tb/vhdl/tb_tb_dp_concat.vhd
tb/vhdl/tb_tb_dp_demux.vhd tb/vhdl/tb_tb_dp_demux.vhd
tb/vhdl/tb_tb2_dp_demux.vhd tb/vhdl/tb_tb2_dp_demux.vhd
......
-------------------------------------------------------------------------------
--
-- 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;
-------------------------------------------------------------------------------
--
-- 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;
...@@ -264,6 +264,7 @@ PACKAGE dp_stream_pkg Is ...@@ -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_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_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_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 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' 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 ...@@ -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)); RETURN RESIZE_DP_DSP_DATA(STD_LOGIC_VECTOR(SIGNED(vec(w-1 DOWNTO 0)) + dec));
END INCR_DP_DSP_DATA; 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 FUNCTION REPLICATE_DP_DATA(seq : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
CONSTANT c_seq_w : NATURAL := seq'LENGTH; CONSTANT c_seq_w : NATURAL := seq'LENGTH;
CONSTANT c_nof_replications : NATURAL := ceil_div(c_dp_stream_data_w, c_seq_w); CONSTANT c_nof_replications : NATURAL := ceil_div(c_dp_stream_data_w, c_seq_w);
......
-------------------------------------------------------------------------------
--
-- 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;
-------------------------------------------------------------------------------
--
-- 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;
This diff is collapsed.
-------------------------------------------------------------------------------
--
-- 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;
-------------------------------------------------------------------------------
--
-- 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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment