1 |
2 |
danv |
--------------------------------------------------------------------------------
|
2 |
|
|
--
|
3 |
5 |
danv |
-- Copyright 2020
|
4 |
2 |
danv |
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
|
5 |
|
|
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
|
6 |
5 |
danv |
--
|
7 |
|
|
-- Licensed under the Apache License, Version 2.0 (the "License");
|
8 |
|
|
-- you may not use this file except in compliance with the License.
|
9 |
|
|
-- You may obtain a copy of the License at
|
10 |
|
|
--
|
11 |
|
|
-- http://www.apache.org/licenses/LICENSE-2.0
|
12 |
|
|
--
|
13 |
|
|
-- Unless required by applicable law or agreed to in writing, software
|
14 |
|
|
-- distributed under the License is distributed on an "AS IS" BASIS,
|
15 |
|
|
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16 |
|
|
-- See the License for the specific language governing permissions and
|
17 |
|
|
-- limitations under the License.
|
18 |
2 |
danv |
--
|
19 |
|
|
--------------------------------------------------------------------------------
|
20 |
|
|
|
21 |
|
|
-- Purpose:
|
22 |
|
|
-- The dp_repack_data works both as packer and as unpacker.
|
23 |
|
|
--
|
24 |
|
|
-- Block diagram:
|
25 |
|
|
--
|
26 |
|
|
-- A) Functional
|
27 |
|
|
-- The drawing shows g_in_nof_words=4 and g_out_nof_words=2 as example:
|
28 |
|
|
--
|
29 |
|
|
-- dp_repack_in dp_repack_out
|
30 |
|
|
-- ___ ___
|
31 |
|
|
-- | | pack_sosi | |--> src_out
|
32 |
|
|
-- | 3 |--------------------->| 1 |
|
33 |
|
|
-- | | | |
|
34 |
|
|
-- | 2 | ^ | | ^
|
35 |
|
|
-- | | |valid | | |shift
|
36 |
|
|
-- | 1 | |flush | 0 | |
|
37 |
|
|
-- | | | | | |
|
38 |
|
|
-- | 0 | | |
|
39 |
|
|
-- snk_in -->|___| pack_siso |___|
|
40 |
|
|
-- snk_out.ready <-- <--------------------- <-- src_in.ready
|
41 |
|
|
-- snk_out.xon <------------------------------------- src_in.xon
|
42 |
|
|
--
|
43 |
|
|
--
|
44 |
|
|
-- B) Flow control
|
45 |
|
|
--
|
46 |
|
|
-- RL=1 RL=1 RL=1
|
47 |
|
|
-- . . .
|
48 |
|
|
-- . /-----------------------------------------\
|
49 |
|
|
-- . | . _____ . |
|
50 |
|
|
-- . | /------\ nxt_r | | r |
|
51 |
|
|
-- . \-->| |---*-------*----->|p_reg|-----*---> src_out
|
52 |
|
|
-- . | | | | |_____|
|
53 |
|
|
-- snk_in -------->|p_comb|<--|-------|--------------*-------- src_in
|
54 |
|
|
-- | | | | |
|
55 |
|
|
-- | | | v |
|
56 |
|
|
-- | | | /-------\ |
|
57 |
|
|
-- | | | |p_flow | |
|
58 |
|
|
-- \------/ | \-------/ |
|
59 |
|
|
-- | | |
|
60 |
|
|
-- nxt_r.hold_out.valid | | |
|
61 |
|
|
-- v | |
|
62 |
|
|
-- /| |r_snk_out |
|
63 |
|
|
-- |0|------/ |
|
64 |
|
|
-- snk_out <------------------| | |
|
65 |
|
|
-- |1|---------------------/
|
66 |
|
|
-- \|
|
67 |
|
|
--
|
68 |
|
|
-- Description:
|
69 |
|
|
-- The dp_repack_data repacks g_in_nof_words of width g_in_dat_w into
|
70 |
|
|
-- g_out_nof_words of width g_out_dat_w.
|
71 |
|
|
--
|
72 |
|
|
-- . g_in_bypass, g_out_bypass
|
73 |
|
|
-- The dp_repack_in and dp_repack_out can be bypassed to save logic and to
|
74 |
|
|
-- avoid the pipeline stage. Default both are FALSE, but they can be set
|
75 |
|
|
-- TRUE if:
|
76 |
|
|
--
|
77 |
|
|
-- . g_in_bypass =TRUE if g_in_nof_words=g_out_nof_words or g_in_nof_words=1
|
78 |
|
|
-- . g_out_bypass=TRUE if g_in_nof_words=g_out_nof_words or g_out_nof_words=1
|
79 |
|
|
--
|
80 |
|
|
-- Both the dp_repack_in and dp_repack_out stage do work correctly independent
|
81 |
|
|
-- of the g_*_bypass setting. When g_*_bypass=FALSE then they merely
|
82 |
|
|
-- add a transparant pipeline delay. It is important that they also work for
|
83 |
|
|
-- g_*_bypass=FALSE because that gives confidence that their implementation
|
84 |
|
|
-- structure is ok.
|
85 |
|
|
--
|
86 |
|
|
-- . g_in_nof_words and input block size
|
87 |
|
|
-- The input block size in words is indicated by snk_in.sop and snk_in.eop.
|
88 |
|
|
-- Each subsection of g_in_nof_words is packed into g_out_nof_words. The
|
89 |
|
|
-- input block size does not have to be a multiple of g_in_nof_words. When
|
90 |
|
|
-- the snk_in.eop occurs the last repack is initiated without need for input
|
91 |
|
|
-- data padding. If the block length is an integer multiple of
|
92 |
|
|
-- g_in_nof_words then the dp_repack_data introduces no gaps between blocks.
|
93 |
|
|
-- If the block length is a fractional multiple of g_in_nof_words then there
|
94 |
|
|
-- will be a gap after the block due to that the dp_repack_in needs to
|
95 |
|
|
-- shift up the last subsection for the 'missing' input words.
|
96 |
|
|
--
|
97 |
|
|
-- . g_in_dat_w*g_in_nof_words <, =, > g_in_dat_w*g_in_nof_words
|
98 |
|
|
-- . = : no subsection zero padding
|
99 |
|
|
-- . < : the subsections will be zero padded
|
100 |
|
|
-- . > : then the input must have sufficient zero padded bits per
|
101 |
|
|
-- subsection that can be stripped without data loss.
|
102 |
|
|
--
|
103 |
|
|
-- . Resolution of the empty field
|
104 |
|
|
-- The g_in_symbol_w is used to define the resolution of snk_in.empty and
|
105 |
|
|
-- the g_out_symbol_w is used to define the resolution of src_out.empty. If
|
106 |
|
|
-- they are 1 then the resolution is in number of bits, because the symbol
|
107 |
|
|
-- size is then 1 bit. Their value has no effect on the packed data it self,
|
108 |
|
|
-- only on the meaning of the empty field. Hence if the empty field is not
|
109 |
|
|
-- used, then the setting of g_in_symbol_w and g_out_symbol_w is dont care.
|
110 |
|
|
--
|
111 |
|
|
-- Remarks:
|
112 |
|
|
-- . Originally reused from LOFAR rad_repack.vhd and rad_repack(rtl).vhd. This
|
113 |
|
|
-- dp_repack_data still uses the shift in input register in and the shift out
|
114 |
|
|
-- output register, but no longer the intermediate buffer register.
|
115 |
|
|
-- Using shift in and shift out may ease timing closure because the routing
|
116 |
|
|
-- is more local compared to using a demultiplexer to put the input data in
|
117 |
|
|
-- the input register and a multiplexer to get the data directly from the
|
118 |
|
|
-- output register. For the demultiplexer / multiplexer it would be possible
|
119 |
|
|
-- to only use one internal register.
|
120 |
|
|
-- Using shift up is sufficient, the shift down option is not needed. With
|
121 |
|
|
-- shift up the data is input a [0] and output the high index.
|
122 |
|
|
-- Instead of requiring an snk_in.valid duty cycle this dp_repack_data uses
|
123 |
|
|
-- snk_out.ready flow control and can handle src_in.ready flow control.
|
124 |
|
|
--
|
125 |
|
|
-- . To pack ETH/IP/UDP header slv of 14 + 20 + 8 = 42 octets into 32 bit words
|
126 |
|
|
-- use:
|
127 |
|
|
-- u_dp_repack_data : ENTITY .dp_repack_data
|
128 |
|
|
-- GENERIC MAP (
|
129 |
|
|
-- g_in_bypass => TRUE,
|
130 |
|
|
-- g_in_dat_w => 8 * 42,
|
131 |
|
|
-- g_in_nof_words => 1,
|
132 |
|
|
-- g_in_symbol_w => 8,
|
133 |
|
|
-- g_out_bypass => FALSE,
|
134 |
|
|
-- g_out_dat_w => 32,
|
135 |
|
|
-- g_out_nof_words => 11,
|
136 |
|
|
-- g_out_symbol_w => 8
|
137 |
|
|
-- )
|
138 |
|
|
-- The src_out.empty will be 2, because:
|
139 |
|
|
-- (g_out_dat_w*g_out_nof_words-g_in_dat_w*g_in_nof_words)/g_out_symbol_w
|
140 |
|
|
-- = (32*11 - 42*8*1)/ 8 = 2 octet symbols
|
141 |
|
|
--
|
142 |
|
|
-- Design steps:
|
143 |
|
|
-- * In total the development took 5 days. On day 3 I was in distress because
|
144 |
|
|
-- I could not get it to work so I needed to rethink. After changing to the
|
145 |
|
|
-- new flow control scheme that uses nxt_r the design was gradually improved
|
146 |
|
|
-- by getting the dp_repack_data instances in tb_tb_dp_repack_data to work one
|
147 |
|
|
-- by one. First only for e_active stimuli and later also for e_random and
|
148 |
|
|
-- e_pulse. Initially about 80 % of the functionality was implemented but
|
149 |
|
|
-- and subsequently each feature was verified starting with the basic
|
150 |
|
|
-- features and then themore detailed features. This step by step approach
|
151 |
|
|
-- makes that the bugs appear one by one instead of all together. Without a
|
152 |
|
|
-- step by step approach the bugs are too big to solve.
|
153 |
|
|
-- . First cases with g_in_nof_words=1 and g_out_nof_words were made to work
|
154 |
|
|
-- for different g_pkt_len <, =, > g_in_nof_words.
|
155 |
|
|
-- . Then the empty functionality for g_pkt_len MOD g_in_nof_words /= 0 was
|
156 |
|
|
-- added.
|
157 |
|
|
-- . Tried g_out_dat_w=1 which makes dp_repack_data a serializer/deserializer.
|
158 |
|
|
-- . Then apply external flow control using c_dp_flow_control_enum_arr in
|
159 |
|
|
-- the tb_tb_dp_repack_data was verified resulting in small corrections.
|
160 |
|
|
-- . Then verified g_in_dat_w * g_in_nof_words > or < g_out_dat_w *
|
161 |
|
|
-- g_out_nof_words which require padding in the subsection. The > case
|
162 |
|
|
-- occurs for packing and the < case then occurs for unpacking.
|
163 |
|
|
-- . Added g_bypass to force using wires instead of a void dp_repack_in or
|
164 |
|
|
-- dp_repack_out stage.
|
165 |
|
|
-- . Verified g_in_symbol_w and g_out_symbol_w /= 1.
|
166 |
|
|
-- * The development used the tb_dp_repack_data testbench that does a pack and
|
167 |
|
|
-- an unpack to be able to verify the data. The c_no_unpack and
|
168 |
|
|
-- c_enable_repack_in and c_enable_repack_out parameters in the tb are
|
169 |
|
|
-- useful to be able to isolate a component for debugging.
|
170 |
|
|
|
171 |
|
|
LIBRARY IEEE, common_pkg_lib, dp_pkg_lib;
|
172 |
|
|
USE IEEE.std_logic_1164.ALL;
|
173 |
|
|
USE common_pkg_lib.common_pkg.ALL;
|
174 |
|
|
USE dp_pkg_lib.dp_stream_pkg.ALL;
|
175 |
|
|
|
176 |
|
|
ENTITY dp_repack_in IS
|
177 |
|
|
GENERIC (
|
178 |
|
|
g_bypass : BOOLEAN := FALSE;
|
179 |
|
|
g_in_dat_w : NATURAL;
|
180 |
|
|
g_in_nof_words : NATURAL;
|
181 |
|
|
g_in_symbol_w : NATURAL := 1 -- default 1 for snk_in.empty in nof bits, else use power of 2
|
182 |
|
|
);
|
183 |
|
|
PORT (
|
184 |
|
|
rst : IN STD_LOGIC;
|
185 |
|
|
clk : IN STD_LOGIC;
|
186 |
|
|
|
187 |
|
|
snk_out : OUT t_dp_siso;
|
188 |
|
|
snk_in : IN t_dp_sosi;
|
189 |
|
|
|
190 |
|
|
src_in : IN t_dp_siso;
|
191 |
|
|
src_out : OUT t_dp_sosi
|
192 |
|
|
);
|
193 |
|
|
END dp_repack_in;
|
194 |
|
|
|
195 |
|
|
|
196 |
|
|
ARCHITECTURE rtl OF dp_repack_in IS
|
197 |
|
|
|
198 |
|
|
CONSTANT c_in_buf_dat_w : NATURAL := g_in_dat_w * g_in_nof_words;
|
199 |
|
|
CONSTANT c_bit_cnt_max : NATURAL := c_in_buf_dat_w;
|
200 |
|
|
CONSTANT c_in_empty_lo : NATURAL := true_log2(g_in_symbol_w);
|
201 |
|
|
|
202 |
|
|
TYPE t_dat_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
|
203 |
|
|
|
204 |
|
|
TYPE t_reg IS RECORD
|
205 |
|
|
dat_arr : t_dat_arr(g_in_nof_words-1 DOWNTO 0); -- internally use dat_arr[] to represent v.src_out.data
|
206 |
|
|
src_out : t_dp_sosi; -- sosi output
|
207 |
|
|
hold_out : t_dp_sosi; -- hold snk_in.sync/sop/eop until end of section and then hold valid src_out until src_in.ready
|
208 |
|
|
flush : STD_LOGIC; -- shift when snk_in.valid or flush in case the last subsection has < g_in_nof_words
|
209 |
|
|
dat_bit_cnt : NATURAL RANGE 0 TO c_bit_cnt_max; -- actual nof bits in subsection
|
210 |
|
|
pack_bit_cnt : NATURAL RANGE 0 TO c_bit_cnt_max; -- count nof bits in subsection
|
211 |
|
|
END RECORD;
|
212 |
|
|
|
213 |
|
|
SIGNAL data_vec : STD_LOGIC_VECTOR(c_in_buf_dat_w-1 DOWNTO 0);
|
214 |
|
|
|
215 |
|
|
SIGNAL r_snk_out : t_dp_siso := c_dp_siso_rdy;
|
216 |
|
|
SIGNAL r : t_reg;
|
217 |
|
|
SIGNAL nxt_r : t_reg;
|
218 |
|
|
|
219 |
|
|
-- Debug signals
|
220 |
|
|
SIGNAL snk_in_data : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
|
221 |
|
|
SIGNAL i_src_out : t_dp_sosi;
|
222 |
|
|
SIGNAL src_out_data : STD_LOGIC_VECTOR(c_in_buf_dat_w-1 DOWNTO 0);
|
223 |
|
|
|
224 |
|
|
SIGNAL dbg_g_in_dat_w : NATURAL := g_in_dat_w;
|
225 |
|
|
SIGNAL dbg_in_nof_words : NATURAL := g_in_nof_words;
|
226 |
|
|
SIGNAL dbg_in_symbol_w : NATURAL := g_in_symbol_w;
|
227 |
|
|
SIGNAL dbc_in_buf_dat_w : NATURAL := c_in_buf_dat_w;
|
228 |
|
|
|
229 |
|
|
BEGIN
|
230 |
|
|
|
231 |
|
|
snk_in_data <= snk_in.data(g_in_dat_w-1 DOWNTO 0);
|
232 |
|
|
|
233 |
|
|
src_out <= i_src_out;
|
234 |
|
|
src_out_data <= i_src_out.data(c_in_buf_dat_w-1 DOWNTO 0);
|
235 |
|
|
|
236 |
|
|
gen_bypass : IF g_bypass=TRUE GENERATE
|
237 |
|
|
snk_out <= src_in;
|
238 |
|
|
i_src_out <= snk_in;
|
239 |
|
|
END GENERATE;
|
240 |
|
|
|
241 |
|
|
no_bypass : IF g_bypass=FALSE GENERATE
|
242 |
|
|
|
243 |
|
|
p_comb : PROCESS(rst, r, snk_in, data_vec, src_in)
|
244 |
|
|
VARIABLE v : t_reg;
|
245 |
|
|
BEGIN
|
246 |
|
|
------------------------------------------------------------------------
|
247 |
|
|
-- Default
|
248 |
|
|
v := r;
|
249 |
|
|
v.src_out.sync := '0';
|
250 |
|
|
v.src_out.valid := '0';
|
251 |
|
|
v.src_out.sop := '0';
|
252 |
|
|
v.src_out.eop := '0';
|
253 |
|
|
|
254 |
|
|
--------------------------------------------------------------------------
|
255 |
|
|
-- Function
|
256 |
|
|
IF r.hold_out.valid='0' THEN
|
257 |
|
|
|
258 |
|
|
-- Clear hold_out for new output valid (= new subsection)
|
259 |
|
|
IF r.src_out.valid='1' THEN
|
260 |
|
|
v.hold_out := c_dp_sosi_rst;
|
261 |
|
|
END IF;
|
262 |
|
|
|
263 |
|
|
-- Capture the snk_in block info that is valid at sop and eop
|
264 |
|
|
IF snk_in.sop='1' THEN
|
265 |
|
|
v.hold_out.sop := '1';
|
266 |
|
|
v.hold_out.sync := snk_in.sync;
|
267 |
|
|
v.src_out.bsn := snk_in.bsn;
|
268 |
|
|
v.src_out.channel := snk_in.channel;
|
269 |
|
|
END IF;
|
270 |
|
|
IF snk_in.eop='1' THEN
|
271 |
|
|
v.hold_out.eop := '1';
|
272 |
|
|
v.hold_out.empty := SHIFT_UVEC(snk_in.empty, -c_in_empty_lo); -- use snk_in.empty as offset for src_out.empty in nof bits
|
273 |
|
|
v.src_out.err := snk_in.err;
|
274 |
|
|
END IF;
|
275 |
|
|
|
276 |
|
|
-- Capture the data per subsection in a block
|
277 |
|
|
IF snk_in.valid='1' OR r.flush='1' THEN
|
278 |
|
|
-- shift in during block
|
279 |
|
|
v.dat_arr(g_in_nof_words-1 DOWNTO 1) := r.dat_arr(g_in_nof_words-2 DOWNTO 0); -- shift up from low to high and shift in at index 0
|
280 |
|
|
IF r.flush='1' THEN
|
281 |
|
|
v.dat_arr(0) := (OTHERS=>'0'); -- shift in data=0 for flush
|
282 |
|
|
ELSE
|
283 |
|
|
v.dat_arr(0) := snk_in.data(g_in_dat_w-1 DOWNTO 0); -- shift in valid data
|
284 |
|
|
END IF;
|
285 |
|
|
|
286 |
|
|
-- pack subsection
|
287 |
|
|
IF r.pack_bit_cnt<c_in_buf_dat_w-g_in_dat_w THEN
|
288 |
|
|
v.pack_bit_cnt := r.pack_bit_cnt + g_in_dat_w;
|
289 |
|
|
|
290 |
|
|
-- early end of pack subsection
|
291 |
|
|
IF snk_in.eop='1' THEN
|
292 |
|
|
v.flush := '1'; -- enable flush in case eop occurs before end of pack subsection
|
293 |
|
|
v.dat_bit_cnt := v.pack_bit_cnt; -- capture the current subsection pack_bit_cnt
|
294 |
|
|
END IF;
|
295 |
|
|
ELSE -- r.pack_bit_cnt=c_in_buf_dat_w-g_in_dat_w
|
296 |
|
|
-- default end of pack subsection
|
297 |
|
|
v.pack_bit_cnt := 0;
|
298 |
|
|
v.flush := '0';
|
299 |
|
|
IF r.flush='0' THEN
|
300 |
|
|
v.dat_bit_cnt := c_in_buf_dat_w; -- set default subsection pack_bit_cnt
|
301 |
|
|
END IF;
|
302 |
|
|
|
303 |
|
|
v.hold_out.valid := '1'; -- the function has new data to output
|
304 |
|
|
END IF;
|
305 |
|
|
END IF;
|
306 |
|
|
|
307 |
|
|
-- pass on the v.dat_arr as data vector
|
308 |
|
|
v.src_out.data := RESIZE_DP_DATA(data_vec);
|
309 |
|
|
|
310 |
|
|
-- pass on dat_bit_cnt via DP empty field
|
311 |
|
|
v.src_out.empty := INCR_UVEC(v.hold_out.empty, c_in_buf_dat_w - v.dat_bit_cnt);
|
312 |
|
|
|
313 |
|
|
-- output input stage into output stage when ready, else hold_out.valid to signal pending output
|
314 |
|
|
IF v.hold_out.valid='1' THEN
|
315 |
|
|
IF src_in.ready='1' THEN
|
316 |
|
|
v.src_out.valid := '1';
|
317 |
|
|
v.src_out.sync := v.hold_out.sync;
|
318 |
|
|
v.src_out.sop := v.hold_out.sop;
|
319 |
|
|
v.src_out.eop := v.hold_out.eop;
|
320 |
|
|
v.hold_out.valid := '0';
|
321 |
|
|
END IF;
|
322 |
|
|
END IF;
|
323 |
|
|
ELSE
|
324 |
|
|
-- pending output
|
325 |
|
|
IF src_in.ready='1' THEN
|
326 |
|
|
v.src_out.valid := '1';
|
327 |
|
|
v.src_out.sync := r.hold_out.sync;
|
328 |
|
|
v.src_out.sop := r.hold_out.sop;
|
329 |
|
|
v.src_out.eop := r.hold_out.eop;
|
330 |
|
|
v.hold_out.valid := '0';
|
331 |
|
|
END IF;
|
332 |
|
|
END IF;
|
333 |
|
|
|
334 |
|
|
------------------------------------------------------------------------
|
335 |
|
|
-- Reset and nxt_r
|
336 |
|
|
IF rst = '1' THEN
|
337 |
|
|
v.src_out := c_dp_sosi_rst;
|
338 |
|
|
v.hold_out := c_dp_sosi_rst;
|
339 |
|
|
v.flush := '0';
|
340 |
|
|
v.dat_bit_cnt := 0;
|
341 |
|
|
v.pack_bit_cnt := 0;
|
342 |
|
|
END IF;
|
343 |
|
|
|
344 |
|
|
nxt_r <= v;
|
345 |
|
|
END PROCESS;
|
346 |
|
|
|
347 |
|
|
--------------------------------------------------------------------------
|
348 |
|
|
-- p_reg
|
349 |
|
|
r <= nxt_r WHEN rising_edge(clk);
|
350 |
|
|
|
351 |
|
|
--------------------------------------------------------------------------
|
352 |
|
|
-- Wires
|
353 |
|
|
p_data_vec : PROCESS(nxt_r)
|
354 |
|
|
BEGIN
|
355 |
|
|
FOR I IN 0 TO g_in_nof_words-1 LOOP
|
356 |
|
|
data_vec((I+1)*g_in_dat_w-1 DOWNTO I*g_in_dat_w) <= nxt_r.dat_arr(I);
|
357 |
|
|
END LOOP;
|
358 |
|
|
END PROCESS;
|
359 |
|
|
|
360 |
|
|
--------------------------------------------------------------------------
|
361 |
|
|
-- Wired output
|
362 |
|
|
i_src_out <= r.src_out;
|
363 |
|
|
|
364 |
|
|
--------------------------------------------------------------------------
|
365 |
|
|
-- Flow control
|
366 |
|
|
|
367 |
|
|
-- local function flow control
|
368 |
|
|
p_flow : PROCESS(nxt_r)
|
369 |
|
|
BEGIN
|
370 |
|
|
r_snk_out <= c_dp_siso_rdy;
|
371 |
|
|
IF nxt_r.flush='1' THEN
|
372 |
|
|
r_snk_out.ready <= '0'; -- input shift in stage function is always ready except when flushing
|
373 |
|
|
END IF;
|
374 |
|
|
END PROCESS;
|
375 |
|
|
|
376 |
|
|
-- combined local and remote src_in flow control
|
377 |
|
|
snk_out.ready <= r_snk_out.ready WHEN nxt_r.hold_out.valid='0' ELSE src_in.ready; -- if there is pending output then the src_in ready determines the flow control
|
378 |
|
|
snk_out.xon <= src_in.xon; -- just pass on the xon/off frame flow control
|
379 |
|
|
|
380 |
|
|
END GENERATE;
|
381 |
|
|
|
382 |
|
|
END rtl;
|
383 |
|
|
|
384 |
|
|
|
385 |
|
|
|
386 |
|
|
LIBRARY IEEE, common_pkg_lib, dp_pkg_lib;
|
387 |
|
|
USE IEEE.std_logic_1164.ALL;
|
388 |
|
|
USE common_pkg_lib.common_pkg.ALL;
|
389 |
|
|
USE dp_pkg_lib.dp_stream_pkg.ALL;
|
390 |
|
|
|
391 |
|
|
ENTITY dp_repack_out IS
|
392 |
|
|
GENERIC (
|
393 |
|
|
g_bypass : BOOLEAN := FALSE;
|
394 |
|
|
g_in_buf_dat_w : NATURAL;
|
395 |
|
|
g_out_dat_w : NATURAL;
|
396 |
|
|
g_out_nof_words : NATURAL;
|
397 |
|
|
g_out_symbol_w : NATURAL := 1 -- default 1 for snk_in.empty in nof bits, else use power of 2
|
398 |
|
|
);
|
399 |
|
|
PORT (
|
400 |
|
|
rst : IN STD_LOGIC;
|
401 |
|
|
clk : IN STD_LOGIC;
|
402 |
|
|
|
403 |
|
|
snk_out : OUT t_dp_siso;
|
404 |
|
|
snk_in : IN t_dp_sosi;
|
405 |
|
|
|
406 |
|
|
src_in : IN t_dp_siso;
|
407 |
|
|
src_out : OUT t_dp_sosi
|
408 |
|
|
);
|
409 |
|
|
END dp_repack_out;
|
410 |
|
|
|
411 |
|
|
ARCHITECTURE rtl OF dp_repack_out IS
|
412 |
|
|
|
413 |
|
|
CONSTANT c_out_buf_dat_w : NATURAL := g_out_dat_w * g_out_nof_words;
|
414 |
|
|
CONSTANT c_out_buf_dat_lo : NATURAL := sel_a_b(c_out_buf_dat_w > g_in_buf_dat_w, c_out_buf_dat_w - g_in_buf_dat_w, 0); -- pack into subsection with 0 or more padding bits
|
415 |
|
|
CONSTANT c_snk_in_dat_lo : NATURAL := sel_a_b(c_out_buf_dat_w < g_in_buf_dat_w, g_in_buf_dat_w - c_out_buf_dat_w, 0); -- unpack from subsection that has 0 or more padding bits
|
416 |
|
|
CONSTANT c_bit_cnt_max : NATURAL := c_out_buf_dat_w;
|
417 |
|
|
CONSTANT c_out_empty_lo : NATURAL := true_log2(g_out_symbol_w);
|
418 |
|
|
|
419 |
|
|
TYPE t_dat_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
|
420 |
|
|
|
421 |
|
|
TYPE t_reg IS RECORD
|
422 |
|
|
dat_arr : t_dat_arr(g_out_nof_words-1 DOWNTO 0);
|
423 |
|
|
src_out : t_dp_sosi;
|
424 |
|
|
hold_out : t_dp_sosi; -- hold src_out valid and sync/sop/eop until src_in.ready
|
425 |
|
|
shift : STD_LOGIC; -- shift out the dat_arr
|
426 |
|
|
dat_bit_cnt : NATURAL RANGE 0 TO c_bit_cnt_max; -- actual nof bits in subsection
|
427 |
|
|
pack_bit_cnt : NATURAL RANGE 0 TO c_bit_cnt_max; -- count nof bits in subsection
|
428 |
|
|
empty_bit_cnt : NATURAL RANGE 0 TO c_bit_cnt_max; -- empty nof bits in subsection
|
429 |
|
|
eos : STD_LOGIC; -- end of subsection
|
430 |
|
|
END RECORD;
|
431 |
|
|
|
432 |
|
|
SIGNAL data_vec : STD_LOGIC_VECTOR(c_out_buf_dat_w-1 DOWNTO 0) := (OTHERS=>'0');
|
433 |
|
|
|
434 |
|
|
SIGNAL r_snk_out : t_dp_siso := c_dp_siso_rdy;
|
435 |
|
|
SIGNAL r : t_reg;
|
436 |
|
|
SIGNAL nxt_r : t_reg;
|
437 |
|
|
|
438 |
|
|
-- Debug signals
|
439 |
|
|
SIGNAL snk_in_data : STD_LOGIC_VECTOR(g_in_buf_dat_w-1 DOWNTO 0);
|
440 |
|
|
SIGNAL i_src_out : t_dp_sosi;
|
441 |
|
|
SIGNAL src_out_data : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
|
442 |
|
|
|
443 |
|
|
SIGNAL dbg_g_in_buf_dat_w : NATURAL := g_in_buf_dat_w;
|
444 |
|
|
SIGNAL dbg_g_out_dat_w : NATURAL := g_out_dat_w;
|
445 |
|
|
SIGNAL dbg_out_nof_words : NATURAL := g_out_nof_words;
|
446 |
|
|
SIGNAL dbg_out_symbol_w : NATURAL := g_out_symbol_w;
|
447 |
|
|
SIGNAL dbc_out_buf_dat_w : NATURAL := c_out_buf_dat_w;
|
448 |
|
|
SIGNAL dbc_out_buf_dat_lo : NATURAL := c_out_buf_dat_lo;
|
449 |
|
|
SIGNAL dbc_snk_in_dat_lo : NATURAL := c_snk_in_dat_lo;
|
450 |
|
|
|
451 |
|
|
BEGIN
|
452 |
|
|
|
453 |
|
|
snk_in_data <= snk_in.data(g_in_buf_dat_w-1 DOWNTO 0);
|
454 |
|
|
|
455 |
|
|
src_out <= i_src_out;
|
456 |
|
|
src_out_data <= i_src_out.data(g_out_dat_w-1 DOWNTO 0);
|
457 |
|
|
|
458 |
|
|
gen_bypass : IF g_bypass=TRUE GENERATE
|
459 |
|
|
snk_out <= src_in;
|
460 |
|
|
|
461 |
|
|
p_src_out : PROCESS(snk_in)
|
462 |
|
|
BEGIN
|
463 |
|
|
i_src_out <= snk_in;
|
464 |
|
|
IF c_snk_in_dat_lo>0 THEN
|
465 |
|
|
i_src_out.data <= SHIFT_UVEC(snk_in.data, c_snk_in_dat_lo);
|
466 |
|
|
i_src_out.empty <= INCR_UVEC( snk_in.empty, -c_snk_in_dat_lo);
|
467 |
|
|
END IF;
|
468 |
|
|
IF c_out_buf_dat_lo>0 THEN
|
469 |
|
|
i_src_out.data <= SHIFT_UVEC(snk_in.data, -c_out_buf_dat_lo);
|
470 |
|
|
i_src_out.empty <= INCR_UVEC( snk_in.empty, c_out_buf_dat_lo);
|
471 |
|
|
END IF;
|
472 |
|
|
END PROCESS;
|
473 |
|
|
END GENERATE;
|
474 |
|
|
|
475 |
|
|
no_bypass : IF g_bypass=FALSE GENERATE
|
476 |
|
|
|
477 |
|
|
p_comb : PROCESS(rst, snk_in, r, data_vec, src_in)
|
478 |
|
|
VARIABLE v : t_reg;
|
479 |
|
|
BEGIN
|
480 |
|
|
------------------------------------------------------------------------
|
481 |
|
|
-- Default
|
482 |
|
|
v := r;
|
483 |
|
|
v.src_out.sync := '0';
|
484 |
|
|
v.src_out.valid := '0';
|
485 |
|
|
v.src_out.sop := '0';
|
486 |
|
|
v.src_out.eop := '0';
|
487 |
|
|
|
488 |
|
|
------------------------------------------------------------------------
|
489 |
|
|
-- Function
|
490 |
|
|
IF r.hold_out.valid='0' THEN
|
491 |
|
|
|
492 |
|
|
-- Clear hold_out for new output valid
|
493 |
|
|
IF r.src_out.sop='1' THEN
|
494 |
|
|
v.hold_out.sync := '0';
|
495 |
|
|
v.hold_out.sop := '0';
|
496 |
|
|
END IF;
|
497 |
|
|
IF r.src_out.eop='1' THEN
|
498 |
|
|
v.hold_out.eop := '0';
|
499 |
|
|
END IF;
|
500 |
|
|
|
501 |
|
|
-- Capture the snk_in block info that is valid at sop and eop
|
502 |
|
|
IF snk_in.sop='1' THEN
|
503 |
|
|
v.hold_out.sop := '1';
|
504 |
|
|
v.hold_out.sync := snk_in.sync;
|
505 |
|
|
v.src_out.bsn := snk_in.bsn;
|
506 |
|
|
v.src_out.channel := snk_in.channel;
|
507 |
|
|
END IF;
|
508 |
|
|
IF snk_in.eop='1' THEN
|
509 |
|
|
v.hold_out.eop := '1'; -- local function will calculate src_out.empty based on snk_in.empty
|
510 |
|
|
v.src_out.err := snk_in.err;
|
511 |
|
|
END IF;
|
512 |
|
|
|
513 |
|
|
IF r.shift='1' THEN
|
514 |
|
|
-- shift out rest of subsection
|
515 |
|
|
v.hold_out.valid := '1';
|
516 |
|
|
|
517 |
|
|
v.dat_arr(g_out_nof_words-1 DOWNTO 1) := r.dat_arr(g_out_nof_words-2 DOWNTO 0); -- shift up from low to high and shift out at high index
|
518 |
|
|
v.dat_arr(0) := (OTHERS=>'0'); -- shift in data=0
|
519 |
|
|
|
520 |
|
|
v.pack_bit_cnt := r.pack_bit_cnt - g_out_dat_w;
|
521 |
|
|
|
522 |
|
|
-- end of pack subsection
|
523 |
|
|
IF v.pack_bit_cnt<=r.empty_bit_cnt THEN
|
524 |
|
|
v.eos := '1'; -- end of subsection, so ready for new snk_in
|
525 |
|
|
v.shift := '0'; -- stop shifting
|
526 |
|
|
END IF;
|
527 |
|
|
|
528 |
|
|
ELSIF snk_in.valid='1' THEN
|
529 |
|
|
-- start of pack subsection
|
530 |
|
|
v.hold_out.valid := '1';
|
531 |
|
|
|
532 |
|
|
FOR I IN 0 TO g_out_nof_words-1 LOOP
|
533 |
|
|
v.dat_arr(I) := data_vec((I+1)*g_out_dat_w-1 DOWNTO I*g_out_dat_w);
|
534 |
|
|
END LOOP;
|
535 |
|
|
|
536 |
|
|
v.dat_bit_cnt := g_in_buf_dat_w - c_snk_in_dat_lo; -- default dat_bit_cnt per subsection
|
537 |
|
|
IF snk_in.eop='1' THEN
|
538 |
|
|
v.dat_bit_cnt := g_in_buf_dat_w - TO_UINT(snk_in.empty); -- pass on last subsection dat_bit_cnt info via DP empty field
|
539 |
|
|
END IF;
|
540 |
|
|
|
541 |
|
|
v.pack_bit_cnt := c_out_buf_dat_w - g_out_dat_w;
|
542 |
|
|
v.empty_bit_cnt := c_out_buf_dat_w - v.dat_bit_cnt;
|
543 |
|
|
v.eos := '0';
|
544 |
|
|
v.shift := '1';
|
545 |
|
|
|
546 |
|
|
-- end of pack subsection
|
547 |
|
|
IF v.pack_bit_cnt<=v.empty_bit_cnt THEN
|
548 |
|
|
v.eos := '1'; -- end of subsection, so ready for new snk_in
|
549 |
|
|
v.shift := '0';
|
550 |
|
|
END IF;
|
551 |
|
|
END IF;
|
552 |
|
|
|
553 |
|
|
-- fill in local empty if this is the last subsection of a block
|
554 |
|
|
IF v.eos='1' THEN
|
555 |
|
|
IF v.hold_out.eop='1' THEN
|
556 |
|
|
v.src_out.empty := TO_DP_EMPTY(v.empty_bit_cnt - v.pack_bit_cnt); -- in nof bits
|
557 |
|
|
v.src_out.empty := SHIFT_UVEC(v.src_out.empty, c_out_empty_lo); -- in nof symbols
|
558 |
|
|
END IF;
|
559 |
|
|
END IF;
|
560 |
|
|
|
561 |
|
|
-- pass on the v.dat_arr as data vector
|
562 |
|
|
v.src_out.data := RESIZE_DP_DATA(v.dat_arr(g_out_nof_words-1));
|
563 |
|
|
|
564 |
|
|
-- output valid data when ready, else hold_out.valid to signal pending output
|
565 |
|
|
IF v.hold_out.valid='1' THEN
|
566 |
|
|
IF src_in.ready='1' THEN
|
567 |
|
|
v.src_out.valid := '1';
|
568 |
|
|
v.src_out.sync := v.hold_out.sync;
|
569 |
|
|
v.src_out.sop := v.hold_out.sop;
|
570 |
|
|
v.src_out.eop := v.hold_out.eop AND v.eos; -- output eop at end of subsection
|
571 |
|
|
v.hold_out.valid := '0';
|
572 |
|
|
END IF;
|
573 |
|
|
END IF;
|
574 |
|
|
|
575 |
|
|
ELSE
|
576 |
|
|
-- pending output
|
577 |
|
|
IF src_in.ready='1' THEN
|
578 |
|
|
v.src_out.valid := '1';
|
579 |
|
|
v.src_out.sync := r.hold_out.sync;
|
580 |
|
|
v.src_out.sop := r.hold_out.sop;
|
581 |
|
|
v.src_out.eop := r.hold_out.eop AND r.eos; -- output eop at end of subsection
|
582 |
|
|
v.hold_out.valid := '0';
|
583 |
|
|
END IF;
|
584 |
|
|
END IF;
|
585 |
|
|
|
586 |
|
|
------------------------------------------------------------------------
|
587 |
|
|
-- Reset and nxt_r
|
588 |
|
|
IF rst = '1' THEN
|
589 |
|
|
v.src_out := c_dp_sosi_rst;
|
590 |
|
|
v.hold_out := c_dp_sosi_rst;
|
591 |
|
|
v.shift := '0';
|
592 |
|
|
v.dat_bit_cnt := 0;
|
593 |
|
|
v.pack_bit_cnt := 0;
|
594 |
|
|
v.empty_bit_cnt := 0;
|
595 |
|
|
v.eos := '0';
|
596 |
|
|
END IF;
|
597 |
|
|
|
598 |
|
|
nxt_r <= v;
|
599 |
|
|
END PROCESS;
|
600 |
|
|
|
601 |
|
|
--------------------------------------------------------------------------
|
602 |
|
|
-- p_reg
|
603 |
|
|
r <= nxt_r WHEN rising_edge(clk);
|
604 |
|
|
|
605 |
|
|
--------------------------------------------------------------------------
|
606 |
|
|
-- Wires
|
607 |
|
|
data_vec(c_out_buf_dat_w-1 DOWNTO c_out_buf_dat_lo) <= snk_in.data(g_in_buf_dat_w-1 DOWNTO c_snk_in_dat_lo);
|
608 |
|
|
|
609 |
|
|
--------------------------------------------------------------------------
|
610 |
|
|
-- Wired output
|
611 |
|
|
i_src_out <= r.src_out;
|
612 |
|
|
|
613 |
|
|
--------------------------------------------------------------------------
|
614 |
|
|
-- Flow control
|
615 |
|
|
|
616 |
|
|
-- local function flow control
|
617 |
|
|
p_flow : PROCESS(nxt_r)
|
618 |
|
|
BEGIN
|
619 |
|
|
r_snk_out <= c_dp_siso_rdy;
|
620 |
|
|
IF nxt_r.shift='1' AND nxt_r.eos='0' THEN
|
621 |
|
|
r_snk_out.ready <= '0'; -- output shift out stage function is only ready when it is not shifting or at the end of the subsection
|
622 |
|
|
END IF;
|
623 |
|
|
END PROCESS;
|
624 |
|
|
|
625 |
|
|
-- combined local and remote src_in flow control
|
626 |
|
|
snk_out.ready <= r_snk_out.ready WHEN nxt_r.hold_out.valid='0' ELSE src_in.ready; -- if there is pending output then the src_in ready determines the flow control
|
627 |
|
|
snk_out.xon <= src_in.xon; -- just pass on the xon/off frame flow control
|
628 |
|
|
|
629 |
|
|
END GENERATE;
|
630 |
|
|
|
631 |
|
|
END rtl;
|
632 |
|
|
|
633 |
|
|
|
634 |
|
|
|
635 |
|
|
LIBRARY IEEE, common_pkg_lib, dp_pkg_lib;
|
636 |
|
|
USE IEEE.std_logic_1164.ALL;
|
637 |
|
|
USE common_pkg_lib.common_pkg.ALL;
|
638 |
|
|
USE dp_pkg_lib.dp_stream_pkg.ALL;
|
639 |
|
|
|
640 |
|
|
ENTITY dp_repack_data IS
|
641 |
|
|
GENERIC (
|
642 |
|
|
g_enable_repack_in : BOOLEAN := TRUE;
|
643 |
|
|
g_enable_repack_out : BOOLEAN := TRUE;
|
644 |
|
|
g_in_bypass : BOOLEAN := FALSE;
|
645 |
|
|
g_in_dat_w : NATURAL;
|
646 |
|
|
g_in_nof_words : NATURAL;
|
647 |
|
|
g_in_symbol_w : NATURAL := 1; -- default 1 for snk_in.empty in nof bits, else use power of 2
|
648 |
|
|
g_out_bypass : BOOLEAN := FALSE;
|
649 |
|
|
g_out_dat_w : NATURAL;
|
650 |
|
|
g_out_nof_words : NATURAL;
|
651 |
|
|
g_out_symbol_w : NATURAL := 1 -- default 1 for src_out.empty in nof bits, else use power of 2
|
652 |
|
|
);
|
653 |
|
|
PORT (
|
654 |
|
|
rst : IN STD_LOGIC;
|
655 |
|
|
clk : IN STD_LOGIC;
|
656 |
|
|
|
657 |
|
|
snk_out : OUT t_dp_siso;
|
658 |
|
|
snk_in : IN t_dp_sosi;
|
659 |
|
|
|
660 |
3 |
danv |
src_in : IN t_dp_siso := c_dp_siso_rdy;
|
661 |
2 |
danv |
src_out : OUT t_dp_sosi
|
662 |
|
|
);
|
663 |
|
|
END dp_repack_data;
|
664 |
|
|
|
665 |
|
|
|
666 |
|
|
ARCHITECTURE str OF dp_repack_data IS
|
667 |
|
|
|
668 |
|
|
CONSTANT c_in_buf_dat_w : NATURAL := g_in_dat_w * g_in_nof_words;
|
669 |
|
|
|
670 |
|
|
SIGNAL snk_in_data : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
|
671 |
|
|
SIGNAL i_snk_out : t_dp_siso;
|
672 |
|
|
|
673 |
|
|
SIGNAL pack_siso : t_dp_siso;
|
674 |
|
|
SIGNAL pack_sosi : t_dp_sosi;
|
675 |
|
|
SIGNAL pack_sosi_data : STD_LOGIC_VECTOR(c_in_buf_dat_w-1 DOWNTO 0);
|
676 |
|
|
|
677 |
|
|
SIGNAL i_src_out : t_dp_sosi;
|
678 |
|
|
SIGNAL src_out_data : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
|
679 |
|
|
|
680 |
|
|
SIGNAL snk_out_ready_reg : STD_LOGIC_VECTOR(0 TO c_dp_stream_rl);
|
681 |
|
|
SIGNAL pack_ready_reg : STD_LOGIC_VECTOR(0 TO c_dp_stream_rl);
|
682 |
|
|
|
683 |
|
|
BEGIN
|
684 |
|
|
|
685 |
|
|
snk_out <= i_snk_out;
|
686 |
|
|
src_out <= i_src_out;
|
687 |
|
|
|
688 |
|
|
snk_in_data <= snk_in.data(g_in_dat_w-1 DOWNTO 0);
|
689 |
|
|
pack_sosi_data <= pack_sosi.data(c_in_buf_dat_w-1 DOWNTO 0);
|
690 |
|
|
src_out_data <= i_src_out.data(g_out_dat_w-1 DOWNTO 0);
|
691 |
|
|
|
692 |
|
|
no_dp_repack_in : IF g_enable_repack_in=FALSE GENERATE
|
693 |
|
|
i_snk_out <= pack_siso;
|
694 |
|
|
pack_sosi <= snk_in;
|
695 |
|
|
END GENERATE;
|
696 |
|
|
|
697 |
|
|
gen_dp_repack_in : IF g_enable_repack_in=TRUE GENERATE
|
698 |
|
|
u_dp_repack_in : ENTITY work.dp_repack_in
|
699 |
|
|
GENERIC MAP (
|
700 |
|
|
g_bypass => g_in_bypass,
|
701 |
|
|
g_in_dat_w => g_in_dat_w,
|
702 |
|
|
g_in_nof_words => g_in_nof_words,
|
703 |
|
|
g_in_symbol_w => g_in_symbol_w
|
704 |
|
|
)
|
705 |
|
|
PORT MAP (
|
706 |
|
|
rst => rst,
|
707 |
|
|
clk => clk,
|
708 |
|
|
|
709 |
|
|
snk_out => i_snk_out,
|
710 |
|
|
snk_in => snk_in,
|
711 |
|
|
|
712 |
|
|
src_in => pack_siso,
|
713 |
|
|
src_out => pack_sosi
|
714 |
|
|
);
|
715 |
|
|
END GENERATE;
|
716 |
|
|
|
717 |
|
|
no_dp_repack_out : IF g_enable_repack_out=FALSE GENERATE
|
718 |
|
|
pack_siso <= src_in;
|
719 |
|
|
i_src_out <= pack_sosi;
|
720 |
|
|
END GENERATE;
|
721 |
|
|
|
722 |
|
|
gen_dp_repack_out : IF g_enable_repack_out=TRUE GENERATE
|
723 |
|
|
u_dp_repack_out : ENTITY work.dp_repack_out
|
724 |
|
|
GENERIC MAP (
|
725 |
|
|
g_bypass => g_out_bypass,
|
726 |
|
|
g_in_buf_dat_w => c_in_buf_dat_w,
|
727 |
|
|
g_out_dat_w => g_out_dat_w,
|
728 |
|
|
g_out_nof_words => g_out_nof_words,
|
729 |
|
|
g_out_symbol_w => g_out_symbol_w
|
730 |
|
|
)
|
731 |
|
|
PORT MAP (
|
732 |
|
|
rst => rst,
|
733 |
|
|
clk => clk,
|
734 |
|
|
|
735 |
|
|
snk_out => pack_siso,
|
736 |
|
|
snk_in => pack_sosi,
|
737 |
|
|
|
738 |
|
|
src_in => src_in,
|
739 |
|
|
src_out => i_src_out
|
740 |
|
|
);
|
741 |
|
|
END GENERATE;
|
742 |
|
|
|
743 |
|
|
-- Simulation only: internal stream RL verification
|
744 |
|
|
proc_dp_siso_alert(clk, snk_in, i_snk_out, snk_out_ready_reg);
|
745 |
|
|
proc_dp_siso_alert(clk, pack_sosi, pack_siso, pack_ready_reg);
|
746 |
|
|
|
747 |
|
|
END str;
|