Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ring_rx.vhd 8.76 KiB
-------------------------------------------------------------------------------
--
-- Copyright 2021
-- 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.
--
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
--
-- Author: R. van der Walle

-- Purpose: Handle RX side of ring design.
-- Description: See https://support.astron.nl/confluence/x/jyu7Ag

-------------------------------------------------------------------------------

library IEEE, common_lib, mm_lib, dp_lib;
use IEEE.std_logic_1164.all;
use common_lib.common_pkg.all;
use common_lib.common_mem_pkg.all;
use common_lib.common_field_pkg.all;
use dp_lib.dp_stream_pkg.all;
use work.ring_pkg.all;

entity ring_rx is
  generic (
    g_use_dp_layer        : boolean := true;
    g_lane_direction      : natural := 1;
    g_total_nof_packets_w : natural := 48;  -- <= c_longword_w = 64
    g_data_w              : natural := 64;
    g_nof_rx_monitors     : natural := 1;
    g_err_bi              : natural := 0;
    g_block_size          : natural := 1024;
    g_nof_err_counts      : natural := 1;
    g_check_channel       : natural := 1;
    g_sync_timeout        : natural := 220 * 10**6  -- 10% margin
  );
  port (
    -- Clocks and reset
    mm_rst                  : in  std_logic;  -- reset synchronous with mm_clk
    mm_clk                  : in  std_logic;  -- memory-mapped bus clock

    dp_clk                  : in  std_logic;
    dp_rst                  : in  std_logic;

    from_lane_sosi          : out t_dp_sosi;
    lane_rx_cable_sosi      : in  t_dp_sosi;
    lane_rx_board_sosi      : in  t_dp_sosi;
    bs_sosi                 : in  t_dp_sosi;

    reg_bsn_monitor_v2_copi                : in  t_mem_copi;
    reg_bsn_monitor_v2_cipo                : out t_mem_cipo;
    reg_dp_block_validate_err_copi         : in  t_mem_copi;
    reg_dp_block_validate_err_cipo         : out t_mem_cipo;
    reg_dp_block_validate_bsn_at_sync_copi : in  t_mem_copi;
    reg_dp_block_validate_bsn_at_sync_cipo : out t_mem_cipo;
    ref_sync  : in  std_logic;
    rx_select : in  std_logic;
    this_rn   : in  std_logic_vector(c_byte_w - 1 downto 0);
    N_rn      : in  std_logic_vector(c_byte_w - 1 downto 0)
  );
end ring_rx;

architecture str of ring_rx is
  constant c_nof_hdr_fields : natural := sel_a_b(g_use_dp_layer, c_ring_dp_nof_hdr_fields, c_ring_eth_nof_hdr_fields);
  constant c_hdr_field_arr  : t_common_field_arr(c_nof_hdr_fields - 1 downto 0) := sel_a_b(g_use_dp_layer, c_ring_dp_hdr_field_arr, c_ring_eth_hdr_field_arr);
  constant c_hdr_field_size : natural := sel_a_b(g_use_dp_layer, c_ring_dp_hdr_field_size, c_ring_eth_hdr_field_size);
  constant c_packet_size    : natural := g_block_size + c_hdr_field_size;

  signal lane_rx_sosi       : t_dp_sosi;
  signal packet_sosi        : t_dp_sosi;
  signal validated_sosi     : t_dp_sosi;
  signal offload_rx_sosi    : t_dp_sosi;
  signal decoded_sosi       : t_dp_sosi;
  signal monitor_sosi       : t_dp_sosi;
  signal piped_monitor_sosi : t_dp_sosi;
  signal demux_sosi_arr     : t_dp_sosi_arr(0 to g_nof_rx_monitors - 1);  -- using 0 TO ... as that is the output of the demux
  signal monitor_sosi_arr   : t_dp_sosi_arr(g_nof_rx_monitors - 1 downto 0);

  signal hdr_fields_out   : std_logic_vector(1023 downto 0);
  signal hdr_fields_raw   : std_logic_vector(1023 downto 0);
begin
  -- Select input based on rx_select
  lane_rx_sosi <= lane_rx_cable_sosi when rx_select = '1' else lane_rx_board_sosi;

  -- Validate length
  u_dp_block_validate_length : entity dp_lib.dp_block_validate_length
  generic map (
    g_err_bi          => g_err_bi,
    g_expected_length => c_packet_size
  )
  port map (
    rst => dp_rst,
    clk => dp_clk,

    snk_in  => lane_rx_sosi,
    src_out => packet_sosi
  );

  -- Validate error field
  -- . Use ref_sync as capture moment for the running MM total counts in dp_block_validate_err.
  --   The rx_packet_sosi does not have rx_packet_sosi.sync, because it carries encoded packets
  --   and because the rx_packet_sosi can carry packets from multiple sources (so multiple sync
  --   intervals multiplexed on one lane).
  u_dp_block_validate_err : entity dp_lib.dp_block_validate_err
  generic map (
    g_cnt_w           => c_word_w,  -- <= c_word_w = 32
    g_blk_cnt_w       => g_total_nof_packets_w,  -- <= c_longword_w = 64
    g_max_block_size  => c_packet_size,
    g_min_block_size  => c_packet_size,
    g_nof_err_counts  => g_nof_err_counts,
    g_fifo_note_is_ful=> false,  -- use false, because g_fifo_size = c_packet_size
    g_fifo_size       => c_packet_size,  -- can be same as g_max_block_size as src_in.ready = '1'
    g_use_sync        => false,  -- no need to pass on ref_sync
    g_data_w          => g_data_w
  )
  port map (
    dp_rst => dp_rst,
    dp_clk => dp_clk,

    ref_sync => ref_sync,

    snk_in  => packet_sosi,
    src_out => validated_sosi,

    mm_rst => mm_rst,
    mm_clk => mm_clk,

    reg_mosi => reg_dp_block_validate_err_copi,
    reg_miso => reg_dp_block_validate_err_cipo
  );

  -- Removing ETH/DP header
  u_dp_offload_rx: entity dp_lib.dp_offload_rx
  generic map (
    g_nof_streams   => 1,
    g_data_w        => g_data_w,
    g_hdr_field_arr => c_hdr_field_arr
  )
  port map (
    mm_rst => mm_rst,
    mm_clk => mm_clk,

    dp_rst => dp_rst,
    dp_clk => dp_clk,

    snk_in_arr(0)  => validated_sosi,
    src_out_arr(0) => offload_rx_sosi,

    hdr_fields_out_arr(0)  => hdr_fields_out,
    hdr_fields_raw_arr(0)  => hdr_fields_raw
  );

  -- Use dp layer
  gen_dp_layer : if g_use_dp_layer generate
    p_set_meta: process(offload_rx_sosi, hdr_fields_out, hdr_fields_raw)
    begin
      decoded_sosi         <= offload_rx_sosi;
      decoded_sosi.sync    <=                sl(hdr_fields_out(field_hi(c_hdr_field_arr, "dp_sync"    ) downto field_lo(c_hdr_field_arr, "dp_sync"     )));
      decoded_sosi.bsn     <= RESIZE_DP_BSN(    hdr_fields_raw(field_hi(c_hdr_field_arr, "dp_bsn"     ) downto field_lo(c_hdr_field_arr, "dp_bsn"      )));
      decoded_sosi.channel <= RESIZE_DP_CHANNEL(hdr_fields_raw(field_hi(c_hdr_field_arr, "dp_channel" ) downto field_lo(c_hdr_field_arr, "dp_channel"  )));
    end process;

    -- Validate bsn at sync
    u_dp_block_validate_bsn_at_sync : entity dp_lib.dp_block_validate_bsn_at_sync
    generic map (
      g_check_channel => g_check_channel
    )
    port map (
      dp_rst => dp_rst,
      dp_clk => dp_clk,

      in_sosi  => decoded_sosi,
      bs_sosi  => bs_sosi,
      out_sosi => from_lane_sosi,

      mm_rst => mm_rst,
      mm_clk => mm_clk,

      reg_mosi => reg_dp_block_validate_bsn_at_sync_copi,
      reg_miso => reg_dp_block_validate_bsn_at_sync_cipo
    );

    -- Convert nof_hops to source RN
    p_hop_to_src_rn: process(dp_rst, dp_clk)
    begin
      if dp_rst = '1' then
        monitor_sosi       <= c_dp_sosi_rst;
        piped_monitor_sosi <= c_dp_sosi_rst;
      elsif rising_edge(dp_clk) then
        -- Pipe monitor sosi to ease timing.
        piped_monitor_sosi <= monitor_sosi;

        -- Convert nof_hops to source RN
        monitor_sosi <= decoded_sosi;
        monitor_sosi.channel <= func_ring_nof_hops_to_source_rn(decoded_sosi.channel, this_rn, N_rn, g_lane_direction);
      end if;
    end process;

    u_dp_demux : entity dp_lib.dp_demux
    generic map (
      g_nof_output => g_nof_rx_monitors
    )
    port map (
      rst         => dp_rst,
      clk         => dp_clk,
      snk_in      => piped_monitor_sosi,
      src_out_arr => demux_sosi_arr
    );
    monitor_sosi_arr <= func_dp_stream_arr_reverse_range(demux_sosi_arr);  -- Fix reversed bus.

    -- BSN Monitors
    u_mms_dp_bsn_monitor_v2 : entity dp_lib.mms_dp_bsn_monitor_v2
    generic map (
      g_nof_streams => g_nof_rx_monitors,
      g_sync_timeout => g_sync_timeout
    )
    port map (
      mm_rst      => mm_rst,
      mm_clk      => mm_clk,
      reg_mosi    => reg_bsn_monitor_v2_copi,
      reg_miso    => reg_bsn_monitor_v2_cipo,

      dp_rst      => dp_rst,
      dp_clk      => dp_clk,
      in_sosi_arr => monitor_sosi_arr,
      ref_sync    => ref_sync
    );
  end generate;

  -- Do not use dp layer
  gen_no_dp_layer : if not g_use_dp_layer generate
    from_lane_sosi <= offload_rx_sosi;
  end generate;

end str;