diff --git a/libraries/base/dp/src/vhdl/dp_bsn_sync_scheduler.vhd b/libraries/base/dp/src/vhdl/dp_bsn_sync_scheduler.vhd index 64242905331882b1fa4f1aa503c986be8acbe48d..9c888558625dbd66a51de1eb75c8cb7ca028d70b 100644 --- a/libraries/base/dp/src/vhdl/dp_bsn_sync_scheduler.vhd +++ b/libraries/base/dp/src/vhdl/dp_bsn_sync_scheduler.vhd @@ -1,24 +1,21 @@ -------------------------------------------------------------------------------- --- --- Copyright (C) 2012 +-- -------------------------------------------------------------------------- +-- Copyright 2021 -- 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. +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at -- --- 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. +-- http://www.apache.org/licenses/LICENSE-2.0 -- --- You should have received a copy of the GNU General Public License --- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- -------------------------------------------------------------------------- -- -------------------------------------------------------------------------------- - -- Author: Eric Kooistra, 30 July 2021 -- Purpose : -- Create programmable sync interval for input stream. @@ -43,26 +40,39 @@ -- output is disable after an in_sosi.eop when ctrl_enable = '0'. If the -- output is diabled, then the sosai control fields are forced to '0', the -- other sosi fields of the in_sosi are passed on to the out_sosi. --- * mon_input_current_bsn: --- The user can read mon_input_current_bsn to determine a suitable +-- * mon_current_input_bsn: +-- The user can read mon_current_input_bsn to determine a suitable -- ctrl_start_bsn in the future. -- * mon_input_bsn_at_sync: --- The user can read mon_input_current_bsn to determine a suitable +-- The user can read mon_current_input_bsn to determine a suitable -- ctrl_start_bsn in the future to create a output sync interval that is -- aligned with the in_sosi.sync. -- * mon_output_enable: -- The user can read mon_output_enable to check whether the output is indeed --- enabled or not. +-- enabled or not (mon_output_enable = out_enable). -- * mon_output_sync_bsn: -- The sync interval calculation is robust to lost in_sosi blocks. As soon -- as it receives a new in_sosi block it will try to determine the next -- output_sync_bsn, even if blocks were lost for multiple output sync --- intervals. If mon_output_sync_bsn - mon_input_current_bsn < 0 then the +-- intervals. If mon_output_sync_bsn - mon_current_input_bsn < 0 then the -- output sync interval calculation should catch up after some in_sosi --- blocks. If mon_output_sync_bsn - mon_input_current_bsn > nof_blk then +-- blocks. If mon_output_sync_bsn - mon_current_input_bsn > nof_blk then -- something went wrong and then it may be necessary to recover using --- ctrl_enable. If mon_output_sync_bsn - mon_input_current_bsn < nof_blk and +-- ctrl_enable. If mon_output_sync_bsn - mon_current_input_bsn < nof_blk and -- > 0 then that yields the number of blocks until the next output sync. +-- * out_start: +-- Pulse at out_sosi.sync with out_sosi.bsn = ctrl_start_bsn. The first +-- out_sosi.sync interval will have nof_blk_max blocks. +-- * out_enable: +-- Goes high at first out_sosi.sync. In case of a restart when ctrl_enable +-- was already '1', then the out_enable will go low and high to ensure that +-- the restart out_sosi.sync interval will have nof_blk_max blocks. When +-- ctrl_enable goes low or in case of a restart then out_enable will go +-- low after an out_sosi.eop, to preserve complete out_sosi blocks. The +-- out_enable is monitored via mon_output_enable, so that the user can +-- check via MM whether an ctrl_enable access was applied. Typically the +-- out_enable OUT can be left OPEN in an VHDL application, and only used for +-- verification purposes in the test bench (tb). -- For example: -- . sample period Ts = 5 ns -- . g_block_size = 1024 samples @@ -114,7 +124,7 @@ ENTITY dp_bsn_sync_scheduler IS ctrl_enable_evt : IN STD_LOGIC; ctrl_interval_size : IN NATURAL; ctrl_start_bsn : IN STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0) := (OTHERS=>'0'); - mon_input_current_bsn : OUT STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0); + mon_current_input_bsn : OUT STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0); mon_input_bsn_at_sync : OUT STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0); mon_output_enable : OUT STD_LOGIC; mon_output_sync_bsn : OUT STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0); @@ -122,8 +132,8 @@ ENTITY dp_bsn_sync_scheduler IS -- Streaming in_sosi : IN t_dp_sosi; out_sosi : OUT t_dp_sosi; - out_start : OUT STD_LOGIC; - out_enable : OUT STD_LOGIC + out_start : OUT STD_LOGIC; -- pulse at out_sosi.sync at ctrl_start_bsn + out_enable : OUT STD_LOGIC -- for tb verification purposes ); END dp_bsn_sync_scheduler; @@ -163,7 +173,7 @@ BEGIN ASSERT g_block_size >= 2 REPORT "g_block_size must be >= 2." SEVERITY FAILURE; -- Capture monitoring info - mon_input_current_bsn <= in_sosi.bsn(g_bsn_w-1 DOWNTO 0) WHEN rising_edge(clk) AND in_sosi.sop = '1'; + mon_current_input_bsn <= in_sosi.bsn(g_bsn_w-1 DOWNTO 0) WHEN rising_edge(clk) AND in_sosi.sop = '1'; mon_input_bsn_at_sync <= in_sosi.bsn(g_bsn_w-1 DOWNTO 0) WHEN rising_edge(clk) AND in_sosi.sync = '1'; mon_output_enable <= r.output_enable; mon_output_sync_bsn <= r.output_sync_bsn; @@ -191,6 +201,8 @@ BEGIN END IF; -- Initialization: calculate number of blocks per output sync interval + -- . use r.enable_init instead of v.enable_init to easy timing closure and + -- because functionally it makes no difference. IF r.enable_init = '1' THEN -- Assume ctrl_start_bsn is scheduled more than nof_blk block clk cycles -- after the ctrl_enable_evt, so there is sufficient time until @@ -229,16 +241,21 @@ BEGIN -- Enable / disable control IF ctrl_enable = '0' THEN - v.enable := '0'; -- disable when ctrl_enable requests disable + -- Disable output when ctrl_enable requests disable. + v.enable := '0'; ELSIF ctrl_enable_evt = '1' THEN - v.enable := '0'; -- disable when ctrl_enable requests re-enable + -- ctrl_enable is on, so this is a re-enable. First disable output. + v.enable := '0'; ELSIF r.enable_init = '0' THEN - IF r.hold_eop = '1' THEN - -- enable after in_sosi.eop, so that r.enable has caused - -- v.output_enable = '0', to ensure that a re-enable starts - -- with the nof_blk_max sync interval. Otherwise - -- v.output_enable = '1' can cause that re-enable can restart - -- with the nof_blk_min sync interval + -- ctrl_enable is still on, so now enable the output. In case of an + -- enable, then the output was already disabled. In case of a re-enable, + -- then wait until the output got disabled. + -- Enabling the output from disabled state ensures that the output will + -- start or restart with nof_blk_max in the first sync interval. + -- Otherwise with re-enabling from enabled state, it is undefined + -- whether the first sync interval after the restart will have + -- nof_blk_min or nof_blk_max blocks. + IF r.output_enable = '0' THEN v.enable := '1'; END IF; END IF; @@ -252,7 +269,7 @@ BEGIN v.hold_eop := '1'; END IF; - IF r.enable = '1' THEN + IF v.enable = '1' THEN -- Output enable at in_sosi.sop start_bsn IF in_sosi.sop = '1' THEN IF UNSIGNED(in_sosi.bsn) = UNSIGNED(r.start_bsn) THEN @@ -304,7 +321,7 @@ BEGIN -- Assume output_sync_bsn is in future v.update_bsn := '0'; - -- else last r.input_bsn will be used to keep update_bsn active for + -- else: last r.input_bsn will be used to keep update_bsn active for -- more clk cycles to catch up for lost input blocks. END IF; @@ -313,11 +330,15 @@ BEGIN v.input_bsn := in_sosi.bsn(g_bsn_w-1 DOWNTO 0); END IF; - -- Catch up with output_sync_bsn in case of lost input blocks + -- Catch up with output_sync_bsn in case of lost input blocks. If many + -- input blocks were lost (e.g. > nof_blk_max), then catching up the + -- output_sync_bsn to the current input_bsn can cause that one or more + -- output_sync will not be made active, but that is acceptable in case + -- recovery from of lost input blocks. IF v.output_enable = '1' THEN IF UNSIGNED(r.input_bsn) > UNSIGNED(v.output_sync_bsn) THEN -- Missed one or more input blocks, fast forward to look for next - -- output_sync_bsn + -- output_sync_bsn in every clk cycle. v.update_bsn := '1'; END IF; END IF;