URL
https://opencores.org/ocsvn/dp_repack_data/dp_repack_data/trunk
Subversion Repositories dp_repack_data
[/] [dp_repack_data/] [trunk/] [dp_repack_data.vhd] - Rev 5
Compare with Previous | Blame | View Log
-------------------------------------------------------------------------------- -- -- Copyright 2020 -- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> -- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands -- -- 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 -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- 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. -- -------------------------------------------------------------------------------- -- Purpose: -- The dp_repack_data works both as packer and as unpacker. -- -- Block diagram: -- -- A) Functional -- The drawing shows g_in_nof_words=4 and g_out_nof_words=2 as example: -- -- dp_repack_in dp_repack_out -- ___ ___ -- | | pack_sosi | |--> src_out -- | 3 |--------------------->| 1 | -- | | | | -- | 2 | ^ | | ^ -- | | |valid | | |shift -- | 1 | |flush | 0 | | -- | | | | | | -- | 0 | | | -- snk_in -->|___| pack_siso |___| -- snk_out.ready <-- <--------------------- <-- src_in.ready -- snk_out.xon <------------------------------------- src_in.xon -- -- -- B) Flow control -- -- RL=1 RL=1 RL=1 -- . . . -- . /-----------------------------------------\ -- . | . _____ . | -- . | /------\ nxt_r | | r | -- . \-->| |---*-------*----->|p_reg|-----*---> src_out -- . | | | | |_____| -- snk_in -------->|p_comb|<--|-------|--------------*-------- src_in -- | | | | | -- | | | v | -- | | | /-------\ | -- | | | |p_flow | | -- \------/ | \-------/ | -- | | | -- nxt_r.hold_out.valid | | | -- v | | -- /| |r_snk_out | -- |0|------/ | -- snk_out <------------------| | | -- |1|---------------------/ -- \| -- -- Description: -- The dp_repack_data repacks g_in_nof_words of width g_in_dat_w into -- g_out_nof_words of width g_out_dat_w. -- -- . g_in_bypass, g_out_bypass -- The dp_repack_in and dp_repack_out can be bypassed to save logic and to -- avoid the pipeline stage. Default both are FALSE, but they can be set -- TRUE if: -- -- . g_in_bypass =TRUE if g_in_nof_words=g_out_nof_words or g_in_nof_words=1 -- . g_out_bypass=TRUE if g_in_nof_words=g_out_nof_words or g_out_nof_words=1 -- -- Both the dp_repack_in and dp_repack_out stage do work correctly independent -- of the g_*_bypass setting. When g_*_bypass=FALSE then they merely -- add a transparant pipeline delay. It is important that they also work for -- g_*_bypass=FALSE because that gives confidence that their implementation -- structure is ok. -- -- . g_in_nof_words and input block size -- The input block size in words is indicated by snk_in.sop and snk_in.eop. -- Each subsection of g_in_nof_words is packed into g_out_nof_words. The -- input block size does not have to be a multiple of g_in_nof_words. When -- the snk_in.eop occurs the last repack is initiated without need for input -- data padding. If the block length is an integer multiple of -- g_in_nof_words then the dp_repack_data introduces no gaps between blocks. -- If the block length is a fractional multiple of g_in_nof_words then there -- will be a gap after the block due to that the dp_repack_in needs to -- shift up the last subsection for the 'missing' input words. -- -- . g_in_dat_w*g_in_nof_words <, =, > g_in_dat_w*g_in_nof_words -- . = : no subsection zero padding -- . < : the subsections will be zero padded -- . > : then the input must have sufficient zero padded bits per -- subsection that can be stripped without data loss. -- -- . Resolution of the empty field -- The g_in_symbol_w is used to define the resolution of snk_in.empty and -- the g_out_symbol_w is used to define the resolution of src_out.empty. If -- they are 1 then the resolution is in number of bits, because the symbol -- size is then 1 bit. Their value has no effect on the packed data it self, -- only on the meaning of the empty field. Hence if the empty field is not -- used, then the setting of g_in_symbol_w and g_out_symbol_w is dont care. -- -- Remarks: -- . Originally reused from LOFAR rad_repack.vhd and rad_repack(rtl).vhd. This -- dp_repack_data still uses the shift in input register in and the shift out -- output register, but no longer the intermediate buffer register. -- Using shift in and shift out may ease timing closure because the routing -- is more local compared to using a demultiplexer to put the input data in -- the input register and a multiplexer to get the data directly from the -- output register. For the demultiplexer / multiplexer it would be possible -- to only use one internal register. -- Using shift up is sufficient, the shift down option is not needed. With -- shift up the data is input a [0] and output the high index. -- Instead of requiring an snk_in.valid duty cycle this dp_repack_data uses -- snk_out.ready flow control and can handle src_in.ready flow control. -- -- . To pack ETH/IP/UDP header slv of 14 + 20 + 8 = 42 octets into 32 bit words -- use: -- u_dp_repack_data : ENTITY .dp_repack_data -- GENERIC MAP ( -- g_in_bypass => TRUE, -- g_in_dat_w => 8 * 42, -- g_in_nof_words => 1, -- g_in_symbol_w => 8, -- g_out_bypass => FALSE, -- g_out_dat_w => 32, -- g_out_nof_words => 11, -- g_out_symbol_w => 8 -- ) -- The src_out.empty will be 2, because: -- (g_out_dat_w*g_out_nof_words-g_in_dat_w*g_in_nof_words)/g_out_symbol_w -- = (32*11 - 42*8*1)/ 8 = 2 octet symbols -- -- Design steps: -- * In total the development took 5 days. On day 3 I was in distress because -- I could not get it to work so I needed to rethink. After changing to the -- new flow control scheme that uses nxt_r the design was gradually improved -- by getting the dp_repack_data instances in tb_tb_dp_repack_data to work one -- by one. First only for e_active stimuli and later also for e_random and -- e_pulse. Initially about 80 % of the functionality was implemented but -- and subsequently each feature was verified starting with the basic -- features and then themore detailed features. This step by step approach -- makes that the bugs appear one by one instead of all together. Without a -- step by step approach the bugs are too big to solve. -- . First cases with g_in_nof_words=1 and g_out_nof_words were made to work -- for different g_pkt_len <, =, > g_in_nof_words. -- . Then the empty functionality for g_pkt_len MOD g_in_nof_words /= 0 was -- added. -- . Tried g_out_dat_w=1 which makes dp_repack_data a serializer/deserializer. -- . Then apply external flow control using c_dp_flow_control_enum_arr in -- the tb_tb_dp_repack_data was verified resulting in small corrections. -- . Then verified g_in_dat_w * g_in_nof_words > or < g_out_dat_w * -- g_out_nof_words which require padding in the subsection. The > case -- occurs for packing and the < case then occurs for unpacking. -- . Added g_bypass to force using wires instead of a void dp_repack_in or -- dp_repack_out stage. -- . Verified g_in_symbol_w and g_out_symbol_w /= 1. -- * The development used the tb_dp_repack_data testbench that does a pack and -- an unpack to be able to verify the data. The c_no_unpack and -- c_enable_repack_in and c_enable_repack_out parameters in the tb are -- useful to be able to isolate a component for debugging. LIBRARY IEEE, common_pkg_lib, dp_pkg_lib; USE IEEE.std_logic_1164.ALL; USE common_pkg_lib.common_pkg.ALL; USE dp_pkg_lib.dp_stream_pkg.ALL; ENTITY dp_repack_in IS GENERIC ( g_bypass : BOOLEAN := FALSE; g_in_dat_w : NATURAL; g_in_nof_words : NATURAL; g_in_symbol_w : NATURAL := 1 -- default 1 for snk_in.empty in nof bits, else use power of 2 ); PORT ( rst : IN STD_LOGIC; clk : IN STD_LOGIC; snk_out : OUT t_dp_siso; snk_in : IN t_dp_sosi; src_in : IN t_dp_siso; src_out : OUT t_dp_sosi ); END dp_repack_in; ARCHITECTURE rtl OF dp_repack_in IS CONSTANT c_in_buf_dat_w : NATURAL := g_in_dat_w * g_in_nof_words; CONSTANT c_bit_cnt_max : NATURAL := c_in_buf_dat_w; CONSTANT c_in_empty_lo : NATURAL := true_log2(g_in_symbol_w); TYPE t_dat_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0); TYPE t_reg IS RECORD dat_arr : t_dat_arr(g_in_nof_words-1 DOWNTO 0); -- internally use dat_arr[] to represent v.src_out.data src_out : t_dp_sosi; -- sosi output 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 flush : STD_LOGIC; -- shift when snk_in.valid or flush in case the last subsection has < g_in_nof_words dat_bit_cnt : NATURAL RANGE 0 TO c_bit_cnt_max; -- actual nof bits in subsection pack_bit_cnt : NATURAL RANGE 0 TO c_bit_cnt_max; -- count nof bits in subsection END RECORD; SIGNAL data_vec : STD_LOGIC_VECTOR(c_in_buf_dat_w-1 DOWNTO 0); SIGNAL r_snk_out : t_dp_siso := c_dp_siso_rdy; SIGNAL r : t_reg; SIGNAL nxt_r : t_reg; -- Debug signals SIGNAL snk_in_data : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0); SIGNAL i_src_out : t_dp_sosi; SIGNAL src_out_data : STD_LOGIC_VECTOR(c_in_buf_dat_w-1 DOWNTO 0); SIGNAL dbg_g_in_dat_w : NATURAL := g_in_dat_w; SIGNAL dbg_in_nof_words : NATURAL := g_in_nof_words; SIGNAL dbg_in_symbol_w : NATURAL := g_in_symbol_w; SIGNAL dbc_in_buf_dat_w : NATURAL := c_in_buf_dat_w; BEGIN snk_in_data <= snk_in.data(g_in_dat_w-1 DOWNTO 0); src_out <= i_src_out; src_out_data <= i_src_out.data(c_in_buf_dat_w-1 DOWNTO 0); gen_bypass : IF g_bypass=TRUE GENERATE snk_out <= src_in; i_src_out <= snk_in; END GENERATE; no_bypass : IF g_bypass=FALSE GENERATE p_comb : PROCESS(rst, r, snk_in, data_vec, src_in) VARIABLE v : t_reg; BEGIN ------------------------------------------------------------------------ -- Default v := r; v.src_out.sync := '0'; v.src_out.valid := '0'; v.src_out.sop := '0'; v.src_out.eop := '0'; -------------------------------------------------------------------------- -- Function IF r.hold_out.valid='0' THEN -- Clear hold_out for new output valid (= new subsection) IF r.src_out.valid='1' THEN v.hold_out := c_dp_sosi_rst; END IF; -- Capture the snk_in block info that is valid at sop and eop IF snk_in.sop='1' THEN v.hold_out.sop := '1'; v.hold_out.sync := snk_in.sync; v.src_out.bsn := snk_in.bsn; v.src_out.channel := snk_in.channel; END IF; IF snk_in.eop='1' THEN v.hold_out.eop := '1'; 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 v.src_out.err := snk_in.err; END IF; -- Capture the data per subsection in a block IF snk_in.valid='1' OR r.flush='1' THEN -- shift in during block 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 IF r.flush='1' THEN v.dat_arr(0) := (OTHERS=>'0'); -- shift in data=0 for flush ELSE v.dat_arr(0) := snk_in.data(g_in_dat_w-1 DOWNTO 0); -- shift in valid data END IF; -- pack subsection IF r.pack_bit_cnt<c_in_buf_dat_w-g_in_dat_w THEN v.pack_bit_cnt := r.pack_bit_cnt + g_in_dat_w; -- early end of pack subsection IF snk_in.eop='1' THEN v.flush := '1'; -- enable flush in case eop occurs before end of pack subsection v.dat_bit_cnt := v.pack_bit_cnt; -- capture the current subsection pack_bit_cnt END IF; ELSE -- r.pack_bit_cnt=c_in_buf_dat_w-g_in_dat_w -- default end of pack subsection v.pack_bit_cnt := 0; v.flush := '0'; IF r.flush='0' THEN v.dat_bit_cnt := c_in_buf_dat_w; -- set default subsection pack_bit_cnt END IF; v.hold_out.valid := '1'; -- the function has new data to output END IF; END IF; -- pass on the v.dat_arr as data vector v.src_out.data := RESIZE_DP_DATA(data_vec); -- pass on dat_bit_cnt via DP empty field v.src_out.empty := INCR_UVEC(v.hold_out.empty, c_in_buf_dat_w - v.dat_bit_cnt); -- output input stage into output stage when ready, else hold_out.valid to signal pending output IF v.hold_out.valid='1' THEN IF src_in.ready='1' THEN v.src_out.valid := '1'; v.src_out.sync := v.hold_out.sync; v.src_out.sop := v.hold_out.sop; v.src_out.eop := v.hold_out.eop; v.hold_out.valid := '0'; END IF; END IF; ELSE -- pending output IF src_in.ready='1' THEN v.src_out.valid := '1'; v.src_out.sync := r.hold_out.sync; v.src_out.sop := r.hold_out.sop; v.src_out.eop := r.hold_out.eop; v.hold_out.valid := '0'; END IF; END IF; ------------------------------------------------------------------------ -- Reset and nxt_r IF rst = '1' THEN v.src_out := c_dp_sosi_rst; v.hold_out := c_dp_sosi_rst; v.flush := '0'; v.dat_bit_cnt := 0; v.pack_bit_cnt := 0; END IF; nxt_r <= v; END PROCESS; -------------------------------------------------------------------------- -- p_reg r <= nxt_r WHEN rising_edge(clk); -------------------------------------------------------------------------- -- Wires p_data_vec : PROCESS(nxt_r) BEGIN FOR I IN 0 TO g_in_nof_words-1 LOOP data_vec((I+1)*g_in_dat_w-1 DOWNTO I*g_in_dat_w) <= nxt_r.dat_arr(I); END LOOP; END PROCESS; -------------------------------------------------------------------------- -- Wired output i_src_out <= r.src_out; -------------------------------------------------------------------------- -- Flow control -- local function flow control p_flow : PROCESS(nxt_r) BEGIN r_snk_out <= c_dp_siso_rdy; IF nxt_r.flush='1' THEN r_snk_out.ready <= '0'; -- input shift in stage function is always ready except when flushing END IF; END PROCESS; -- combined local and remote src_in flow control 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 snk_out.xon <= src_in.xon; -- just pass on the xon/off frame flow control END GENERATE; END rtl; LIBRARY IEEE, common_pkg_lib, dp_pkg_lib; USE IEEE.std_logic_1164.ALL; USE common_pkg_lib.common_pkg.ALL; USE dp_pkg_lib.dp_stream_pkg.ALL; ENTITY dp_repack_out IS GENERIC ( g_bypass : BOOLEAN := FALSE; g_in_buf_dat_w : NATURAL; g_out_dat_w : NATURAL; g_out_nof_words : NATURAL; g_out_symbol_w : NATURAL := 1 -- default 1 for snk_in.empty in nof bits, else use power of 2 ); PORT ( rst : IN STD_LOGIC; clk : IN STD_LOGIC; snk_out : OUT t_dp_siso; snk_in : IN t_dp_sosi; src_in : IN t_dp_siso; src_out : OUT t_dp_sosi ); END dp_repack_out; ARCHITECTURE rtl OF dp_repack_out IS CONSTANT c_out_buf_dat_w : NATURAL := g_out_dat_w * g_out_nof_words; 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 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 CONSTANT c_bit_cnt_max : NATURAL := c_out_buf_dat_w; CONSTANT c_out_empty_lo : NATURAL := true_log2(g_out_symbol_w); TYPE t_dat_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0); TYPE t_reg IS RECORD dat_arr : t_dat_arr(g_out_nof_words-1 DOWNTO 0); src_out : t_dp_sosi; hold_out : t_dp_sosi; -- hold src_out valid and sync/sop/eop until src_in.ready shift : STD_LOGIC; -- shift out the dat_arr dat_bit_cnt : NATURAL RANGE 0 TO c_bit_cnt_max; -- actual nof bits in subsection pack_bit_cnt : NATURAL RANGE 0 TO c_bit_cnt_max; -- count nof bits in subsection empty_bit_cnt : NATURAL RANGE 0 TO c_bit_cnt_max; -- empty nof bits in subsection eos : STD_LOGIC; -- end of subsection END RECORD; SIGNAL data_vec : STD_LOGIC_VECTOR(c_out_buf_dat_w-1 DOWNTO 0) := (OTHERS=>'0'); SIGNAL r_snk_out : t_dp_siso := c_dp_siso_rdy; SIGNAL r : t_reg; SIGNAL nxt_r : t_reg; -- Debug signals SIGNAL snk_in_data : STD_LOGIC_VECTOR(g_in_buf_dat_w-1 DOWNTO 0); SIGNAL i_src_out : t_dp_sosi; SIGNAL src_out_data : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0); SIGNAL dbg_g_in_buf_dat_w : NATURAL := g_in_buf_dat_w; SIGNAL dbg_g_out_dat_w : NATURAL := g_out_dat_w; SIGNAL dbg_out_nof_words : NATURAL := g_out_nof_words; SIGNAL dbg_out_symbol_w : NATURAL := g_out_symbol_w; SIGNAL dbc_out_buf_dat_w : NATURAL := c_out_buf_dat_w; SIGNAL dbc_out_buf_dat_lo : NATURAL := c_out_buf_dat_lo; SIGNAL dbc_snk_in_dat_lo : NATURAL := c_snk_in_dat_lo; BEGIN snk_in_data <= snk_in.data(g_in_buf_dat_w-1 DOWNTO 0); src_out <= i_src_out; src_out_data <= i_src_out.data(g_out_dat_w-1 DOWNTO 0); gen_bypass : IF g_bypass=TRUE GENERATE snk_out <= src_in; p_src_out : PROCESS(snk_in) BEGIN i_src_out <= snk_in; IF c_snk_in_dat_lo>0 THEN i_src_out.data <= SHIFT_UVEC(snk_in.data, c_snk_in_dat_lo); i_src_out.empty <= INCR_UVEC( snk_in.empty, -c_snk_in_dat_lo); END IF; IF c_out_buf_dat_lo>0 THEN i_src_out.data <= SHIFT_UVEC(snk_in.data, -c_out_buf_dat_lo); i_src_out.empty <= INCR_UVEC( snk_in.empty, c_out_buf_dat_lo); END IF; END PROCESS; END GENERATE; no_bypass : IF g_bypass=FALSE GENERATE p_comb : PROCESS(rst, snk_in, r, data_vec, src_in) VARIABLE v : t_reg; BEGIN ------------------------------------------------------------------------ -- Default v := r; v.src_out.sync := '0'; v.src_out.valid := '0'; v.src_out.sop := '0'; v.src_out.eop := '0'; ------------------------------------------------------------------------ -- Function IF r.hold_out.valid='0' THEN -- Clear hold_out for new output valid IF r.src_out.sop='1' THEN v.hold_out.sync := '0'; v.hold_out.sop := '0'; END IF; IF r.src_out.eop='1' THEN v.hold_out.eop := '0'; END IF; -- Capture the snk_in block info that is valid at sop and eop IF snk_in.sop='1' THEN v.hold_out.sop := '1'; v.hold_out.sync := snk_in.sync; v.src_out.bsn := snk_in.bsn; v.src_out.channel := snk_in.channel; END IF; IF snk_in.eop='1' THEN v.hold_out.eop := '1'; -- local function will calculate src_out.empty based on snk_in.empty v.src_out.err := snk_in.err; END IF; IF r.shift='1' THEN -- shift out rest of subsection v.hold_out.valid := '1'; 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 v.dat_arr(0) := (OTHERS=>'0'); -- shift in data=0 v.pack_bit_cnt := r.pack_bit_cnt - g_out_dat_w; -- end of pack subsection IF v.pack_bit_cnt<=r.empty_bit_cnt THEN v.eos := '1'; -- end of subsection, so ready for new snk_in v.shift := '0'; -- stop shifting END IF; ELSIF snk_in.valid='1' THEN -- start of pack subsection v.hold_out.valid := '1'; FOR I IN 0 TO g_out_nof_words-1 LOOP v.dat_arr(I) := data_vec((I+1)*g_out_dat_w-1 DOWNTO I*g_out_dat_w); END LOOP; v.dat_bit_cnt := g_in_buf_dat_w - c_snk_in_dat_lo; -- default dat_bit_cnt per subsection IF snk_in.eop='1' THEN 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 END IF; v.pack_bit_cnt := c_out_buf_dat_w - g_out_dat_w; v.empty_bit_cnt := c_out_buf_dat_w - v.dat_bit_cnt; v.eos := '0'; v.shift := '1'; -- end of pack subsection IF v.pack_bit_cnt<=v.empty_bit_cnt THEN v.eos := '1'; -- end of subsection, so ready for new snk_in v.shift := '0'; END IF; END IF; -- fill in local empty if this is the last subsection of a block IF v.eos='1' THEN IF v.hold_out.eop='1' THEN v.src_out.empty := TO_DP_EMPTY(v.empty_bit_cnt - v.pack_bit_cnt); -- in nof bits v.src_out.empty := SHIFT_UVEC(v.src_out.empty, c_out_empty_lo); -- in nof symbols END IF; END IF; -- pass on the v.dat_arr as data vector v.src_out.data := RESIZE_DP_DATA(v.dat_arr(g_out_nof_words-1)); -- output valid data when ready, else hold_out.valid to signal pending output IF v.hold_out.valid='1' THEN IF src_in.ready='1' THEN v.src_out.valid := '1'; v.src_out.sync := v.hold_out.sync; v.src_out.sop := v.hold_out.sop; v.src_out.eop := v.hold_out.eop AND v.eos; -- output eop at end of subsection v.hold_out.valid := '0'; END IF; END IF; ELSE -- pending output IF src_in.ready='1' THEN v.src_out.valid := '1'; v.src_out.sync := r.hold_out.sync; v.src_out.sop := r.hold_out.sop; v.src_out.eop := r.hold_out.eop AND r.eos; -- output eop at end of subsection v.hold_out.valid := '0'; END IF; END IF; ------------------------------------------------------------------------ -- Reset and nxt_r IF rst = '1' THEN v.src_out := c_dp_sosi_rst; v.hold_out := c_dp_sosi_rst; v.shift := '0'; v.dat_bit_cnt := 0; v.pack_bit_cnt := 0; v.empty_bit_cnt := 0; v.eos := '0'; END IF; nxt_r <= v; END PROCESS; -------------------------------------------------------------------------- -- p_reg r <= nxt_r WHEN rising_edge(clk); -------------------------------------------------------------------------- -- Wires 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); -------------------------------------------------------------------------- -- Wired output i_src_out <= r.src_out; -------------------------------------------------------------------------- -- Flow control -- local function flow control p_flow : PROCESS(nxt_r) BEGIN r_snk_out <= c_dp_siso_rdy; IF nxt_r.shift='1' AND nxt_r.eos='0' THEN 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 END IF; END PROCESS; -- combined local and remote src_in flow control 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 snk_out.xon <= src_in.xon; -- just pass on the xon/off frame flow control END GENERATE; END rtl; LIBRARY IEEE, common_pkg_lib, dp_pkg_lib; USE IEEE.std_logic_1164.ALL; USE common_pkg_lib.common_pkg.ALL; USE dp_pkg_lib.dp_stream_pkg.ALL; ENTITY dp_repack_data IS GENERIC ( g_enable_repack_in : BOOLEAN := TRUE; g_enable_repack_out : BOOLEAN := TRUE; g_in_bypass : BOOLEAN := FALSE; g_in_dat_w : NATURAL; g_in_nof_words : NATURAL; g_in_symbol_w : NATURAL := 1; -- default 1 for snk_in.empty in nof bits, else use power of 2 g_out_bypass : BOOLEAN := FALSE; g_out_dat_w : NATURAL; g_out_nof_words : NATURAL; g_out_symbol_w : NATURAL := 1 -- default 1 for src_out.empty in nof bits, else use power of 2 ); PORT ( rst : IN STD_LOGIC; clk : IN STD_LOGIC; snk_out : OUT t_dp_siso; snk_in : IN t_dp_sosi; src_in : IN t_dp_siso := c_dp_siso_rdy; src_out : OUT t_dp_sosi ); END dp_repack_data; ARCHITECTURE str OF dp_repack_data IS CONSTANT c_in_buf_dat_w : NATURAL := g_in_dat_w * g_in_nof_words; SIGNAL snk_in_data : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0); SIGNAL i_snk_out : t_dp_siso; SIGNAL pack_siso : t_dp_siso; SIGNAL pack_sosi : t_dp_sosi; SIGNAL pack_sosi_data : STD_LOGIC_VECTOR(c_in_buf_dat_w-1 DOWNTO 0); SIGNAL i_src_out : t_dp_sosi; SIGNAL src_out_data : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0); SIGNAL snk_out_ready_reg : STD_LOGIC_VECTOR(0 TO c_dp_stream_rl); SIGNAL pack_ready_reg : STD_LOGIC_VECTOR(0 TO c_dp_stream_rl); BEGIN snk_out <= i_snk_out; src_out <= i_src_out; snk_in_data <= snk_in.data(g_in_dat_w-1 DOWNTO 0); pack_sosi_data <= pack_sosi.data(c_in_buf_dat_w-1 DOWNTO 0); src_out_data <= i_src_out.data(g_out_dat_w-1 DOWNTO 0); no_dp_repack_in : IF g_enable_repack_in=FALSE GENERATE i_snk_out <= pack_siso; pack_sosi <= snk_in; END GENERATE; gen_dp_repack_in : IF g_enable_repack_in=TRUE GENERATE u_dp_repack_in : ENTITY work.dp_repack_in GENERIC MAP ( g_bypass => g_in_bypass, g_in_dat_w => g_in_dat_w, g_in_nof_words => g_in_nof_words, g_in_symbol_w => g_in_symbol_w ) PORT MAP ( rst => rst, clk => clk, snk_out => i_snk_out, snk_in => snk_in, src_in => pack_siso, src_out => pack_sosi ); END GENERATE; no_dp_repack_out : IF g_enable_repack_out=FALSE GENERATE pack_siso <= src_in; i_src_out <= pack_sosi; END GENERATE; gen_dp_repack_out : IF g_enable_repack_out=TRUE GENERATE u_dp_repack_out : ENTITY work.dp_repack_out GENERIC MAP ( g_bypass => g_out_bypass, g_in_buf_dat_w => c_in_buf_dat_w, g_out_dat_w => g_out_dat_w, g_out_nof_words => g_out_nof_words, g_out_symbol_w => g_out_symbol_w ) PORT MAP ( rst => rst, clk => clk, snk_out => pack_siso, snk_in => pack_sosi, src_in => src_in, src_out => i_src_out ); END GENERATE; -- Simulation only: internal stream RL verification proc_dp_siso_alert(clk, snk_in, i_snk_out, snk_out_ready_reg); proc_dp_siso_alert(clk, pack_sosi, pack_siso, pack_ready_reg); END str;