From 8a9d2984617437632260a1a375f2d5a2992519e6 Mon Sep 17 00:00:00 2001 From: Erik Kooistra <kooistra@astron.nl> Date: Fri, 17 Nov 2017 14:12:32 +0000 Subject: [PATCH] Added dp_bsn_restore_global.vhd and used and verified it in dp_block_gen_valid_arr.vhd. --- libraries/base/dp/hdllib.cfg | 1 + .../dp/src/vhdl/dp_block_gen_valid_arr.vhd | 73 +++++++---- .../dp/src/vhdl/dp_bsn_restore_global.vhd | 121 ++++++++++++++++++ .../dp/tb/vhdl/tb_dp_block_gen_valid_arr.vhd | 34 +++-- .../tb/vhdl/tb_tb_dp_block_gen_valid_arr.vhd | 28 ++-- 5 files changed, 210 insertions(+), 47 deletions(-) create mode 100644 libraries/base/dp/src/vhdl/dp_bsn_restore_global.vhd diff --git a/libraries/base/dp/hdllib.cfg b/libraries/base/dp/hdllib.cfg index 501c1bd142..2a55c9c043 100644 --- a/libraries/base/dp/hdllib.cfg +++ b/libraries/base/dp/hdllib.cfg @@ -68,6 +68,7 @@ synth_files = src/vhdl/dp_pad_remove.vhd src/vhdl/dp_block_gen.vhd src/vhdl/dp_block_gen_valid_arr.vhd + src/vhdl/dp_bsn_restore_global.vhd src/vhdl/dp_bsn_source.vhd src/vhdl/dp_bsn_source_reg.vhd src/vhdl/mms_dp_bsn_source.vhd diff --git a/libraries/base/dp/src/vhdl/dp_block_gen_valid_arr.vhd b/libraries/base/dp/src/vhdl/dp_block_gen_valid_arr.vhd index 62e7b2f7fb..66538e01ea 100644 --- a/libraries/base/dp/src/vhdl/dp_block_gen_valid_arr.vhd +++ b/libraries/base/dp/src/vhdl/dp_block_gen_valid_arr.vhd @@ -148,7 +148,8 @@ ENTITY dp_block_gen_valid_arr IS g_nof_data_per_block : POSITIVE := 1; g_nof_blk_per_sync : POSITIVE := 8; g_check_input_sync : BOOLEAN := FALSE; - g_nof_pages_bsn : NATURAL := 0 + g_nof_pages_bsn : NATURAL := 0; + g_restore_global_bsn : BOOLEAN := FALSE ); PORT ( rst : IN STD_LOGIC; @@ -188,7 +189,7 @@ ARCHITECTURE rtl OF dp_block_gen_valid_arr IS state : t_state; data_cnt : NATURAL RANGE 0 TO g_nof_data_per_block; blk_cnt : NATURAL RANGE 0 TO g_nof_blk_per_sync; - src_out : t_dp_sosi; + reg_sosi : t_dp_sosi; END RECORD; CONSTANT c_reg_rst : t_reg := (s_sop, 0, 0, c_dp_sosi_rst); @@ -197,6 +198,7 @@ ARCHITECTURE rtl OF dp_block_gen_valid_arr IS SIGNAL in_sync_wr_en : STD_LOGIC_VECTOR(g_nof_pages_bsn-1 DOWNTO 0); SIGNAL in_bsn_buffer : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0); + SIGNAL out_sosi : t_dp_sosi; SIGNAL nxt_src_out_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); -- Define the local registers in t_reg record @@ -245,21 +247,18 @@ BEGIN END PROCESS; END GENERATE; - -- Combine input data with the same out_put info and output ctrl for all streams - nxt_src_out_arr <= func_dp_stream_arr_combine_data_info_ctrl(snk_in_arr, nxt_r.src_out, nxt_r.src_out); - - -- Determine the output info and output ctrl using snk_in and r.src_out + -- Determine the output info and output ctrl using snk_in and r.reg_sosi p_state : PROCESS(r, enable, in_sosi) BEGIN nxt_r <= r; -- default output in_sosi, hold output bsn and set the output ctrl to '0' - nxt_r.src_out <= in_sosi; - nxt_r.src_out.bsn <= r.src_out.bsn; - nxt_r.src_out.valid <= '0'; - nxt_r.src_out.sop <= '0'; - nxt_r.src_out.eop <= '0'; - nxt_r.src_out.sync <= '0'; + nxt_r.reg_sosi <= in_sosi; + nxt_r.reg_sosi.bsn <= r.reg_sosi.bsn; + nxt_r.reg_sosi.valid <= '0'; + nxt_r.reg_sosi.sop <= '0'; + nxt_r.reg_sosi.eop <= '0'; + nxt_r.reg_sosi.sync <= '0'; CASE r.state IS WHEN s_sop => @@ -277,17 +276,17 @@ BEGIN -- create local sync and pass on input bsn at local sync IF r.blk_cnt=0 THEN -- output sync starts at first input valid - nxt_r.src_out.sync <= '1'; -- output sync for this block - nxt_r.src_out.bsn <= in_sosi.bsn; -- output input bsn at sync + nxt_r.reg_sosi.sync <= '1'; -- output sync for this block + nxt_r.reg_sosi.bsn <= in_sosi.bsn; -- output input bsn at sync ELSE - nxt_r.src_out.bsn <= TO_DP_BSN(r.blk_cnt); -- output local bsn for the subsequent blocks + nxt_r.reg_sosi.bsn <= TO_DP_BSN(r.blk_cnt); -- output local bsn for the subsequent blocks END IF; - nxt_r.src_out.valid <= '1'; - nxt_r.src_out.sop <= '1'; + nxt_r.reg_sosi.valid <= '1'; + nxt_r.reg_sosi.sop <= '1'; IF g_nof_data_per_block=1 THEN - nxt_r.src_out.eop <= '1'; -- single word block + nxt_r.reg_sosi.eop <= '1'; -- single word block ELSE nxt_r.data_cnt <= 1; -- start of multi word block nxt_r.state <= s_data; @@ -297,10 +296,10 @@ BEGIN IF g_check_input_sync=TRUE THEN IF r.blk_cnt=0 THEN IF snk_in.sync='0' THEN - nxt_r.src_out.valid <= '0'; -- undo all ctrl preparations for the new block - nxt_r.src_out.sop <= '0'; - nxt_r.src_out.eop <= '0'; - nxt_r.src_out.sync <= '0'; + nxt_r.reg_sosi.valid <= '0'; -- undo all ctrl preparations for the new block + nxt_r.reg_sosi.sop <= '0'; + nxt_r.reg_sosi.eop <= '0'; + nxt_r.reg_sosi.sync <= '0'; nxt_r.blk_cnt <= 0; -- restart blk_cnt nxt_r.state <= s_sop; -- remain in this state and wait for snk_in.sync END IF; @@ -311,18 +310,42 @@ BEGIN WHEN s_data => IF snk_in.valid='1' THEN nxt_r.data_cnt <= r.data_cnt+1; - nxt_r.src_out.valid <= '1'; + nxt_r.reg_sosi.valid <= '1'; IF r.data_cnt=g_nof_data_per_block-2 THEN nxt_r.state <= s_eop; END IF; END IF; WHEN OTHERS => -- s_eop IF snk_in.valid='1' THEN - nxt_r.src_out.valid <= '1'; - nxt_r.src_out.eop <= '1'; + nxt_r.reg_sosi.valid <= '1'; + nxt_r.reg_sosi.eop <= '1'; nxt_r.state <= s_sop; END IF; END CASE; END PROCESS; + + -- Use local BSN that counts from 0 during sync interval, or restore global BSN between syncs + use_local_bsn : IF g_restore_global_bsn=FALSE GENERATE + out_sosi <= nxt_r.reg_sosi; + END GENERATE; + + use_global_bsn : IF g_restore_global_bsn=TRUE GENERATE + u_dp_bsn_restore_global : ENTITY work.dp_bsn_restore_global + GENERIC MAP ( + g_bsn_w => c_dp_stream_bsn_w, + g_pipeline => 0 -- pipeline registering is done via nxt_src_out_arr + ) + PORT MAP ( + rst => rst, + clk => clk, + -- ST sink + snk_in => nxt_r.reg_sosi, + -- ST source + src_out => out_sosi + ); + END GENERATE; + -- Combine input data with the same out_put info and output ctrl for all streams + nxt_src_out_arr <= func_dp_stream_arr_combine_data_info_ctrl(snk_in_arr, out_sosi, out_sosi); + END rtl; diff --git a/libraries/base/dp/src/vhdl/dp_bsn_restore_global.vhd b/libraries/base/dp/src/vhdl/dp_bsn_restore_global.vhd new file mode 100644 index 0000000000..109a910bab --- /dev/null +++ b/libraries/base/dp/src/vhdl/dp_bsn_restore_global.vhd @@ -0,0 +1,121 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2017 +-- 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, common_lib; +USE IEEE.std_logic_1164.all; +USE common_lib.common_pkg.ALL; +USE work.dp_stream_pkg.ALL; + +-- Author: Eric Kooistra, 17 nov 2017 +-- Purpose: +-- Restore global BSN. +-- Description: +-- The input global BSN is active at the sync. In between sync the other BSN +-- BSN at the sop may count a local BSN that restarted at 0 for every sync. +-- This dp_bsn_restore_global takes the BSN at the sync and starts counting +-- from there for every sop, so in this way it restores the global BSN count +-- for the blocks in between syncs. +-- The increment for each restored BSN is 1. The assumption is that the +-- number of blocks between syncs equals the difference in global BSN values +-- between syncs. In this way the restored BSN counts without gaps or +-- duplicates. +-- Remarks: + +ENTITY dp_bsn_restore_global IS + GENERIC ( + g_bsn_w : NATURAL := c_dp_stream_bsn_w; + g_pipeline : NATURAL := 1 -- 0 for wires, > 0 for registers + ); + PORT ( + rst : IN STD_LOGIC; + clk : IN STD_LOGIC; + -- ST sink + snk_out : OUT t_dp_siso; + snk_in : IN t_dp_sosi; + -- ST source + src_in : IN t_dp_siso := c_dp_siso_rdy; + src_out : OUT t_dp_sosi + ); +END dp_bsn_restore_global; + + +ARCHITECTURE str OF dp_bsn_restore_global IS + + SIGNAL blk_sync : STD_LOGIC; + SIGNAL bsn_at_sync : STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0); + SIGNAL nxt_bsn_at_sync : STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0); + SIGNAL bsn_restored : STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0); + SIGNAL snk_in_restored : t_dp_sosi; + +BEGIN + + -- keep BSN at sync + p_clk : PROCESS(clk, rst) + BEGIN + IF rst='1' THEN + bsn_at_sync <= (OTHERS=>'0'); + ELSIF rising_edge(clk) THEN + bsn_at_sync <= nxt_bsn_at_sync; + END IF; + END PROCESS; + + -- Store global BSN at sync + nxt_bsn_at_sync <= snk_in.bsn(g_bsn_w-1 DOWNTO 0) WHEN snk_in.sync='1' ELSE bsn_at_sync; + + -- Create block sync from snk_in.sync, this blk_sync is active during entire first sop-eop block of sync interval + u_common_switch : ENTITY common_lib.common_switch + GENERIC MAP ( + g_rst_level => '0', -- Defines the output level at reset. + g_priority_lo => FALSE, -- When TRUE then input switch_low has priority, else switch_high. Don't care when switch_high and switch_low are pulses that do not occur simultaneously. + g_or_high => TRUE, -- When TRUE and priority hi then the registered switch_level is OR-ed with the input switch_high to get out_level, else out_level is the registered switch_level + g_and_low => FALSE -- When TRUE and priority lo then the registered switch_level is AND-ed with the input switch_low to get out_level, else out_level is the registered switch_level + ) + PORT MAP ( + rst => rst, + clk => clk, + switch_high => snk_in.sync, -- A pulse on switch_high makes the out_level go high + switch_low => snk_in.eop, -- A pulse on switch_low makes the out_level go low + out_level => blk_sync + ); + + -- Use stored global BSN at sync and add local BSN to restore the global BSN for every next sop + bsn_restored <= snk_in.bsn WHEN blk_sync='1' ELSE ADD_UVEC(bsn_at_sync, snk_in.bsn, g_bsn_w); + + snk_in_restored <= func_dp_stream_bsn_set(snk_in, bsn_restored); + + -- Add pipeline to ensure timing closure for the restored BSN summation + u_pipeline : ENTITY work.dp_pipeline + GENERIC MAP ( + g_pipeline => g_pipeline -- 0 for wires, > 0 for registers + ) + PORT MAP ( + rst => rst, + clk => clk, + -- ST sink + snk_out => snk_out, + snk_in => snk_in_restored, + -- ST source + src_in => src_in, + src_out => src_out + ); + +END str; diff --git a/libraries/base/dp/tb/vhdl/tb_dp_block_gen_valid_arr.vhd b/libraries/base/dp/tb/vhdl/tb_dp_block_gen_valid_arr.vhd index 31aae5f022..68eabaf55c 100644 --- a/libraries/base/dp/tb/vhdl/tb_dp_block_gen_valid_arr.vhd +++ b/libraries/base/dp/tb/vhdl/tb_dp_block_gen_valid_arr.vhd @@ -42,8 +42,9 @@ ENTITY tb_dp_block_gen_valid_arr IS g_nof_streams : POSITIVE := 1; g_nof_data_per_block : POSITIVE := 11; g_nof_blk_per_sync : POSITIVE := 8; - g_check_input_sync : BOOLEAN := FALSE; + g_check_input_sync : BOOLEAN := TRUE; g_nof_pages_bsn : NATURAL := 0; + g_restore_global_bsn : BOOLEAN := FALSE; g_enable : t_dp_flow_control_enum := e_active; -- always e_active or e_pulse block generator enable g_flow_control : t_dp_flow_control_enum := e_active; -- always e_active, e_random or e_pulse flow control for input valid g_nof_repeat : NATURAL := 1000 @@ -59,7 +60,8 @@ ARCHITECTURE tb OF tb_dp_block_gen_valid_arr IS CONSTANT c_dsp_latency : NATURAL := 1; -- >= 1 block and typically << g_nof_blk_per_sync blocks - CONSTANT c_bsn_init : NATURAL := 3; + CONSTANT c_sync_offset : NATURAL := 1; -- 0, < g_nof_blk_per_sync + CONSTANT c_bsn_init : NATURAL := 37; CONSTANT c_channel_init : NATURAL := 17; CONSTANT c_err_init : NATURAL := 13; @@ -142,7 +144,7 @@ BEGIN g_flow_control => g_flow_control, -- always active, random or pulse flow control -- initializations g_sync_period => g_nof_blk_per_sync, - g_sync_offset => 0, + g_sync_offset => c_sync_offset, g_data_init => 0, g_bsn_init => TO_DP_BSN(c_bsn_init), g_err_init => c_err_init, @@ -204,7 +206,7 @@ BEGIN proc_common_wait_until_high(clk, enable); proc_common_wait_until_hi_lo(clk, out_sosi.sop); proc_common_wait_until_hi_lo(clk, out_sosi.sop); -- first two sop will have occured, so start verification for subsequent BSN - IF g_check_input_sync=TRUE THEN + IF g_check_input_sync=TRUE OR g_nof_pages_bsn>0 THEN proc_common_wait_until_hi_lo(clk, out_sosi.sync); -- if necessary also wait for first sync END IF; WHILE enable='1' LOOP @@ -240,13 +242,22 @@ BEGIN out_sosi_local.sop <= '0'; END IF; END PROCESS; - - -- only verify BSN at sync using out_sosi - proc_dp_verify_sync(1, c_bsn_init, clk, verify_bsn_en, out_sosi.sync, out_sosi.sync, out_sosi.bsn); - proc_dp_verify_data("BSN", c_input_bsn_no_wrap, c_input_bsn_gap, clk, verify_bsn_en, out_sosi.sync, out_sosi.bsn, prev_out_sosi.bsn); - -- verify BSN at all sop using out_sosi_local - proc_dp_verify_data("BSN", c_local_bsn_max, c_local_bsn_gap, clk, verify_bsn_en, out_sosi_local.sop, out_sosi_local.bsn, prev_out_sosi_local.bsn); + verify_sync_bsn : IF g_check_input_sync=TRUE OR g_nof_pages_bsn>0 GENERATE + -- verify BSN at sync when out_sosi should have same bsn as in_sosi + proc_dp_verify_sync(c_input_bsn_gap, c_sync_offset, clk, verify_bsn_en, out_sosi.sync, out_sosi.sync, out_sosi.bsn); + END GENERATE; + + verify_local_bsn : IF g_restore_global_bsn=FALSE GENERATE + -- verify BSN for sop at sync + proc_dp_verify_data("BSN", c_input_bsn_no_wrap, c_input_bsn_gap, clk, verify_bsn_en, out_sosi.sync, out_sosi.bsn, prev_out_sosi.bsn); + -- verify BSN for the other sop between sync using out_sosi_local + proc_dp_verify_data("BSN", c_local_bsn_max, c_local_bsn_gap, clk, verify_bsn_en, out_sosi_local.sop, out_sosi_local.bsn, prev_out_sosi_local.bsn); + END GENERATE; + verify_global_bsn : IF g_restore_global_bsn=TRUE GENERATE + -- verify BSN for all sop + proc_dp_verify_data("BSN", clk, verify_bsn_en, out_sosi.sop, out_sosi.bsn, prev_out_sosi.bsn); + END GENERATE; -- Verify intervals proc_dp_verify_sop_and_eop(clk, out_sosi.valid, out_sosi.sop, out_sosi.eop, hold_sop); @@ -263,7 +274,8 @@ BEGIN g_nof_data_per_block => g_nof_data_per_block, g_nof_blk_per_sync => g_nof_blk_per_sync, g_check_input_sync => g_check_input_sync, - g_nof_pages_bsn => g_nof_pages_bsn + g_nof_pages_bsn => g_nof_pages_bsn, + g_restore_global_bsn => g_restore_global_bsn ) PORT MAP ( rst => rst, diff --git a/libraries/base/dp/tb/vhdl/tb_tb_dp_block_gen_valid_arr.vhd b/libraries/base/dp/tb/vhdl/tb_tb_dp_block_gen_valid_arr.vhd index 36cd50a953..3abe0192fa 100644 --- a/libraries/base/dp/tb/vhdl/tb_tb_dp_block_gen_valid_arr.vhd +++ b/libraries/base/dp/tb/vhdl/tb_tb_dp_block_gen_valid_arr.vhd @@ -41,19 +41,25 @@ BEGIN -- g_nof_blk_per_sync : POSITIVE := 8; -- g_check_input_sync : BOOLEAN := FALSE; -- g_nof_pages_bsn : NATURAL := 0; + -- g_restore_global_bsn : BOOLEAN := FALSE; -- g_enable : t_dp_flow_control_enum := e_active; -- always e_active or e_pulse block generator enable -- g_flow_control : t_dp_flow_control_enum := e_active; -- always e_active, e_random or e_pulse flow control for input valid -- g_nof_repeat : NATURAL := 200 - u_input_bsn : ENTITY work.tb_dp_block_gen_valid_arr GENERIC MAP (1, 11, 8, FALSE, 0, e_active, e_active, 100); - u_input_bsn_check_sync : ENTITY work.tb_dp_block_gen_valid_arr GENERIC MAP (1, 11, 9, TRUE, 0, e_active, e_active, 100); - u_buffer_input_bsn : ENTITY work.tb_dp_block_gen_valid_arr GENERIC MAP (1, 11, 5, FALSE, 1, e_active, e_active, 100); - - u_en_input_bsn : ENTITY work.tb_dp_block_gen_valid_arr GENERIC MAP (1, 11, 8, FALSE, 0, e_pulse, e_active, 500); - u_en_input_bsn_check_sync : ENTITY work.tb_dp_block_gen_valid_arr GENERIC MAP (1, 11, 9, TRUE, 0, e_pulse, e_active, 500); - u_en_buffer_input_bsn : ENTITY work.tb_dp_block_gen_valid_arr GENERIC MAP (1, 11, 5, FALSE, 1, e_pulse, e_active, 500); - - u_en_rnd_input_bsn : ENTITY work.tb_dp_block_gen_valid_arr GENERIC MAP (1, 11, 8, FALSE, 0, e_pulse, e_random, 500); - u_en_rnd_input_bsn_check_sync : ENTITY work.tb_dp_block_gen_valid_arr GENERIC MAP (1, 11, 9, TRUE, 0, e_pulse, e_random, 500); - u_en_rnd_buffer_input_bsn : ENTITY work.tb_dp_block_gen_valid_arr GENERIC MAP (1, 11, 5, FALSE, 1, e_pulse, e_random, 500); + u_input_bsn : ENTITY work.tb_dp_block_gen_valid_arr GENERIC MAP (1, 11, 8, FALSE, 0, FALSE, e_active, e_active, 100); + u_input_bsn_check_sync : ENTITY work.tb_dp_block_gen_valid_arr GENERIC MAP (1, 11, 9, TRUE, 0, FALSE, e_active, e_active, 100); + u_buffer_input_bsn : ENTITY work.tb_dp_block_gen_valid_arr GENERIC MAP (1, 11, 5, FALSE, 1, FALSE, e_active, e_active, 100); + + u_en_input_bsn : ENTITY work.tb_dp_block_gen_valid_arr GENERIC MAP (1, 11, 8, FALSE, 0, FALSE, e_pulse, e_active, 500); + u_en_input_bsn_check_sync : ENTITY work.tb_dp_block_gen_valid_arr GENERIC MAP (1, 11, 9, TRUE, 0, FALSE, e_pulse, e_active, 500); + u_en_buffer_input_bsn : ENTITY work.tb_dp_block_gen_valid_arr GENERIC MAP (1, 11, 5, FALSE, 1, FALSE, e_pulse, e_active, 500); + + u_en_rnd_input_bsn : ENTITY work.tb_dp_block_gen_valid_arr GENERIC MAP (1, 11, 8, FALSE, 0, FALSE, e_pulse, e_random, 500); + u_en_rnd_input_bsn_check_sync : ENTITY work.tb_dp_block_gen_valid_arr GENERIC MAP (1, 11, 9, TRUE, 0, FALSE, e_pulse, e_random, 500); + u_en_rnd_buffer_input_bsn : ENTITY work.tb_dp_block_gen_valid_arr GENERIC MAP (1, 11, 5, FALSE, 1, FALSE, e_pulse, e_random, 500); + + u_global_input_bsn : ENTITY work.tb_dp_block_gen_valid_arr GENERIC MAP (1, 11, 8, FALSE, 0, TRUE, e_active, e_active, 100); + u_global_input_bsn_check_sync : ENTITY work.tb_dp_block_gen_valid_arr GENERIC MAP (1, 11, 9, TRUE, 0, TRUE, e_active, e_active, 100); + u_buffer_global_input_bsn : ENTITY work.tb_dp_block_gen_valid_arr GENERIC MAP (1, 11, 5, FALSE, 1, TRUE, e_active, e_active, 100); + END tb; -- GitLab