Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
reorder_col.vhd 10.65 KiB
-------------------------------------------------------------------------------
--
-- Copyright (C) 2011
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- 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
-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
--
-------------------------------------------------------------------------------

-- Purpose: Reorder packet
-- Description:
--   Select g_nof_ch_sel complex samples from an input block of g_nof_ch_in
--   complex samples. The subband select map is arbitrary (any order and also
--   duplicates) and can be set via the MM interface.
--   The timing of sync and BSN is passed on in parallel.
-- Remarks:
-- . The g_nof_ch_sel can be <= g_nof_ch_in <= period size, where g_nof_ch_in
--   is the number of valid samples from sop to eop. If g_nof_ch_in is equal to
--   the period size then there are no data invalid cycles during a period.
--   Note that if g_nof_ch_in is less than the period size, then g_nof_ch_sel
--   can be larger than g_nof_ch_in to select channels multiple times.
-- . The g_nof_ch_in defines the number of complex input data words in a data
--   period. In LOFAR a subband sample was defined as a dual pol subband, so a
--   pair of complex samples, but here instead the subband is defined as a
--   single signal path sample, so 1 complex sample via sosi.im and sosi.re.
-- . In LOFAR the channel select buffer was dual page, to ensure that the page
--   switch happens aligned with the sync. However typically the select buffer
--   only needs to be set once and remains fixed during a measurement.
--   Therefore the channel select buffer can be a single page memory.
-- . In LOFAR the selected channels were also output time multiplexed. This
--   was possible because g_nof_ch_sel <= g_nof_ch_in/2. Here the output is not
--   time multiplexed. If time multiplexing is needed then a separate component
--   needs to be used for this. For this purpose the reorder_retrieve streaming
--   source supports the ready signal. Typically output_siso.ready='1', but
--   when g_nof_ch_sel < g_nof_ch_in/2, then a toggling output_siso.ready can
--   be used to multiplex this reorder_col output with another reorder_col output stream.
-- . The reorder_col streaming sink does not support the input_siso signal, because it
--   is assumed that the reorder_col source is always fast enough. The reorder_col sink could
--   support the input_siso signal, e.g. based on store_done and retrieve_done.

library IEEE, common_lib, dp_lib;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use common_lib.common_pkg.all;
use common_lib.common_mem_pkg.all;
use dp_lib.dp_stream_pkg.all;

entity reorder_col is
  generic (
    -- when true adapt output RL to 1 else the output RL is equal to c_retrieve_lat=2 which
    -- is fine if no flow control is needed.
    g_use_output_rl_adapter : boolean := false;
    g_dsp_data_w            : natural := 18;  -- complex data width, = c_data_w / 2
    g_nof_ch_in             : natural := 512;
    g_nof_ch_sel            : natural := 252;  -- g_nof_ch_sel < g_nof_ch_in
    g_select_file_name      : string  := "UNUSED";
    g_use_complex           : boolean := true
  );
  port (
    mm_rst         : in  std_logic;
    mm_clk         : in  std_logic;
    dp_rst         : in  std_logic;
    dp_clk         : in  std_logic;

    -- Memory Mapped
    ram_ss_ss_mosi : in  t_mem_mosi;  -- channel select control
    ram_ss_ss_miso : out t_mem_miso;

    -- Streaming
    input_sosi     : in  t_dp_sosi;  -- complex input
    input_siso     : out t_dp_siso;  -- complex input

    output_sosi    : out t_dp_sosi;  -- selected complex output with flow control
    output_siso    : in  t_dp_siso := c_dp_siso_rdy
  );
end reorder_col;

architecture str of reorder_col is

  constant c_data_w         : natural := c_nof_complex * g_dsp_data_w;
  constant c_store_buf      : t_c_mem := (latency  => 1,
                                          adr_w    => ceil_log2(g_nof_ch_in),
                                          dat_w    => c_data_w,
                                          nof_dat  => g_nof_ch_in,
                                          init_sl  => '0');  -- ST side : stat_mosi

  constant c_select_buf     : t_c_mem := (latency  => 1,
                                          adr_w    => ceil_log2(g_nof_ch_sel),
                                          dat_w    => ceil_log2(g_nof_ch_in),
                                          nof_dat  => g_nof_ch_sel,
                                          init_sl  => '0');

  constant c_data_nof_pages       : natural := 2;  -- fixed dual page SS
  constant c_info_nof_pages       : natural := 2;  -- fixed, fits the dual page block latency and logic latency of the SS

  constant c_retrieve_lat         : natural := c_select_buf.latency + c_store_buf.latency;  -- = 2
  -- force output ready latency (RL) from 2 -> 1 or leave it at 2
  constant c_output_rl            : natural := sel_a_b(g_use_output_rl_adapter, 1, c_retrieve_lat);

  signal info_sop_wr_en   : std_logic_vector(c_info_nof_pages - 1 downto 0);
  signal info_eop_wr_en   : std_logic_vector(c_info_nof_pages - 1 downto 0);
  signal info_sosi        : t_dp_sosi;

  signal store_mosi       : t_mem_mosi;
  signal store_done       : std_logic;

  signal retrieve_mosi    : t_mem_mosi := c_mem_mosi_rst;
  signal retrieve_miso    : t_mem_miso := c_mem_miso_rst;
  signal retrieve_done    : std_logic;

  signal select_mosi      : t_mem_mosi := c_mem_mosi_rst;
  signal select_miso      : t_mem_miso := c_mem_miso_rst;

  signal retrieve_sosi    : t_dp_sosi;
  signal retrieve_siso    : t_dp_siso;

  signal ss_sosi          : t_dp_sosi;
  signal ss_siso          : t_dp_siso;

begin

  -----------------------------------------------------------------------------
  -- Throttle the incoming streams so they provide a consistent packet flow
  -- (no bursting) by enforcing a minimum period of g_nof_ch_sel
  -----------------------------------------------------------------------------
  u_dp_throttle_sop : entity dp_lib.dp_throttle_sop
  generic map (
    g_period    => g_nof_ch_sel
  )
  port map (
    rst         => dp_rst,
    clk         => dp_clk,
    snk_out     => input_siso,
    snk_in      => input_sosi
  );

  u_store : entity work.reorder_store
  generic map (
    g_dsp_data_w  => g_dsp_data_w,
    g_nof_ch_in   => g_nof_ch_in,
    g_use_complex => g_use_complex
  )
  port map (
    rst           => dp_rst,
    clk           => dp_clk,

    -- Streaming
    input_sosi    => input_sosi,
    -- Timing
    store_done    => store_done,
    -- Write store buffer control
    store_mosi    => store_mosi
  );

  u_store_buf : entity common_lib.common_paged_ram_r_w
  generic map (
    g_str             => "use_adr",
    g_data_w          => c_store_buf.dat_w,
    g_nof_pages       => c_data_nof_pages,
    g_page_sz         => c_store_buf.nof_dat,
    g_wr_start_page   => 0,
    g_rd_start_page   => 0,
    g_rd_latency      => 1
  )
  port map (
    rst          => dp_rst,
    clk          => dp_clk,
    wr_next_page => store_done,
    wr_adr       => store_mosi.address(c_store_buf.adr_w - 1 downto 0),
    wr_en        => store_mosi.wr,
    wr_dat       => store_mosi.wrdata(c_store_buf.dat_w - 1 downto 0),
    rd_next_page => retrieve_done,
    rd_adr       => retrieve_mosi.address(c_store_buf.adr_w - 1 downto 0),
    rd_en        => retrieve_mosi.rd,
    rd_dat       => retrieve_miso.rddata(c_store_buf.dat_w - 1 downto 0),
    rd_val       => retrieve_miso.rdval
  );

  u_select_buf : entity common_lib.common_ram_crw_crw
  generic map (
    g_ram        => c_select_buf,
    g_init_file  => g_select_file_name
  )
  port map (
    -- MM side
    rst_a     => mm_rst,
    clk_a     => mm_clk,
    wr_en_a   => ram_ss_ss_mosi.wr,
    wr_dat_a  => ram_ss_ss_mosi.wrdata(c_select_buf.dat_w - 1 downto 0),
    adr_a     => ram_ss_ss_mosi.address(c_select_buf.adr_w - 1 downto 0),
    rd_en_a   => ram_ss_ss_mosi.rd,
    rd_dat_a  => ram_ss_ss_miso.rddata(c_select_buf.dat_w - 1 downto 0),
    rd_val_a  => ram_ss_ss_miso.rdval,
    -- ST side
    rst_b     => dp_rst,
    clk_b     => dp_clk,
    wr_en_b   => select_mosi.wr,
    wr_dat_b  => select_mosi.wrdata(c_select_buf.dat_w - 1 downto 0),
    adr_b     => select_mosi.address(c_select_buf.adr_w - 1 downto 0),
    rd_en_b   => select_mosi.rd,
    rd_dat_b  => select_miso.rddata(c_select_buf.dat_w - 1 downto 0),
    rd_val_b  => select_miso.rdval
  );

  u_retrieve : entity work.reorder_retrieve
  generic map (
    g_dsp_data_w   => g_dsp_data_w,
    g_nof_ch_in    => g_nof_ch_in,
    g_nof_ch_sel   => g_nof_ch_sel
  )
  port map (
    rst            => dp_rst,
    clk            => dp_clk,

    -- Timing
    store_done     => store_done,

    -- Read store_buf control
    retrieve_mosi  => retrieve_mosi,
    retrieve_miso  => retrieve_miso,
    retrieve_done  => retrieve_done,

    -- Read select_buf control
    select_mosi    => select_mosi,
    select_miso    => select_miso,

    -- Streaming
    output_sosi    => retrieve_sosi,
    output_siso    => retrieve_siso
  );

  u_rl : entity dp_lib.dp_latency_adapter  -- defaults to wires when c_output_rl = c_retrieve_lat
  generic map (
    g_in_latency   => c_retrieve_lat,
    g_out_latency  => c_output_rl
  )
  port map (
    rst          => dp_rst,
    clk          => dp_clk,
    -- ST sink
    snk_out      => retrieve_siso,
    snk_in       => retrieve_sosi,
    -- ST source
    src_in       => ss_siso,
    src_out      => ss_sosi
  );

  -- Page delay the input_sosi info (sync, BSN, channel at sop and err, empty at eop) and combine
  -- it with the retrieved SS data to get the output_sosi.
  info_sop_wr_en <= input_sosi.sop & store_done;
  info_eop_wr_en <= input_sosi.eop & store_done;

  u_info_sosi : entity dp_lib.dp_paged_sop_eop_reg
  generic map (
    g_nof_pages  => c_info_nof_pages
  )
  port map (
    rst         => dp_rst,
    clk         => dp_clk,
    -- page write enable ctrl
    sop_wr_en   => info_sop_wr_en,
    eop_wr_en   => info_eop_wr_en,
    -- ST sink
    snk_in      => input_sosi,
    -- ST source
    src_out     => info_sosi
  );
  output_sosi <= func_dp_stream_combine_info_and_data(info_sosi, ss_sosi);
  ss_siso     <= output_siso;

end str;