1 |
2 |
danv |
-------------------------------------------------------------------------------
|
2 |
|
|
--
|
3 |
|
|
-- Copyright (C) 2011
|
4 |
|
|
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
|
5 |
|
|
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
|
6 |
|
|
--
|
7 |
|
|
-- This program is free software: you can redistribute it and/or modify
|
8 |
|
|
-- it under the terms of the GNU General Public License as published by
|
9 |
|
|
-- the Free Software Foundation, either version 3 of the License, or
|
10 |
|
|
-- (at your option) any later version.
|
11 |
|
|
--
|
12 |
|
|
-- This program is distributed in the hope that it will be useful,
|
13 |
|
|
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 |
|
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15 |
|
|
-- GNU General Public License for more details.
|
16 |
|
|
--
|
17 |
|
|
-- You should have received a copy of the GNU General Public License
|
18 |
|
|
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19 |
|
|
--
|
20 |
|
|
-------------------------------------------------------------------------------
|
21 |
|
|
|
22 |
|
|
-- Purpose : Generate the sosi control for a block of data based on the
|
23 |
|
|
-- input valid
|
24 |
|
|
-- Description:
|
25 |
|
|
-- All input streams in the snk_in_arr must have the same sosi ctrl and info
|
26 |
|
|
-- fields, such that the valid from snk_in_arr(0) is sufficient. Only the
|
27 |
|
|
-- data, re, im in the snk_in_arr() differs. Therefore default connect snk_in
|
28 |
|
|
-- = snk_in_arr(0).
|
29 |
|
|
--
|
30 |
|
|
-- When enabled (enable='1') then a block of g_nof_data_per_block words is
|
31 |
|
|
-- output via src_out_arr under flow control by the input valid.
|
32 |
|
|
--
|
33 |
|
|
-- The input sync, sop and eop are ignored. For the output the sync, sop and
|
34 |
|
|
-- eop are generated by counting the input valid and using
|
35 |
|
|
-- g_nof_data_per_block for the output sop and eop, and using
|
36 |
|
|
-- g_nof_blk_per_sync for the output sync.
|
37 |
|
|
--
|
38 |
|
|
-- The first active input valid starts the dp_block_gen_valid_arr. The first
|
39 |
|
|
-- output block will have an output sync and every g_nof_blk_per_sync there
|
40 |
|
|
-- is another output sync. Each output block is marked by output sop and
|
41 |
|
|
-- output eop. The output sop also marks the output BSN. The output BSN is
|
42 |
|
|
-- generated such that it increments for every block and that it restarts at
|
43 |
|
|
-- 0 at every output sync.
|
44 |
|
|
--
|
45 |
|
|
-- Typically the size of g_nof_blk_per_sync*g_nof_data_per_block should match
|
46 |
|
|
-- the number of input valids in an input sync interval.
|
47 |
|
|
--
|
48 |
|
|
-- The local BSN restarts at 0 for every new output sync interval, but instead
|
49 |
|
|
-- of BSN = 0 the input BSN will be inserted at the first block in a new
|
50 |
|
|
-- output sync interval. If the first output BSN should remain 0 then simply
|
51 |
|
|
-- keep snk_in.bsn = 0.
|
52 |
|
|
--
|
53 |
|
|
-- g_nof_pages_bsn:
|
54 |
|
|
-- The input BSN is not available in snk_in_arr(0) if the upstream component
|
55 |
|
|
-- does not pass the BSN on. In that case the snk_in.sync and snk_in.bsn can
|
56 |
|
|
-- be connected to some further upstream interface that does have the proper
|
57 |
|
|
-- BSN. The input BSN is then buffered to align it with the local sync that is
|
58 |
|
|
-- recreated for the output. This buffer is set via g_nof_pages_bsn. Typically
|
59 |
|
|
-- g_nof_pages_bsn = 1 is sufficient to align the BSN along some DSP,
|
60 |
|
|
-- components, because the latency in number of blocks of most DSP functions
|
61 |
|
|
-- is much less than a sync interval. For a corner turn that operates per sync
|
62 |
|
|
-- interval choosing g_nof_pages_bsn = 2 seems appropriate.
|
63 |
|
|
--
|
64 |
|
|
-- g_check_input_sync:
|
65 |
|
|
-- When g_check_input_sync=FALSE then the input sync is ignored and the first
|
66 |
|
|
-- input valid that occurs after when enable is active will start the local
|
67 |
|
|
-- sync. When g_check_input_sync=TRUE then the block output for a new sync
|
68 |
|
|
-- interval is only started if the input valid also coincides with a input
|
69 |
|
|
-- sync. Until then all input valid are ignored and there is no output then.
|
70 |
|
|
--
|
71 |
|
|
-- Usage:
|
72 |
|
|
-- * Example 1: Use snk_in.valid to recreate sync, sop, eop, bsn for a DP
|
73 |
|
|
-- function that only passes on the valid.
|
74 |
|
|
--
|
75 |
|
|
-- - g_check_input_sync = False
|
76 |
|
|
-- - g_nof_pages_bsn = 0
|
77 |
|
|
--
|
78 |
|
|
-- |------|
|
79 |
|
|
-- snk_in_arr() ----*--------->| |----> src_out_arr
|
80 |
|
|
-- | | dp |
|
81 |
|
|
-- (0)| | block|
|
82 |
|
|
-- | snk_in | gen |
|
83 |
|
|
-- \--------->| arr |
|
84 |
|
|
-- |------|
|
85 |
|
|
--
|
86 |
|
|
-- * Example 2: Use snk_in.valid to recreate sop, eop, bsn and check that the
|
87 |
|
|
-- local sync is aligned with the snk_in.sync. If the snk_in.sync
|
88 |
|
|
-- does not coincide with the local sync, then stop the output of
|
89 |
|
|
-- blocks until the snk_in.sync occurs again.
|
90 |
|
|
--
|
91 |
|
|
-- - g_check_input_sync = True
|
92 |
|
|
-- - g_nof_pages_bsn = 0
|
93 |
|
|
--
|
94 |
|
|
-- |------|
|
95 |
|
|
-- snk_in_arr() ----*--------->| |----> src_out_arr
|
96 |
|
|
-- | | dp |
|
97 |
|
|
-- (0)| | block|
|
98 |
|
|
-- | snk_in | gen |
|
99 |
|
|
-- \--------->| arr |
|
100 |
|
|
-- |------|
|
101 |
|
|
--
|
102 |
|
|
-- * Example 3: Use snk_in.valid to recreate sop, eop, bsn for a DP
|
103 |
|
|
-- function that only passes on the valid. However use snk_in.sync
|
104 |
|
|
-- to delay the snk_in.bsn by g_nof_pages_bsn to account for the
|
105 |
|
|
-- block latency of the upstream DP components that did not pass
|
106 |
|
|
-- on the snk_in.bsn.
|
107 |
|
|
--
|
108 |
|
|
-- - g_check_input_sync = False
|
109 |
|
|
-- - g_nof_pages_bsn >= 1
|
110 |
|
|
--
|
111 |
|
|
-- |-----| snk_in_arr() |------|
|
112 |
|
|
-- -----*-->| |-------*--------->| |----> src_out_arr
|
113 |
|
|
-- | | DP | | | dp |
|
114 |
|
|
-- | | | (0)| | block|
|
115 |
|
|
-- | | | | snk_in | gen |
|
116 |
|
|
-- | | | \--*------>| arr |
|
117 |
|
|
-- sync| |-----| ^ |------|
|
118 |
|
|
-- bsn | |
|
119 |
|
|
-- \--------------------/
|
120 |
|
|
--
|
121 |
|
|
-- Remarks:
|
122 |
|
|
-- . This dp_block_gen_valid_arr relates to:
|
123 |
|
|
-- - dp_bsn_source.vhd
|
124 |
|
|
-- - dp_block_gen.vhd when snk_in.valid is used for flow control (so when
|
125 |
|
|
-- g_use_src_in=FALSE). This is why thsi dp_block_gen_valid_arr is called
|
126 |
|
|
-- with '_valid' in its name.
|
127 |
|
|
-- - dp_counter.vhd
|
128 |
|
|
-- - dp_paged_sop_eop_reg.vhd
|
129 |
|
|
-- - dp_fifo_info.vhd
|
130 |
|
|
-- - dp_sync_checker.vhd
|
131 |
|
|
-- . This dp_block_gen_valid_arr has no siso flow control, although enable
|
132 |
|
|
-- could be used as siso.xon.
|
133 |
|
|
-- . The channel, empty and err fields are passed on to the output. Typically
|
134 |
|
|
-- these fields are not used with DSP data. However this scheme still
|
135 |
|
|
-- allows setting these fields to a fixed value via snk_in.
|
136 |
|
|
-- . Using g_check_input_sync=True is similar to using a dp_sync_checker in
|
137 |
|
|
-- front of this dp_block_gen_valid_arr. However the advantage of
|
138 |
|
|
-- dp_sync_checker is that it provides monitoring and control via MM.
|
139 |
|
|
|
140 |
|
|
LIBRARY IEEE, common_pkg_lib, dp_pkg_lib, common_components_lib;
|
141 |
|
|
USE IEEE.STD_LOGIC_1164.ALL;
|
142 |
|
|
USE IEEE.NUMERIC_STD.ALL;
|
143 |
|
|
USE common_pkg_lib.common_pkg.ALL;
|
144 |
|
|
USE dp_pkg_lib.dp_stream_pkg.ALL;
|
145 |
|
|
|
146 |
|
|
ENTITY dp_block_gen_valid_arr IS
|
147 |
|
|
GENERIC (
|
148 |
|
|
g_nof_streams : POSITIVE := 1;
|
149 |
|
|
g_nof_data_per_block : POSITIVE := 1;
|
150 |
|
|
g_nof_blk_per_sync : POSITIVE := 8;
|
151 |
|
|
g_check_input_sync : BOOLEAN := FALSE;
|
152 |
|
|
g_nof_pages_bsn : NATURAL := 0;
|
153 |
|
|
g_restore_global_bsn : BOOLEAN := FALSE
|
154 |
|
|
);
|
155 |
|
|
PORT (
|
156 |
|
|
rst : IN STD_LOGIC;
|
157 |
|
|
clk : IN STD_LOGIC;
|
158 |
|
|
-- Streaming sink
|
159 |
|
|
snk_in : IN t_dp_sosi; -- = snk_in_arr(0)
|
160 |
|
|
snk_in_arr : IN t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
|
161 |
|
|
-- Streaming source
|
162 |
|
|
src_out_arr : OUT t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
|
163 |
|
|
-- Control
|
164 |
|
|
enable : IN STD_LOGIC := '1' -- can connect via MM or could also connect to a src_in.xon
|
165 |
|
|
);
|
166 |
|
|
END dp_block_gen_valid_arr;
|
167 |
|
|
|
168 |
|
|
|
169 |
|
|
ARCHITECTURE rtl OF dp_block_gen_valid_arr IS
|
170 |
|
|
|
171 |
|
|
-- Check consistancy of the parameters, the function return value is void, because always true or abort due to failure
|
172 |
|
|
FUNCTION parameter_asserts(g_check_input_sync : BOOLEAN; g_nof_pages_bsn : NATURAL) return BOOLEAN IS
|
173 |
|
|
BEGIN
|
174 |
|
|
IF g_check_input_sync=TRUE THEN
|
175 |
|
|
ASSERT g_nof_pages_bsn=0 REPORT "When g_check_input_sync=TRUE then g_nof_pages_bsn must be 0." SEVERITY FAILURE;
|
176 |
|
|
-- because snk_in.sync and snk_in.bsn are then already aligned with the first snk_in.valid
|
177 |
|
|
END IF;
|
178 |
|
|
IF g_nof_pages_bsn>0 THEN
|
179 |
|
|
ASSERT g_check_input_sync=FALSE REPORT "When g_nof_pages_bsn>0 then g_check_input_sync must be FALSE." SEVERITY FAILURE;
|
180 |
|
|
-- because snk_in.sync and snk_in.bsn are then NOT aligned with the first snk_in.valid
|
181 |
|
|
END IF;
|
182 |
|
|
RETURN TRUE;
|
183 |
|
|
END parameter_asserts;
|
184 |
|
|
|
185 |
|
|
CONSTANT c_parameters_ok : BOOLEAN := parameter_asserts(g_check_input_sync, g_nof_pages_bsn);
|
186 |
|
|
|
187 |
|
|
TYPE t_state IS (s_sop, s_data, s_eop);
|
188 |
|
|
|
189 |
|
|
TYPE t_reg IS RECORD -- local registers
|
190 |
|
|
state : t_state;
|
191 |
|
|
data_cnt : NATURAL RANGE 0 TO g_nof_data_per_block;
|
192 |
|
|
blk_cnt : NATURAL RANGE 0 TO g_nof_blk_per_sync;
|
193 |
|
|
reg_sosi : t_dp_sosi;
|
194 |
|
|
END RECORD;
|
195 |
|
|
|
196 |
|
|
CONSTANT c_reg_rst : t_reg := (s_sop, 0, 0, c_dp_sosi_rst);
|
197 |
|
|
|
198 |
|
|
SIGNAL in_sosi : t_dp_sosi;
|
199 |
|
|
SIGNAL in_sync_wr_en : STD_LOGIC_VECTOR(g_nof_pages_bsn-1 DOWNTO 0);
|
200 |
|
|
SIGNAL in_bsn_buffer : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0);
|
201 |
|
|
|
202 |
|
|
SIGNAL out_sosi : t_dp_sosi;
|
203 |
|
|
SIGNAL nxt_src_out_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
|
204 |
|
|
|
205 |
|
|
-- Define the local registers in t_reg record
|
206 |
|
|
SIGNAL r : t_reg;
|
207 |
|
|
SIGNAL nxt_r : t_reg;
|
208 |
|
|
|
209 |
|
|
BEGIN
|
210 |
|
|
|
211 |
|
|
p_clk : PROCESS(rst, clk)
|
212 |
|
|
BEGIN
|
213 |
|
|
IF rst='1' THEN
|
214 |
|
|
r <= c_reg_rst;
|
215 |
|
|
src_out_arr <= (OTHERS=>c_dp_sosi_rst);
|
216 |
|
|
ELSIF rising_edge(clk) THEN
|
217 |
|
|
r <= nxt_r;
|
218 |
|
|
src_out_arr <= nxt_src_out_arr;
|
219 |
|
|
END IF;
|
220 |
|
|
END PROCESS;
|
221 |
|
|
|
222 |
|
|
no_bsn_buffer : IF g_nof_pages_bsn=0 GENERATE
|
223 |
|
|
in_sosi <= snk_in;
|
224 |
|
|
END GENERATE;
|
225 |
|
|
|
226 |
|
|
gen_bsn_buffer : IF g_nof_pages_bsn>0 GENERATE
|
227 |
|
|
-- Buffer input BSN at each input sync
|
228 |
|
|
in_sync_wr_en <= (OTHERS=>snk_in.sync);
|
229 |
|
|
|
230 |
|
|
u_paged_bsn : ENTITY common_components_lib.common_paged_reg
|
231 |
|
|
GENERIC MAP (
|
232 |
|
|
g_data_w => c_dp_stream_bsn_w,
|
233 |
|
|
g_nof_pages => g_nof_pages_bsn
|
234 |
|
|
)
|
235 |
|
|
PORT MAP (
|
236 |
|
|
rst => rst,
|
237 |
|
|
clk => clk,
|
238 |
|
|
wr_en => in_sync_wr_en,
|
239 |
|
|
wr_dat => snk_in.bsn,
|
240 |
|
|
out_dat => in_bsn_buffer
|
241 |
|
|
);
|
242 |
|
|
|
243 |
|
|
p_snk_in : PROCESS(snk_in, in_bsn_buffer)
|
244 |
|
|
BEGIN
|
245 |
|
|
in_sosi <= snk_in;
|
246 |
|
|
in_sosi.sync <= '0';
|
247 |
|
|
in_sosi.bsn <= in_bsn_buffer;
|
248 |
|
|
END PROCESS;
|
249 |
|
|
END GENERATE;
|
250 |
|
|
|
251 |
|
|
-- Determine the output info and output ctrl using snk_in and r.reg_sosi
|
252 |
|
|
p_state : PROCESS(r, enable, in_sosi, snk_in)
|
253 |
|
|
BEGIN
|
254 |
|
|
nxt_r <= r;
|
255 |
|
|
|
256 |
|
|
-- default output in_sosi, hold output bsn and set the output ctrl to '0'
|
257 |
|
|
nxt_r.reg_sosi <= in_sosi;
|
258 |
|
|
nxt_r.reg_sosi.bsn <= r.reg_sosi.bsn;
|
259 |
|
|
nxt_r.reg_sosi.valid <= '0';
|
260 |
|
|
nxt_r.reg_sosi.sop <= '0';
|
261 |
|
|
nxt_r.reg_sosi.eop <= '0';
|
262 |
|
|
nxt_r.reg_sosi.sync <= '0';
|
263 |
|
|
|
264 |
|
|
CASE r.state IS
|
265 |
|
|
WHEN s_sop =>
|
266 |
|
|
nxt_r.data_cnt <= 0; -- For clarity init data count to 0 (because it will become 1 anyway at sop)
|
267 |
|
|
IF enable='0' THEN -- Check enable in state s_sop to ensure that disable cannot happen during a block
|
268 |
|
|
nxt_r.blk_cnt <= 0; -- If disabled then reset block generator and remain in this state
|
269 |
|
|
ELSE -- Enabled block generator
|
270 |
|
|
IF snk_in.valid='1' THEN -- Once enabled the complete block will be output dependent on the input valid
|
271 |
|
|
-- maintain blk_cnt for output sync interval, the blk_cnt is the local bsn that wraps at every sync
|
272 |
|
|
IF r.blk_cnt>=g_nof_blk_per_sync-1 THEN
|
273 |
|
|
nxt_r.blk_cnt <= 0;
|
274 |
|
|
ELSE
|
275 |
|
|
nxt_r.blk_cnt <= r.blk_cnt+1;
|
276 |
|
|
END IF;
|
277 |
|
|
|
278 |
|
|
-- create local sync and pass on input bsn at local sync
|
279 |
|
|
IF r.blk_cnt=0 THEN -- output sync starts at first input valid
|
280 |
|
|
nxt_r.reg_sosi.sync <= '1'; -- output sync for this block
|
281 |
|
|
nxt_r.reg_sosi.bsn <= in_sosi.bsn; -- output input bsn at sync
|
282 |
|
|
ELSE
|
283 |
|
|
nxt_r.reg_sosi.bsn <= TO_DP_BSN(r.blk_cnt); -- output local bsn for the subsequent blocks
|
284 |
|
|
END IF;
|
285 |
|
|
|
286 |
|
|
nxt_r.reg_sosi.valid <= '1';
|
287 |
|
|
nxt_r.reg_sosi.sop <= '1';
|
288 |
|
|
|
289 |
|
|
IF g_nof_data_per_block=1 THEN
|
290 |
|
|
nxt_r.reg_sosi.eop <= '1'; -- single word block
|
291 |
|
|
ELSE
|
292 |
|
|
nxt_r.data_cnt <= 1; -- start of multi word block
|
293 |
|
|
nxt_r.state <= s_data;
|
294 |
|
|
END IF;
|
295 |
|
|
|
296 |
|
|
-- if enabled then check input sync and stop the new block output if the local sync does not coincide with the input sync
|
297 |
|
|
IF g_check_input_sync=TRUE THEN
|
298 |
|
|
IF r.blk_cnt=0 THEN
|
299 |
|
|
IF snk_in.sync='0' THEN
|
300 |
|
|
nxt_r.reg_sosi.valid <= '0'; -- undo all ctrl preparations for the new block
|
301 |
|
|
nxt_r.reg_sosi.sop <= '0';
|
302 |
|
|
nxt_r.reg_sosi.eop <= '0';
|
303 |
|
|
nxt_r.reg_sosi.sync <= '0';
|
304 |
|
|
nxt_r.blk_cnt <= 0; -- restart blk_cnt
|
305 |
|
|
nxt_r.state <= s_sop; -- remain in this state and wait for snk_in.sync
|
306 |
|
|
END IF;
|
307 |
|
|
END IF;
|
308 |
|
|
END IF;
|
309 |
|
|
END IF;
|
310 |
|
|
END IF;
|
311 |
|
|
WHEN s_data =>
|
312 |
|
|
IF snk_in.valid='1' THEN
|
313 |
|
|
nxt_r.data_cnt <= r.data_cnt+1;
|
314 |
|
|
nxt_r.reg_sosi.valid <= '1';
|
315 |
|
|
IF r.data_cnt=g_nof_data_per_block-2 THEN
|
316 |
|
|
nxt_r.state <= s_eop;
|
317 |
|
|
END IF;
|
318 |
|
|
END IF;
|
319 |
|
|
WHEN OTHERS => -- s_eop
|
320 |
|
|
IF snk_in.valid='1' THEN
|
321 |
|
|
nxt_r.reg_sosi.valid <= '1';
|
322 |
|
|
nxt_r.reg_sosi.eop <= '1';
|
323 |
|
|
nxt_r.state <= s_sop;
|
324 |
|
|
END IF;
|
325 |
|
|
END CASE;
|
326 |
|
|
END PROCESS;
|
327 |
|
|
|
328 |
|
|
-- Use local BSN that counts from 0 during sync interval, or restore global BSN between syncs
|
329 |
|
|
use_local_bsn : IF g_restore_global_bsn=FALSE GENERATE
|
330 |
|
|
out_sosi <= nxt_r.reg_sosi;
|
331 |
|
|
END GENERATE;
|
332 |
|
|
|
333 |
|
|
use_global_bsn : IF g_restore_global_bsn=TRUE GENERATE
|
334 |
|
|
u_dp_bsn_restore_global : ENTITY work.dp_bsn_restore_global
|
335 |
|
|
GENERIC MAP (
|
336 |
|
|
g_bsn_w => c_dp_stream_bsn_w,
|
337 |
|
|
g_pipeline => 0 -- pipeline registering is done via nxt_src_out_arr
|
338 |
|
|
)
|
339 |
|
|
PORT MAP (
|
340 |
|
|
rst => rst,
|
341 |
|
|
clk => clk,
|
342 |
|
|
-- ST sink
|
343 |
|
|
snk_in => nxt_r.reg_sosi,
|
344 |
|
|
-- ST source
|
345 |
|
|
src_out => out_sosi
|
346 |
|
|
);
|
347 |
|
|
END GENERATE;
|
348 |
|
|
|
349 |
|
|
-- Combine input data with the same out_put info and output ctrl for all streams
|
350 |
|
|
nxt_src_out_arr <= func_dp_stream_arr_combine_data_info_ctrl(snk_in_arr, out_sosi, out_sosi);
|
351 |
|
|
|
352 |
|
|
END rtl;
|