--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
--
|
--
|
-- Copyright (C) 2015
|
-- Copyright 2020
|
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
|
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
|
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
|
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
|
--
|
--
|
-- This program is free software: you can redistribute it and/or modify
|
-- Licensed under the Apache License, Version 2.0 (the "License");
|
-- it under the terms of the GNU General Public License as published by
|
-- you may not use this file except in compliance with the License.
|
-- the Free Software Foundation, either version 3 of the License, or
|
-- You may obtain a copy of the License at
|
-- (at your option) any later version.
|
|
--
|
--
|
-- This program is distributed in the hope that it will be useful,
|
-- http://www.apache.org/licenses/LICENSE-2.0
|
-- 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
|
-- Unless required by applicable law or agreed to in writing, software
|
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
-- 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:
|
-- Purpose:
|
-- The dp_repack_data works both as packer and as unpacker.
|
-- The dp_repack_data works both as packer and as unpacker.
|
--
|
--
|
-- Block diagram:
|
-- Block diagram:
|
--
|
--
|
-- A) Functional
|
-- A) Functional
|
-- The drawing shows g_in_nof_words=4 and g_out_nof_words=2 as example:
|
-- The drawing shows g_in_nof_words=4 and g_out_nof_words=2 as example:
|
--
|
--
|
-- dp_repack_in dp_repack_out
|
-- dp_repack_in dp_repack_out
|
-- ___ ___
|
-- ___ ___
|
-- | | pack_sosi | |--> src_out
|
-- | | pack_sosi | |--> src_out
|
-- | 3 |--------------------->| 1 |
|
-- | 3 |--------------------->| 1 |
|
-- | | | |
|
-- | | | |
|
-- | 2 | ^ | | ^
|
-- | 2 | ^ | | ^
|
-- | | |valid | | |shift
|
-- | | |valid | | |shift
|
-- | 1 | |flush | 0 | |
|
-- | 1 | |flush | 0 | |
|
-- | | | | | |
|
-- | | | | | |
|
-- | 0 | | |
|
-- | 0 | | |
|
-- snk_in -->|___| pack_siso |___|
|
-- snk_in -->|___| pack_siso |___|
|
-- snk_out.ready <-- <--------------------- <-- src_in.ready
|
-- snk_out.ready <-- <--------------------- <-- src_in.ready
|
-- snk_out.xon <------------------------------------- src_in.xon
|
-- snk_out.xon <------------------------------------- src_in.xon
|
--
|
--
|
--
|
--
|
-- B) Flow control
|
-- B) Flow control
|
--
|
--
|
-- RL=1 RL=1 RL=1
|
-- RL=1 RL=1 RL=1
|
-- . . .
|
-- . . .
|
-- . /-----------------------------------------\
|
-- . /-----------------------------------------\
|
-- . | . _____ . |
|
-- . | . _____ . |
|
-- . | /------\ nxt_r | | r |
|
-- . | /------\ nxt_r | | r |
|
-- . \-->| |---*-------*----->|p_reg|-----*---> src_out
|
-- . \-->| |---*-------*----->|p_reg|-----*---> src_out
|
-- . | | | | |_____|
|
-- . | | | | |_____|
|
-- snk_in -------->|p_comb|<--|-------|--------------*-------- src_in
|
-- snk_in -------->|p_comb|<--|-------|--------------*-------- src_in
|
-- | | | | |
|
-- | | | | |
|
-- | | | v |
|
-- | | | v |
|
-- | | | /-------\ |
|
-- | | | /-------\ |
|
-- | | | |p_flow | |
|
-- | | | |p_flow | |
|
-- \------/ | \-------/ |
|
-- \------/ | \-------/ |
|
-- | | |
|
-- | | |
|
-- nxt_r.hold_out.valid | | |
|
-- nxt_r.hold_out.valid | | |
|
-- v | |
|
-- v | |
|
-- /| |r_snk_out |
|
-- /| |r_snk_out |
|
-- |0|------/ |
|
-- |0|------/ |
|
-- snk_out <------------------| | |
|
-- snk_out <------------------| | |
|
-- |1|---------------------/
|
-- |1|---------------------/
|
-- \|
|
-- \|
|
--
|
--
|
-- Description:
|
-- Description:
|
-- The dp_repack_data repacks g_in_nof_words of width g_in_dat_w into
|
-- 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_out_nof_words of width g_out_dat_w.
|
--
|
--
|
-- . g_in_bypass, g_out_bypass
|
-- . g_in_bypass, g_out_bypass
|
-- The dp_repack_in and dp_repack_out can be bypassed to save logic and to
|
-- 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
|
-- avoid the pipeline stage. Default both are FALSE, but they can be set
|
-- TRUE if:
|
-- TRUE if:
|
--
|
--
|
-- . g_in_bypass =TRUE if g_in_nof_words=g_out_nof_words or g_in_nof_words=1
|
-- . 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
|
-- . 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
|
-- 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
|
-- 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
|
-- add a transparant pipeline delay. It is important that they also work for
|
-- g_*_bypass=FALSE because that gives confidence that their implementation
|
-- g_*_bypass=FALSE because that gives confidence that their implementation
|
-- structure is ok.
|
-- structure is ok.
|
--
|
--
|
-- . g_in_nof_words and input block size
|
-- . g_in_nof_words and input block size
|
-- The input block size in words is indicated by snk_in.sop and snk_in.eop.
|
-- 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
|
-- 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
|
-- 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
|
-- 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
|
-- 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.
|
-- 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
|
-- 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
|
-- 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.
|
-- 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
|
-- . g_in_dat_w*g_in_nof_words <, =, > g_in_dat_w*g_in_nof_words
|
-- . = : no subsection zero padding
|
-- . = : no subsection zero padding
|
-- . < : the subsections will be zero padded
|
-- . < : the subsections will be zero padded
|
-- . > : then the input must have sufficient zero padded bits per
|
-- . > : then the input must have sufficient zero padded bits per
|
-- subsection that can be stripped without data loss.
|
-- subsection that can be stripped without data loss.
|
--
|
--
|
-- . Resolution of the empty field
|
-- . Resolution of the empty field
|
-- The g_in_symbol_w is used to define the resolution of snk_in.empty and
|
-- 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
|
-- 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
|
-- 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,
|
-- 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
|
-- 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.
|
-- used, then the setting of g_in_symbol_w and g_out_symbol_w is dont care.
|
--
|
--
|
-- Remarks:
|
-- Remarks:
|
-- . Originally reused from LOFAR rad_repack.vhd and rad_repack(rtl).vhd. This
|
-- . 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
|
-- dp_repack_data still uses the shift in input register in and the shift out
|
-- output register, but no longer the intermediate buffer register.
|
-- output register, but no longer the intermediate buffer register.
|
-- Using shift in and shift out may ease timing closure because the routing
|
-- 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
|
-- 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
|
-- the input register and a multiplexer to get the data directly from the
|
-- output register. For the demultiplexer / multiplexer it would be possible
|
-- output register. For the demultiplexer / multiplexer it would be possible
|
-- to only use one internal register.
|
-- to only use one internal register.
|
-- Using shift up is sufficient, the shift down option is not needed. With
|
-- 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.
|
-- 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
|
-- 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.
|
-- 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
|
-- . To pack ETH/IP/UDP header slv of 14 + 20 + 8 = 42 octets into 32 bit words
|
-- use:
|
-- use:
|
-- u_dp_repack_data : ENTITY .dp_repack_data
|
-- u_dp_repack_data : ENTITY .dp_repack_data
|
-- GENERIC MAP (
|
-- GENERIC MAP (
|
-- g_in_bypass => TRUE,
|
-- g_in_bypass => TRUE,
|
-- g_in_dat_w => 8 * 42,
|
-- g_in_dat_w => 8 * 42,
|
-- g_in_nof_words => 1,
|
-- g_in_nof_words => 1,
|
-- g_in_symbol_w => 8,
|
-- g_in_symbol_w => 8,
|
-- g_out_bypass => FALSE,
|
-- g_out_bypass => FALSE,
|
-- g_out_dat_w => 32,
|
-- g_out_dat_w => 32,
|
-- g_out_nof_words => 11,
|
-- g_out_nof_words => 11,
|
-- g_out_symbol_w => 8
|
-- g_out_symbol_w => 8
|
-- )
|
-- )
|
-- The src_out.empty will be 2, because:
|
-- 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
|
-- (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
|
-- = (32*11 - 42*8*1)/ 8 = 2 octet symbols
|
--
|
--
|
-- Design steps:
|
-- Design steps:
|
-- * In total the development took 5 days. On day 3 I was in distress because
|
-- * 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
|
-- 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
|
-- 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 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
|
-- 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
|
-- e_pulse. Initially about 80 % of the functionality was implemented but
|
-- and subsequently each feature was verified starting with the basic
|
-- and subsequently each feature was verified starting with the basic
|
-- features and then themore detailed features. This step by step approach
|
-- 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
|
-- 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.
|
-- 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
|
-- . 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.
|
-- for different g_pkt_len <, =, > g_in_nof_words.
|
-- . Then the empty functionality for g_pkt_len MOD g_in_nof_words /= 0 was
|
-- . Then the empty functionality for g_pkt_len MOD g_in_nof_words /= 0 was
|
-- added.
|
-- added.
|
-- . Tried g_out_dat_w=1 which makes dp_repack_data a serializer/deserializer.
|
-- . 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
|
-- . 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.
|
-- 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 *
|
-- . 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
|
-- g_out_nof_words which require padding in the subsection. The > case
|
-- occurs for packing and the < case then occurs for unpacking.
|
-- 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
|
-- . Added g_bypass to force using wires instead of a void dp_repack_in or
|
-- dp_repack_out stage.
|
-- dp_repack_out stage.
|
-- . Verified g_in_symbol_w and g_out_symbol_w /= 1.
|
-- . 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
|
-- * 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
|
-- 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
|
-- c_enable_repack_in and c_enable_repack_out parameters in the tb are
|
-- useful to be able to isolate a component for debugging.
|
-- useful to be able to isolate a component for debugging.
|
|
|
LIBRARY IEEE, common_pkg_lib, dp_pkg_lib;
|
LIBRARY IEEE, common_pkg_lib, dp_pkg_lib;
|
USE IEEE.std_logic_1164.ALL;
|
USE IEEE.std_logic_1164.ALL;
|
USE common_pkg_lib.common_pkg.ALL;
|
USE common_pkg_lib.common_pkg.ALL;
|
USE dp_pkg_lib.dp_stream_pkg.ALL;
|
USE dp_pkg_lib.dp_stream_pkg.ALL;
|
|
|
ENTITY dp_repack_in IS
|
ENTITY dp_repack_in IS
|
GENERIC (
|
GENERIC (
|
g_bypass : BOOLEAN := FALSE;
|
g_bypass : BOOLEAN := FALSE;
|
g_in_dat_w : NATURAL;
|
g_in_dat_w : NATURAL;
|
g_in_nof_words : 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_in_symbol_w : NATURAL := 1 -- default 1 for snk_in.empty in nof bits, else use power of 2
|
);
|
);
|
PORT (
|
PORT (
|
rst : IN STD_LOGIC;
|
rst : IN STD_LOGIC;
|
clk : IN STD_LOGIC;
|
clk : IN STD_LOGIC;
|
|
|
snk_out : OUT t_dp_siso;
|
snk_out : OUT t_dp_siso;
|
snk_in : IN t_dp_sosi;
|
snk_in : IN t_dp_sosi;
|
|
|
src_in : IN t_dp_siso;
|
src_in : IN t_dp_siso;
|
src_out : OUT t_dp_sosi
|
src_out : OUT t_dp_sosi
|
);
|
);
|
END dp_repack_in;
|
END dp_repack_in;
|
|
|
|
|
ARCHITECTURE rtl OF dp_repack_in IS
|
ARCHITECTURE rtl OF dp_repack_in IS
|
|
|
CONSTANT c_in_buf_dat_w : NATURAL := g_in_dat_w * g_in_nof_words;
|
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_bit_cnt_max : NATURAL := c_in_buf_dat_w;
|
CONSTANT c_in_empty_lo : NATURAL := true_log2(g_in_symbol_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_dat_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
|
|
|
TYPE t_reg IS RECORD
|
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
|
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
|
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
|
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
|
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
|
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
|
pack_bit_cnt : NATURAL RANGE 0 TO c_bit_cnt_max; -- count nof bits in subsection
|
END RECORD;
|
END RECORD;
|
|
|
SIGNAL data_vec : STD_LOGIC_VECTOR(c_in_buf_dat_w-1 DOWNTO 0);
|
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_snk_out : t_dp_siso := c_dp_siso_rdy;
|
SIGNAL r : t_reg;
|
SIGNAL r : t_reg;
|
SIGNAL nxt_r : t_reg;
|
SIGNAL nxt_r : t_reg;
|
|
|
-- Debug signals
|
-- Debug signals
|
SIGNAL snk_in_data : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
|
SIGNAL snk_in_data : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
|
SIGNAL i_src_out : t_dp_sosi;
|
SIGNAL i_src_out : t_dp_sosi;
|
SIGNAL src_out_data : STD_LOGIC_VECTOR(c_in_buf_dat_w-1 DOWNTO 0);
|
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_g_in_dat_w : NATURAL := g_in_dat_w;
|
SIGNAL dbg_in_nof_words : NATURAL := g_in_nof_words;
|
SIGNAL dbg_in_nof_words : NATURAL := g_in_nof_words;
|
SIGNAL dbg_in_symbol_w : NATURAL := g_in_symbol_w;
|
SIGNAL dbg_in_symbol_w : NATURAL := g_in_symbol_w;
|
SIGNAL dbc_in_buf_dat_w : NATURAL := c_in_buf_dat_w;
|
SIGNAL dbc_in_buf_dat_w : NATURAL := c_in_buf_dat_w;
|
|
|
BEGIN
|
BEGIN
|
|
|
snk_in_data <= snk_in.data(g_in_dat_w-1 DOWNTO 0);
|
snk_in_data <= snk_in.data(g_in_dat_w-1 DOWNTO 0);
|
|
|
src_out <= i_src_out;
|
src_out <= i_src_out;
|
src_out_data <= i_src_out.data(c_in_buf_dat_w-1 DOWNTO 0);
|
src_out_data <= i_src_out.data(c_in_buf_dat_w-1 DOWNTO 0);
|
|
|
gen_bypass : IF g_bypass=TRUE GENERATE
|
gen_bypass : IF g_bypass=TRUE GENERATE
|
snk_out <= src_in;
|
snk_out <= src_in;
|
i_src_out <= snk_in;
|
i_src_out <= snk_in;
|
END GENERATE;
|
END GENERATE;
|
|
|
no_bypass : IF g_bypass=FALSE GENERATE
|
no_bypass : IF g_bypass=FALSE GENERATE
|
|
|
p_comb : PROCESS(rst, r, snk_in, data_vec, src_in)
|
p_comb : PROCESS(rst, r, snk_in, data_vec, src_in)
|
VARIABLE v : t_reg;
|
VARIABLE v : t_reg;
|
BEGIN
|
BEGIN
|
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
-- Default
|
-- Default
|
v := r;
|
v := r;
|
v.src_out.sync := '0';
|
v.src_out.sync := '0';
|
v.src_out.valid := '0';
|
v.src_out.valid := '0';
|
v.src_out.sop := '0';
|
v.src_out.sop := '0';
|
v.src_out.eop := '0';
|
v.src_out.eop := '0';
|
|
|
--------------------------------------------------------------------------
|
--------------------------------------------------------------------------
|
-- Function
|
-- Function
|
IF r.hold_out.valid='0' THEN
|
IF r.hold_out.valid='0' THEN
|
|
|
-- Clear hold_out for new output valid (= new subsection)
|
-- Clear hold_out for new output valid (= new subsection)
|
IF r.src_out.valid='1' THEN
|
IF r.src_out.valid='1' THEN
|
v.hold_out := c_dp_sosi_rst;
|
v.hold_out := c_dp_sosi_rst;
|
END IF;
|
END IF;
|
|
|
-- Capture the snk_in block info that is valid at sop and eop
|
-- Capture the snk_in block info that is valid at sop and eop
|
IF snk_in.sop='1' THEN
|
IF snk_in.sop='1' THEN
|
v.hold_out.sop := '1';
|
v.hold_out.sop := '1';
|
v.hold_out.sync := snk_in.sync;
|
v.hold_out.sync := snk_in.sync;
|
v.src_out.bsn := snk_in.bsn;
|
v.src_out.bsn := snk_in.bsn;
|
v.src_out.channel := snk_in.channel;
|
v.src_out.channel := snk_in.channel;
|
END IF;
|
END IF;
|
IF snk_in.eop='1' THEN
|
IF snk_in.eop='1' THEN
|
v.hold_out.eop := '1';
|
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.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;
|
v.src_out.err := snk_in.err;
|
END IF;
|
END IF;
|
|
|
-- Capture the data per subsection in a block
|
-- Capture the data per subsection in a block
|
IF snk_in.valid='1' OR r.flush='1' THEN
|
IF snk_in.valid='1' OR r.flush='1' THEN
|
-- shift in during block
|
-- 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
|
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
|
IF r.flush='1' THEN
|
v.dat_arr(0) := (OTHERS=>'0'); -- shift in data=0 for flush
|
v.dat_arr(0) := (OTHERS=>'0'); -- shift in data=0 for flush
|
ELSE
|
ELSE
|
v.dat_arr(0) := snk_in.data(g_in_dat_w-1 DOWNTO 0); -- shift in valid data
|
v.dat_arr(0) := snk_in.data(g_in_dat_w-1 DOWNTO 0); -- shift in valid data
|
END IF;
|
END IF;
|
|
|
-- pack subsection
|
-- pack subsection
|
IF r.pack_bit_cnt<c_in_buf_dat_w-g_in_dat_w THEN
|
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;
|
v.pack_bit_cnt := r.pack_bit_cnt + g_in_dat_w;
|
|
|
-- early end of pack subsection
|
-- early end of pack subsection
|
IF snk_in.eop='1' THEN
|
IF snk_in.eop='1' THEN
|
v.flush := '1'; -- enable flush in case eop occurs before end of pack subsection
|
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
|
v.dat_bit_cnt := v.pack_bit_cnt; -- capture the current subsection pack_bit_cnt
|
END IF;
|
END IF;
|
ELSE -- r.pack_bit_cnt=c_in_buf_dat_w-g_in_dat_w
|
ELSE -- r.pack_bit_cnt=c_in_buf_dat_w-g_in_dat_w
|
-- default end of pack subsection
|
-- default end of pack subsection
|
v.pack_bit_cnt := 0;
|
v.pack_bit_cnt := 0;
|
v.flush := '0';
|
v.flush := '0';
|
IF r.flush='0' THEN
|
IF r.flush='0' THEN
|
v.dat_bit_cnt := c_in_buf_dat_w; -- set default subsection pack_bit_cnt
|
v.dat_bit_cnt := c_in_buf_dat_w; -- set default subsection pack_bit_cnt
|
END IF;
|
END IF;
|
|
|
v.hold_out.valid := '1'; -- the function has new data to output
|
v.hold_out.valid := '1'; -- the function has new data to output
|
END IF;
|
END IF;
|
END IF;
|
END IF;
|
|
|
-- pass on the v.dat_arr as data vector
|
-- pass on the v.dat_arr as data vector
|
v.src_out.data := RESIZE_DP_DATA(data_vec);
|
v.src_out.data := RESIZE_DP_DATA(data_vec);
|
|
|
-- pass on dat_bit_cnt via DP empty field
|
-- 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);
|
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
|
-- output input stage into output stage when ready, else hold_out.valid to signal pending output
|
IF v.hold_out.valid='1' THEN
|
IF v.hold_out.valid='1' THEN
|
IF src_in.ready='1' THEN
|
IF src_in.ready='1' THEN
|
v.src_out.valid := '1';
|
v.src_out.valid := '1';
|
v.src_out.sync := v.hold_out.sync;
|
v.src_out.sync := v.hold_out.sync;
|
v.src_out.sop := v.hold_out.sop;
|
v.src_out.sop := v.hold_out.sop;
|
v.src_out.eop := v.hold_out.eop;
|
v.src_out.eop := v.hold_out.eop;
|
v.hold_out.valid := '0';
|
v.hold_out.valid := '0';
|
END IF;
|
END IF;
|
END IF;
|
END IF;
|
ELSE
|
ELSE
|
-- pending output
|
-- pending output
|
IF src_in.ready='1' THEN
|
IF src_in.ready='1' THEN
|
v.src_out.valid := '1';
|
v.src_out.valid := '1';
|
v.src_out.sync := r.hold_out.sync;
|
v.src_out.sync := r.hold_out.sync;
|
v.src_out.sop := r.hold_out.sop;
|
v.src_out.sop := r.hold_out.sop;
|
v.src_out.eop := r.hold_out.eop;
|
v.src_out.eop := r.hold_out.eop;
|
v.hold_out.valid := '0';
|
v.hold_out.valid := '0';
|
END IF;
|
END IF;
|
END IF;
|
END IF;
|
|
|
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
-- Reset and nxt_r
|
-- Reset and nxt_r
|
IF rst = '1' THEN
|
IF rst = '1' THEN
|
v.src_out := c_dp_sosi_rst;
|
v.src_out := c_dp_sosi_rst;
|
v.hold_out := c_dp_sosi_rst;
|
v.hold_out := c_dp_sosi_rst;
|
v.flush := '0';
|
v.flush := '0';
|
v.dat_bit_cnt := 0;
|
v.dat_bit_cnt := 0;
|
v.pack_bit_cnt := 0;
|
v.pack_bit_cnt := 0;
|
END IF;
|
END IF;
|
|
|
nxt_r <= v;
|
nxt_r <= v;
|
END PROCESS;
|
END PROCESS;
|
|
|
--------------------------------------------------------------------------
|
--------------------------------------------------------------------------
|
-- p_reg
|
-- p_reg
|
r <= nxt_r WHEN rising_edge(clk);
|
r <= nxt_r WHEN rising_edge(clk);
|
|
|
--------------------------------------------------------------------------
|
--------------------------------------------------------------------------
|
-- Wires
|
-- Wires
|
p_data_vec : PROCESS(nxt_r)
|
p_data_vec : PROCESS(nxt_r)
|
BEGIN
|
BEGIN
|
FOR I IN 0 TO g_in_nof_words-1 LOOP
|
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);
|
data_vec((I+1)*g_in_dat_w-1 DOWNTO I*g_in_dat_w) <= nxt_r.dat_arr(I);
|
END LOOP;
|
END LOOP;
|
END PROCESS;
|
END PROCESS;
|
|
|
--------------------------------------------------------------------------
|
--------------------------------------------------------------------------
|
-- Wired output
|
-- Wired output
|
i_src_out <= r.src_out;
|
i_src_out <= r.src_out;
|
|
|
--------------------------------------------------------------------------
|
--------------------------------------------------------------------------
|
-- Flow control
|
-- Flow control
|
|
|
-- local function flow control
|
-- local function flow control
|
p_flow : PROCESS(nxt_r)
|
p_flow : PROCESS(nxt_r)
|
BEGIN
|
BEGIN
|
r_snk_out <= c_dp_siso_rdy;
|
r_snk_out <= c_dp_siso_rdy;
|
IF nxt_r.flush='1' THEN
|
IF nxt_r.flush='1' THEN
|
r_snk_out.ready <= '0'; -- input shift in stage function is always ready except when flushing
|
r_snk_out.ready <= '0'; -- input shift in stage function is always ready except when flushing
|
END IF;
|
END IF;
|
END PROCESS;
|
END PROCESS;
|
|
|
-- combined local and remote src_in flow control
|
-- 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.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
|
snk_out.xon <= src_in.xon; -- just pass on the xon/off frame flow control
|
|
|
END GENERATE;
|
END GENERATE;
|
|
|
END rtl;
|
END rtl;
|
|
|
|
|
|
|
LIBRARY IEEE, common_pkg_lib, dp_pkg_lib;
|
LIBRARY IEEE, common_pkg_lib, dp_pkg_lib;
|
USE IEEE.std_logic_1164.ALL;
|
USE IEEE.std_logic_1164.ALL;
|
USE common_pkg_lib.common_pkg.ALL;
|
USE common_pkg_lib.common_pkg.ALL;
|
USE dp_pkg_lib.dp_stream_pkg.ALL;
|
USE dp_pkg_lib.dp_stream_pkg.ALL;
|
|
|
ENTITY dp_repack_out IS
|
ENTITY dp_repack_out IS
|
GENERIC (
|
GENERIC (
|
g_bypass : BOOLEAN := FALSE;
|
g_bypass : BOOLEAN := FALSE;
|
g_in_buf_dat_w : NATURAL;
|
g_in_buf_dat_w : NATURAL;
|
g_out_dat_w : NATURAL;
|
g_out_dat_w : NATURAL;
|
g_out_nof_words : 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
|
g_out_symbol_w : NATURAL := 1 -- default 1 for snk_in.empty in nof bits, else use power of 2
|
);
|
);
|
PORT (
|
PORT (
|
rst : IN STD_LOGIC;
|
rst : IN STD_LOGIC;
|
clk : IN STD_LOGIC;
|
clk : IN STD_LOGIC;
|
|
|
snk_out : OUT t_dp_siso;
|
snk_out : OUT t_dp_siso;
|
snk_in : IN t_dp_sosi;
|
snk_in : IN t_dp_sosi;
|
|
|
src_in : IN t_dp_siso;
|
src_in : IN t_dp_siso;
|
src_out : OUT t_dp_sosi
|
src_out : OUT t_dp_sosi
|
);
|
);
|
END dp_repack_out;
|
END dp_repack_out;
|
|
|
ARCHITECTURE rtl OF dp_repack_out IS
|
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_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_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_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_bit_cnt_max : NATURAL := c_out_buf_dat_w;
|
CONSTANT c_out_empty_lo : NATURAL := true_log2(g_out_symbol_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_dat_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
|
|
|
TYPE t_reg IS RECORD
|
TYPE t_reg IS RECORD
|
dat_arr : t_dat_arr(g_out_nof_words-1 DOWNTO 0);
|
dat_arr : t_dat_arr(g_out_nof_words-1 DOWNTO 0);
|
src_out : t_dp_sosi;
|
src_out : t_dp_sosi;
|
hold_out : t_dp_sosi; -- hold src_out valid and sync/sop/eop until src_in.ready
|
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
|
shift : STD_LOGIC; -- shift out the dat_arr
|
dat_bit_cnt : NATURAL RANGE 0 TO c_bit_cnt_max; -- actual nof bits in subsection
|
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
|
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
|
empty_bit_cnt : NATURAL RANGE 0 TO c_bit_cnt_max; -- empty nof bits in subsection
|
eos : STD_LOGIC; -- end of subsection
|
eos : STD_LOGIC; -- end of subsection
|
END RECORD;
|
END RECORD;
|
|
|
SIGNAL data_vec : STD_LOGIC_VECTOR(c_out_buf_dat_w-1 DOWNTO 0) := (OTHERS=>'0');
|
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_snk_out : t_dp_siso := c_dp_siso_rdy;
|
SIGNAL r : t_reg;
|
SIGNAL r : t_reg;
|
SIGNAL nxt_r : t_reg;
|
SIGNAL nxt_r : t_reg;
|
|
|
-- Debug signals
|
-- Debug signals
|
SIGNAL snk_in_data : STD_LOGIC_VECTOR(g_in_buf_dat_w-1 DOWNTO 0);
|
SIGNAL snk_in_data : STD_LOGIC_VECTOR(g_in_buf_dat_w-1 DOWNTO 0);
|
SIGNAL i_src_out : t_dp_sosi;
|
SIGNAL i_src_out : t_dp_sosi;
|
SIGNAL src_out_data : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
|
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_in_buf_dat_w : NATURAL := g_in_buf_dat_w;
|
SIGNAL dbg_g_out_dat_w : NATURAL := g_out_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_nof_words : NATURAL := g_out_nof_words;
|
SIGNAL dbg_out_symbol_w : NATURAL := g_out_symbol_w;
|
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_w : NATURAL := c_out_buf_dat_w;
|
SIGNAL dbc_out_buf_dat_lo : NATURAL := c_out_buf_dat_lo;
|
SIGNAL dbc_out_buf_dat_lo : NATURAL := c_out_buf_dat_lo;
|
SIGNAL dbc_snk_in_dat_lo : NATURAL := c_snk_in_dat_lo;
|
SIGNAL dbc_snk_in_dat_lo : NATURAL := c_snk_in_dat_lo;
|
|
|
BEGIN
|
BEGIN
|
|
|
snk_in_data <= snk_in.data(g_in_buf_dat_w-1 DOWNTO 0);
|
snk_in_data <= snk_in.data(g_in_buf_dat_w-1 DOWNTO 0);
|
|
|
src_out <= i_src_out;
|
src_out <= i_src_out;
|
src_out_data <= i_src_out.data(g_out_dat_w-1 DOWNTO 0);
|
src_out_data <= i_src_out.data(g_out_dat_w-1 DOWNTO 0);
|
|
|
gen_bypass : IF g_bypass=TRUE GENERATE
|
gen_bypass : IF g_bypass=TRUE GENERATE
|
snk_out <= src_in;
|
snk_out <= src_in;
|
|
|
p_src_out : PROCESS(snk_in)
|
p_src_out : PROCESS(snk_in)
|
BEGIN
|
BEGIN
|
i_src_out <= snk_in;
|
i_src_out <= snk_in;
|
IF c_snk_in_dat_lo>0 THEN
|
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.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);
|
i_src_out.empty <= INCR_UVEC( snk_in.empty, -c_snk_in_dat_lo);
|
END IF;
|
END IF;
|
IF c_out_buf_dat_lo>0 THEN
|
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.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);
|
i_src_out.empty <= INCR_UVEC( snk_in.empty, c_out_buf_dat_lo);
|
END IF;
|
END IF;
|
END PROCESS;
|
END PROCESS;
|
END GENERATE;
|
END GENERATE;
|
|
|
no_bypass : IF g_bypass=FALSE GENERATE
|
no_bypass : IF g_bypass=FALSE GENERATE
|
|
|
p_comb : PROCESS(rst, snk_in, r, data_vec, src_in)
|
p_comb : PROCESS(rst, snk_in, r, data_vec, src_in)
|
VARIABLE v : t_reg;
|
VARIABLE v : t_reg;
|
BEGIN
|
BEGIN
|
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
-- Default
|
-- Default
|
v := r;
|
v := r;
|
v.src_out.sync := '0';
|
v.src_out.sync := '0';
|
v.src_out.valid := '0';
|
v.src_out.valid := '0';
|
v.src_out.sop := '0';
|
v.src_out.sop := '0';
|
v.src_out.eop := '0';
|
v.src_out.eop := '0';
|
|
|
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
-- Function
|
-- Function
|
IF r.hold_out.valid='0' THEN
|
IF r.hold_out.valid='0' THEN
|
|
|
-- Clear hold_out for new output valid
|
-- Clear hold_out for new output valid
|
IF r.src_out.sop='1' THEN
|
IF r.src_out.sop='1' THEN
|
v.hold_out.sync := '0';
|
v.hold_out.sync := '0';
|
v.hold_out.sop := '0';
|
v.hold_out.sop := '0';
|
END IF;
|
END IF;
|
IF r.src_out.eop='1' THEN
|
IF r.src_out.eop='1' THEN
|
v.hold_out.eop := '0';
|
v.hold_out.eop := '0';
|
END IF;
|
END IF;
|
|
|
-- Capture the snk_in block info that is valid at sop and eop
|
-- Capture the snk_in block info that is valid at sop and eop
|
IF snk_in.sop='1' THEN
|
IF snk_in.sop='1' THEN
|
v.hold_out.sop := '1';
|
v.hold_out.sop := '1';
|
v.hold_out.sync := snk_in.sync;
|
v.hold_out.sync := snk_in.sync;
|
v.src_out.bsn := snk_in.bsn;
|
v.src_out.bsn := snk_in.bsn;
|
v.src_out.channel := snk_in.channel;
|
v.src_out.channel := snk_in.channel;
|
END IF;
|
END IF;
|
IF snk_in.eop='1' THEN
|
IF snk_in.eop='1' THEN
|
v.hold_out.eop := '1'; -- local function will calculate src_out.empty based on snk_in.empty
|
v.hold_out.eop := '1'; -- local function will calculate src_out.empty based on snk_in.empty
|
v.src_out.err := snk_in.err;
|
v.src_out.err := snk_in.err;
|
END IF;
|
END IF;
|
|
|
IF r.shift='1' THEN
|
IF r.shift='1' THEN
|
-- shift out rest of subsection
|
-- shift out rest of subsection
|
v.hold_out.valid := '1';
|
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(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.dat_arr(0) := (OTHERS=>'0'); -- shift in data=0
|
|
|
v.pack_bit_cnt := r.pack_bit_cnt - g_out_dat_w;
|
v.pack_bit_cnt := r.pack_bit_cnt - g_out_dat_w;
|
|
|
-- end of pack subsection
|
-- end of pack subsection
|
IF v.pack_bit_cnt<=r.empty_bit_cnt THEN
|
IF v.pack_bit_cnt<=r.empty_bit_cnt THEN
|
v.eos := '1'; -- end of subsection, so ready for new snk_in
|
v.eos := '1'; -- end of subsection, so ready for new snk_in
|
v.shift := '0'; -- stop shifting
|
v.shift := '0'; -- stop shifting
|
END IF;
|
END IF;
|
|
|
ELSIF snk_in.valid='1' THEN
|
ELSIF snk_in.valid='1' THEN
|
-- start of pack subsection
|
-- start of pack subsection
|
v.hold_out.valid := '1';
|
v.hold_out.valid := '1';
|
|
|
FOR I IN 0 TO g_out_nof_words-1 LOOP
|
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);
|
v.dat_arr(I) := data_vec((I+1)*g_out_dat_w-1 DOWNTO I*g_out_dat_w);
|
END LOOP;
|
END LOOP;
|
|
|
v.dat_bit_cnt := g_in_buf_dat_w - c_snk_in_dat_lo; -- default dat_bit_cnt per subsection
|
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
|
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
|
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;
|
END IF;
|
|
|
v.pack_bit_cnt := c_out_buf_dat_w - g_out_dat_w;
|
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.empty_bit_cnt := c_out_buf_dat_w - v.dat_bit_cnt;
|
v.eos := '0';
|
v.eos := '0';
|
v.shift := '1';
|
v.shift := '1';
|
|
|
-- end of pack subsection
|
-- end of pack subsection
|
IF v.pack_bit_cnt<=v.empty_bit_cnt THEN
|
IF v.pack_bit_cnt<=v.empty_bit_cnt THEN
|
v.eos := '1'; -- end of subsection, so ready for new snk_in
|
v.eos := '1'; -- end of subsection, so ready for new snk_in
|
v.shift := '0';
|
v.shift := '0';
|
END IF;
|
END IF;
|
END IF;
|
END IF;
|
|
|
-- fill in local empty if this is the last subsection of a block
|
-- fill in local empty if this is the last subsection of a block
|
IF v.eos='1' THEN
|
IF v.eos='1' THEN
|
IF v.hold_out.eop='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 := 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
|
v.src_out.empty := SHIFT_UVEC(v.src_out.empty, c_out_empty_lo); -- in nof symbols
|
END IF;
|
END IF;
|
END IF;
|
END IF;
|
|
|
-- pass on the v.dat_arr as data vector
|
-- pass on the v.dat_arr as data vector
|
v.src_out.data := RESIZE_DP_DATA(v.dat_arr(g_out_nof_words-1));
|
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
|
-- output valid data when ready, else hold_out.valid to signal pending output
|
IF v.hold_out.valid='1' THEN
|
IF v.hold_out.valid='1' THEN
|
IF src_in.ready='1' THEN
|
IF src_in.ready='1' THEN
|
v.src_out.valid := '1';
|
v.src_out.valid := '1';
|
v.src_out.sync := v.hold_out.sync;
|
v.src_out.sync := v.hold_out.sync;
|
v.src_out.sop := v.hold_out.sop;
|
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.src_out.eop := v.hold_out.eop AND v.eos; -- output eop at end of subsection
|
v.hold_out.valid := '0';
|
v.hold_out.valid := '0';
|
END IF;
|
END IF;
|
END IF;
|
END IF;
|
|
|
ELSE
|
ELSE
|
-- pending output
|
-- pending output
|
IF src_in.ready='1' THEN
|
IF src_in.ready='1' THEN
|
v.src_out.valid := '1';
|
v.src_out.valid := '1';
|
v.src_out.sync := r.hold_out.sync;
|
v.src_out.sync := r.hold_out.sync;
|
v.src_out.sop := r.hold_out.sop;
|
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.src_out.eop := r.hold_out.eop AND r.eos; -- output eop at end of subsection
|
v.hold_out.valid := '0';
|
v.hold_out.valid := '0';
|
END IF;
|
END IF;
|
END IF;
|
END IF;
|
|
|
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
-- Reset and nxt_r
|
-- Reset and nxt_r
|
IF rst = '1' THEN
|
IF rst = '1' THEN
|
v.src_out := c_dp_sosi_rst;
|
v.src_out := c_dp_sosi_rst;
|
v.hold_out := c_dp_sosi_rst;
|
v.hold_out := c_dp_sosi_rst;
|
v.shift := '0';
|
v.shift := '0';
|
v.dat_bit_cnt := 0;
|
v.dat_bit_cnt := 0;
|
v.pack_bit_cnt := 0;
|
v.pack_bit_cnt := 0;
|
v.empty_bit_cnt := 0;
|
v.empty_bit_cnt := 0;
|
v.eos := '0';
|
v.eos := '0';
|
END IF;
|
END IF;
|
|
|
nxt_r <= v;
|
nxt_r <= v;
|
END PROCESS;
|
END PROCESS;
|
|
|
--------------------------------------------------------------------------
|
--------------------------------------------------------------------------
|
-- p_reg
|
-- p_reg
|
r <= nxt_r WHEN rising_edge(clk);
|
r <= nxt_r WHEN rising_edge(clk);
|
|
|
--------------------------------------------------------------------------
|
--------------------------------------------------------------------------
|
-- Wires
|
-- 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);
|
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
|
-- Wired output
|
i_src_out <= r.src_out;
|
i_src_out <= r.src_out;
|
|
|
--------------------------------------------------------------------------
|
--------------------------------------------------------------------------
|
-- Flow control
|
-- Flow control
|
|
|
-- local function flow control
|
-- local function flow control
|
p_flow : PROCESS(nxt_r)
|
p_flow : PROCESS(nxt_r)
|
BEGIN
|
BEGIN
|
r_snk_out <= c_dp_siso_rdy;
|
r_snk_out <= c_dp_siso_rdy;
|
IF nxt_r.shift='1' AND nxt_r.eos='0' THEN
|
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
|
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 IF;
|
END PROCESS;
|
END PROCESS;
|
|
|
-- combined local and remote src_in flow control
|
-- 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.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
|
snk_out.xon <= src_in.xon; -- just pass on the xon/off frame flow control
|
|
|
END GENERATE;
|
END GENERATE;
|
|
|
END rtl;
|
END rtl;
|
|
|
|
|
|
|
LIBRARY IEEE, common_pkg_lib, dp_pkg_lib;
|
LIBRARY IEEE, common_pkg_lib, dp_pkg_lib;
|
USE IEEE.std_logic_1164.ALL;
|
USE IEEE.std_logic_1164.ALL;
|
USE common_pkg_lib.common_pkg.ALL;
|
USE common_pkg_lib.common_pkg.ALL;
|
USE dp_pkg_lib.dp_stream_pkg.ALL;
|
USE dp_pkg_lib.dp_stream_pkg.ALL;
|
|
|
ENTITY dp_repack_data IS
|
ENTITY dp_repack_data IS
|
GENERIC (
|
GENERIC (
|
g_enable_repack_in : BOOLEAN := TRUE;
|
g_enable_repack_in : BOOLEAN := TRUE;
|
g_enable_repack_out : BOOLEAN := TRUE;
|
g_enable_repack_out : BOOLEAN := TRUE;
|
g_in_bypass : BOOLEAN := FALSE;
|
g_in_bypass : BOOLEAN := FALSE;
|
g_in_dat_w : NATURAL;
|
g_in_dat_w : NATURAL;
|
g_in_nof_words : 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_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_bypass : BOOLEAN := FALSE;
|
g_out_dat_w : NATURAL;
|
g_out_dat_w : NATURAL;
|
g_out_nof_words : 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
|
g_out_symbol_w : NATURAL := 1 -- default 1 for src_out.empty in nof bits, else use power of 2
|
);
|
);
|
PORT (
|
PORT (
|
rst : IN STD_LOGIC;
|
rst : IN STD_LOGIC;
|
clk : IN STD_LOGIC;
|
clk : IN STD_LOGIC;
|
|
|
snk_out : OUT t_dp_siso;
|
snk_out : OUT t_dp_siso;
|
snk_in : IN t_dp_sosi;
|
snk_in : IN t_dp_sosi;
|
|
|
src_in : IN t_dp_siso := c_dp_siso_rdy;
|
src_in : IN t_dp_siso := c_dp_siso_rdy;
|
src_out : OUT t_dp_sosi
|
src_out : OUT t_dp_sosi
|
);
|
);
|
END dp_repack_data;
|
END dp_repack_data;
|
|
|
|
|
ARCHITECTURE str OF dp_repack_data IS
|
ARCHITECTURE str OF dp_repack_data IS
|
|
|
CONSTANT c_in_buf_dat_w : NATURAL := g_in_dat_w * g_in_nof_words;
|
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 snk_in_data : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
|
SIGNAL i_snk_out : t_dp_siso;
|
SIGNAL i_snk_out : t_dp_siso;
|
|
|
SIGNAL pack_siso : t_dp_siso;
|
SIGNAL pack_siso : t_dp_siso;
|
SIGNAL pack_sosi : t_dp_sosi;
|
SIGNAL pack_sosi : t_dp_sosi;
|
SIGNAL pack_sosi_data : STD_LOGIC_VECTOR(c_in_buf_dat_w-1 DOWNTO 0);
|
SIGNAL pack_sosi_data : STD_LOGIC_VECTOR(c_in_buf_dat_w-1 DOWNTO 0);
|
|
|
SIGNAL i_src_out : t_dp_sosi;
|
SIGNAL i_src_out : t_dp_sosi;
|
SIGNAL src_out_data : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
|
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 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);
|
SIGNAL pack_ready_reg : STD_LOGIC_VECTOR(0 TO c_dp_stream_rl);
|
|
|
BEGIN
|
BEGIN
|
|
|
snk_out <= i_snk_out;
|
snk_out <= i_snk_out;
|
src_out <= i_src_out;
|
src_out <= i_src_out;
|
|
|
snk_in_data <= snk_in.data(g_in_dat_w-1 DOWNTO 0);
|
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);
|
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);
|
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
|
no_dp_repack_in : IF g_enable_repack_in=FALSE GENERATE
|
i_snk_out <= pack_siso;
|
i_snk_out <= pack_siso;
|
pack_sosi <= snk_in;
|
pack_sosi <= snk_in;
|
END GENERATE;
|
END GENERATE;
|
|
|
gen_dp_repack_in : IF g_enable_repack_in=TRUE GENERATE
|
gen_dp_repack_in : IF g_enable_repack_in=TRUE GENERATE
|
u_dp_repack_in : ENTITY work.dp_repack_in
|
u_dp_repack_in : ENTITY work.dp_repack_in
|
GENERIC MAP (
|
GENERIC MAP (
|
g_bypass => g_in_bypass,
|
g_bypass => g_in_bypass,
|
g_in_dat_w => g_in_dat_w,
|
g_in_dat_w => g_in_dat_w,
|
g_in_nof_words => g_in_nof_words,
|
g_in_nof_words => g_in_nof_words,
|
g_in_symbol_w => g_in_symbol_w
|
g_in_symbol_w => g_in_symbol_w
|
)
|
)
|
PORT MAP (
|
PORT MAP (
|
rst => rst,
|
rst => rst,
|
clk => clk,
|
clk => clk,
|
|
|
snk_out => i_snk_out,
|
snk_out => i_snk_out,
|
snk_in => snk_in,
|
snk_in => snk_in,
|
|
|
src_in => pack_siso,
|
src_in => pack_siso,
|
src_out => pack_sosi
|
src_out => pack_sosi
|
);
|
);
|
END GENERATE;
|
END GENERATE;
|
|
|
no_dp_repack_out : IF g_enable_repack_out=FALSE GENERATE
|
no_dp_repack_out : IF g_enable_repack_out=FALSE GENERATE
|
pack_siso <= src_in;
|
pack_siso <= src_in;
|
i_src_out <= pack_sosi;
|
i_src_out <= pack_sosi;
|
END GENERATE;
|
END GENERATE;
|
|
|
gen_dp_repack_out : IF g_enable_repack_out=TRUE GENERATE
|
gen_dp_repack_out : IF g_enable_repack_out=TRUE GENERATE
|
u_dp_repack_out : ENTITY work.dp_repack_out
|
u_dp_repack_out : ENTITY work.dp_repack_out
|
GENERIC MAP (
|
GENERIC MAP (
|
g_bypass => g_out_bypass,
|
g_bypass => g_out_bypass,
|
g_in_buf_dat_w => c_in_buf_dat_w,
|
g_in_buf_dat_w => c_in_buf_dat_w,
|
g_out_dat_w => g_out_dat_w,
|
g_out_dat_w => g_out_dat_w,
|
g_out_nof_words => g_out_nof_words,
|
g_out_nof_words => g_out_nof_words,
|
g_out_symbol_w => g_out_symbol_w
|
g_out_symbol_w => g_out_symbol_w
|
)
|
)
|
PORT MAP (
|
PORT MAP (
|
rst => rst,
|
rst => rst,
|
clk => clk,
|
clk => clk,
|
|
|
snk_out => pack_siso,
|
snk_out => pack_siso,
|
snk_in => pack_sosi,
|
snk_in => pack_sosi,
|
|
|
src_in => src_in,
|
src_in => src_in,
|
src_out => i_src_out
|
src_out => i_src_out
|
);
|
);
|
END GENERATE;
|
END GENERATE;
|
|
|
-- Simulation only: internal stream RL verification
|
-- 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, snk_in, i_snk_out, snk_out_ready_reg);
|
proc_dp_siso_alert(clk, pack_sosi, pack_siso, pack_ready_reg);
|
proc_dp_siso_alert(clk, pack_sosi, pack_siso, pack_ready_reg);
|
|
|
END str;
|
END str;
|
|
|