OpenCores
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;
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.