Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
reorder_row.vhd 9.89 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: Subband Select Reordering.
--
-- Description: For every clock cycle within a frame a different output
--              configuration can be created, based on the available inputs.
--
--              The selection buffer stores a set of selection words. Each
--              selection word defines the mapping of the inputs to the outputs
--              for a single clock cylce.
--
-- Remarks:
--

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_row is
  generic (
    g_dsp_data_w    : natural := 16;
    g_frame_size    : natural := 256;
    g_nof_inputs    : natural := 8;
    g_nof_outputs   : natural := 16;
    g_use_complex   : boolean := true;
    g_ram_init_file : string  := "../../../src/data/select_buf";  -- or "UNUSED"
    g_pipeline_in   : natural := 1;  -- pipeline in_data
    g_pipeline_in_m : natural := 1;  -- pipeline in_data for M-fold fan out
    g_pipeline_out  : natural := 1  -- pipeline out_data
  );
  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_reorder_mosi : in  t_mem_mosi;
    ram_ss_reorder_miso : out t_mem_miso;

    -- Streaming
    input_sosi_arr      : in  t_dp_sosi_arr(g_nof_inputs - 1  downto 0);
    output_sosi_arr     : out t_dp_sosi_arr(g_nof_outputs - 1 downto 0);
    output_siso_arr     : in  t_dp_siso_arr(g_nof_outputs - 1 downto 0) := (others => c_dp_siso_rdy)
  );
end reorder_row;

architecture str of reorder_row is

  constant c_sel_buf_read_lat    : natural := 1;  -- Latency introduced by the counter.
  constant c_tot_pipeline        : natural := g_pipeline_in + g_pipeline_in_m + g_pipeline_out + c_sel_buf_read_lat;

  constant c_select_w            : natural := ceil_log2(g_nof_inputs);
  constant c_select_word_w       : natural := c_select_w * g_nof_outputs;
  constant c_select_dat_w_mm     : natural := sel_a_b(c_select_word_w <= c_word_w, c_select_word_w, c_word_w);

  constant c_nof_mm_regs_per_sel : natural := 2**(true_log2(ceil_div(c_select_word_w, c_word_w)));

  constant c_mem_nof_dat_mm      : natural := 2**(true_log2(c_nof_mm_regs_per_sel)) * g_frame_size;
  constant c_mem_dat_w_mm        : natural := 2**(true_log2(c_select_dat_w_mm));
  constant c_mem_dat_w_dp        : natural := 2**(true_log2(c_select_word_w));

  constant c_select_buf_mm    : t_c_mem := (latency  => 1,
                                            adr_w    => ceil_log2(c_mem_nof_dat_mm),
                                            dat_w    => c_mem_dat_w_mm,
                                            nof_dat  => c_mem_nof_dat_mm,
                                            init_sl  => '0');


  constant c_select_buf_dp    : t_c_mem := (latency  => 1,
                                            adr_w    => ceil_log2(g_frame_size),
                                            dat_w    => c_mem_dat_w_dp,
                                            nof_dat  => g_frame_size,
                                            init_sl  => '0');

  constant c_data_w           : natural := g_dsp_data_w * c_nof_complex;
  constant c_mem_ratio_w      : natural := c_mem_dat_w_dp / c_mem_dat_w_mm;

  type t_dp_sosi_2arr is array (integer range <>) of t_dp_sosi_arr(g_nof_inputs - 1 downto 0);

  type reg_type is record
    pipe_sosi_2arr  : t_dp_sosi_2arr(c_tot_pipeline-1 downto 0);
    output_sosi_arr : t_dp_sosi_arr(g_nof_outputs - 1   downto 0);
  end record;

  signal r, rin             : reg_type;

  signal reorder_in_dat     : std_logic_vector(g_nof_inputs * c_data_w - 1 downto 0);
  signal reorder_out_dat    : std_logic_vector(g_nof_outputs * c_data_w - 1 downto 0);
  signal reorder_select     : std_logic_vector(c_mem_dat_w_dp - 1 downto 0);
  --SIGNAL reorder_select     : STD_LOGIC_VECTOR(g_nof_outputs*c_select_w-1 DOWNTO 0);
  signal reorder_chan_cnt   : std_logic_vector(c_select_buf_dp.adr_w - 1 downto 0);

begin
  ---------------------------------------------------------------
  -- PREPARE THE INPUT DATA.
  --
  -- Use a delayed version of the input data to correct for the
  -- delay that is introduced by the read latency of the
  -- selection buffer.
  ---------------------------------------------------------------
  gen_input : for I in g_nof_inputs - 1 downto 0 generate
    use_complex : if g_use_complex generate
      reorder_in_dat((I + 1) * c_data_w - 1 downto I * c_data_w) <=
        r.pipe_sosi_2arr(0)(I).im(g_dsp_data_w - 1 downto 0) &
        r.pipe_sosi_2arr(0)(I).re(g_dsp_data_w - 1 downto 0);
    end generate;
   use_data : if not g_use_complex generate
      reorder_in_dat((I + 1) * c_data_w - 1 downto I * c_data_w) <=
        r.pipe_sosi_2arr(0)(I).data(c_data_w - 1 downto 0);
    end generate;
  end generate;

  ---------------------------------------------------------------
  -- EXECUTE SELECTION
  --
  -- Selection is performed based on the setting of the
  -- reorder_select signal.
  ---------------------------------------------------------------
  u_reorder : entity common_lib.common_select_m_symbols
  generic map (
    g_nof_input     => g_nof_inputs,
    g_nof_output    => g_nof_outputs,
    g_symbol_w      => c_nof_complex * g_dsp_data_w,
    g_pipeline_in   => g_pipeline_in,
    g_pipeline_in_m => g_pipeline_in_m,
    g_pipeline_out  => g_pipeline_out
  )
  port map (
    rst        => dp_rst,
    clk        => dp_clk,
    in_data    => reorder_in_dat,
    in_select  => reorder_select(g_nof_outputs * c_select_w - 1 downto 0),
    out_data   => reorder_out_dat
  );

  ---------------------------------------------------------------
  -- SELECTION BUFFER
  --
  -- Buffer containing the selection words for a complete frame.
  ---------------------------------------------------------------
  u_select_buf : entity common_lib.common_ram_crw_crw_ratio
  generic map(
    g_ram_a     => c_select_buf_mm,
    g_ram_b     => c_select_buf_dp,
    g_init_file => g_ram_init_file
  )
  port map (
    rst_a     => mm_rst,
    clk_a     => mm_clk,
    wr_en_a   => ram_ss_reorder_mosi.wr,
    wr_dat_a  => ram_ss_reorder_mosi.wrdata(c_select_buf_mm.dat_w - 1 downto 0),
    adr_a     => ram_ss_reorder_mosi.address(c_select_buf_mm.adr_w - 1 downto 0),
    rd_en_a   => ram_ss_reorder_mosi.rd,
    rd_dat_a  => ram_ss_reorder_miso.rddata(c_select_buf_mm.dat_w - 1 downto 0),
    rd_val_a  => ram_ss_reorder_miso.rdval,

    rst_b     => dp_rst,
    clk_b     => dp_clk,
    wr_en_b   => '0',
    wr_dat_b  => (others => '0'),
    adr_b     => reorder_chan_cnt,
    rd_dat_b  => reorder_select,
    rd_val_b  => open
  );

  ---------------------------------------------------------------
  -- ADDRESS COUNTER
  --
  -- Counter that addresses the selection buffer
  ---------------------------------------------------------------
  gen_cnt : if g_frame_size > 1 generate
    u_adr_chn_cnt : entity common_lib.common_counter
    generic map(
      g_latency   => 1,
      g_init      => 0,
      g_width     => c_select_buf_dp.adr_w,
      g_max       => g_frame_size
    )
    port map (
      rst     => dp_rst,
      clk     => dp_clk,
      cnt_en  => input_sosi_arr(0).valid,
      cnt_clr => input_sosi_arr(0).eop,
      count   => reorder_chan_cnt
    );
  end generate;
  gen_no_cnt : if g_frame_size = 1 generate
    reorder_chan_cnt <= (others => '0');
  end generate;

  ---------------------------------------------------------------
  -- REGISTERING AND PIPELINING
  --
  -- This process takes care of registering the incoming SOSI
  -- array and the pipelining for all SOSI control fields.
  -- Also the data-output of the select_m_symbols block is merged
  -- here with the rest of the pipelined SOSI signals.
  ---------------------------------------------------------------
   comb : process(r, input_sosi_arr, reorder_out_dat)
    variable v : reg_type;
    -- Use intermediate variables to avoid too long code lines
    variable v_re : std_logic_vector(g_dsp_data_w - 1 downto 0);
    variable v_im : std_logic_vector(g_dsp_data_w - 1 downto 0);
  begin
    v                      := r;
    v.pipe_sosi_2arr(0)    := input_sosi_arr;
    v.pipe_sosi_2arr(c_tot_pipeline-1 downto 1) := r.pipe_sosi_2arr(c_tot_pipeline-2 downto 0);

    -- Merge data output to the outgoing SOSI record.
    -- Assigning re,im is don't care when g_use_complex is false.
    for I in g_nof_outputs - 1 downto 0 loop
      v_im := reorder_out_dat((I + 1) * c_data_w - 1                downto I * c_data_w + g_dsp_data_w);
      v_re := reorder_out_dat((I + 1) * c_data_w - g_dsp_data_w - 1 downto I * c_data_w);
      v.output_sosi_arr(I)    := r.pipe_sosi_2arr(c_tot_pipeline-1)(0);
      v.output_sosi_arr(I).im := RESIZE_DP_DSP_DATA(v_im);
      v.output_sosi_arr(I).re := RESIZE_DP_DSP_DATA(v_re);
    end loop;

    rin             <= v;
  end process comb;

  regs : process(dp_clk)
  begin
    if rising_edge(dp_clk) then
      r <= rin;
    end if;
  end process;

  output_sosi_arr <= r.output_sosi_arr;

end str;