RTLDoc datamover (lkesting/konark) - RTLDoc example
source file

rtl/datamover_streamer.sv

datamover 225 lines
/*
 * Copyright (C) 2020-2026 ETH Zurich and University of Bologna
 *
 * Copyright and related rights are licensed under the Solderpad Hardware
 * License, Version 0.51 (the "License"); you may not use this file except in
 * compliance with the License.  You may obtain a copy of the License at
 * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
 * or agreed to in writing, software, hardware and materials distributed under
 * this 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.
 */

/*
 * Authors:  Francesco Conti <f.conti@unibo.it>
 *           Sergio Mazzola <smazzola@iis.ee.ethz.ch>
 *           Cyrill Durrer <cdurrer@iis.ee.ethz.ch>
 */

`include "hci_helpers.svh"

module datamover_streamer
  import hwpe_stream_package::*;
  import hci_package::*;
  import datamover_package::*;
#(
  parameter int unsigned BANDWIDTH = 32,
  parameter int unsigned NUM_ELEM_WORD = 4, // number of elements in a bank word
  parameter int unsigned ELEM_WIDTH = 8,    // element width (in bits)
  parameter int unsigned TCDM_FIFO_DEPTH = 2,
  parameter int unsigned MISALIGNED_ACCESSES = 1,
  parameter hci_size_parameter_t `HCI_SIZE_PARAM(tcdm) = '0
) (
  // global signals
  input  logic                   clk_i,
  input  logic                   rst_ni,
  input  logic                   test_mode_i,
  // local enable & clear
  input  logic                   enable_i,
  input  logic                   clear_i,
  // input data stream + handshake
  hwpe_stream_intf_stream.source data_in,
  // output data stream + handshake
  hwpe_stream_intf_stream.sink   data_out,
  // TCDM ports
  hci_core_intf.initiator        tcdm,
  // control channel
  input  ctrl_streamer_t         ctrl_i,
  output flags_streamer_t        flags_o
);

  localparam int unsigned BW = `HCI_SIZE_GET_BW(tcdm);
  localparam int unsigned AW = `HCI_SIZE_GET_AW(tcdm);
  localparam int unsigned UW  = `HCI_SIZE_GET_UW(tcdm);
  localparam int unsigned IW  = `HCI_SIZE_GET_IW(tcdm);
  localparam int unsigned EW  = `HCI_SIZE_GET_EW(tcdm);
  localparam int unsigned EHW = `HCI_SIZE_GET_EHW(tcdm);

  flags_fifo_t tcdm_fifo_flags;

  // "Virtual" HCI TCDM interfaces. Interface [0] maps loads (coming from
  // and HCI source) and interface [1] maps stores (coming from an HCI sink).
  hci_core_intf #(
    .DW  ( BANDWIDTH ),
    .BW  ( BW ),
    .AW  ( AW ),
    .UW  ( UW ),
    .IW  ( IW ),
    .EW  ( EW ),
    .EHW ( EHW)
    // `ifndef SYNTHESIS
    // ,.WAIVE_RQ4_ASSERT ( 1'b1 )    // ToDo: make sure that these waives are not hiding real issues in the design
    // ,.WAIVE_RQ3_ASSERT ( 1'b1 )
    // `endif
  ) virt_tcdm [1:0] (
    .clk ( clk_i )
  );

  // "Virtual" TCDM interface, used to embody data after mixing loads and
  // stores, but before the TCDM FIFO (if present).
  hci_core_intf #(
    .DW ( BANDWIDTH ),
    .BW ( BW ),
    .AW ( AW ),
    .UW ( UW ),
    .IW ( IW ),
    .EW ( EW ),
    .EHW( EHW)
  ) tcdm_prefifo (
    .clk ( clk_i )
  );

  // "Virtual" TCDM interface, used to embody data after the TCDM FIFO
  // (if present) but before the load filter. Notice this is technically
  // an array of interfaces, with one single instance inside. This is
  // useful because HCI muxes expect an array of output interfaces.
  hci_core_intf #(
    .DW  ( BANDWIDTH ),
    .BW  ( BW ),
    .AW  ( AW ),
    .UW  ( UW ),
    .IW  ( IW ),
    .EW  ( EW ),
    .EHW ( EHW)
  ) tcdm_prefilter [0:0] (
    .clk ( clk_i )
  );

  // Standard HCI core source. The DATA_WIDTH parameter is referred to
  // the HWPE-Stream, since the source also performs realignment, it will
  // expose a 1-word-larger HCI TCDM interface.
  hci_core_source #(
    .ELEMENT_WIDTH         ( ELEM_WIDTH            ), // e.g., 8 bits per element
    .ELEMENTS_PER_BANK     ( NUM_ELEM_WORD         ), // number of elements in one memory bank word
    .MISALIGNED_ACCESSES   ( MISALIGNED_ACCESSES   ),
    .DIM_ENABLE_1H         ( 4'b1111               ),
    .TCDM_R_READY_SUPPORT  ( 1'b0                  ),
    .`HCI_SIZE_PARAM(tcdm) ( `HCI_SIZE_PARAM(tcdm) )
  ) i_source (
    .clk_i       ( clk_i                         ),
    .rst_ni      ( rst_ni                        ),
    .test_mode_i ( test_mode_i                   ),
    .clear_i     ( clear_i                       ),
    .enable_i    ( 1'b1                          ),
    .tcdm        ( virt_tcdm [0]                 ),
    .stream      ( data_in                       ),
    .ctrl_i      ( ctrl_i.data_in_source_ctrl    ),
    .flags_o     ( flags_o.data_in_source_flags  )
  );

  // Standard HCI core sink. The DATA_WIDTH parameter is referred to
  // the HWPE-Stream, since the sink also performs realignment, it will
  // expose a 1-word-larger HCI TCDM interface.
  hci_core_sink #(
    .ELEMENT_WIDTH         ( ELEM_WIDTH            ), // e.g., 8 bits per element
    .ELEMENTS_PER_BANK     ( NUM_ELEM_WORD         ), // number of elements in one memory bank word
    .MISALIGNED_ACCESSES   ( MISALIGNED_ACCESSES   ),
    .DIM_ENABLE_1H         ( 4'b1111               ),
    .`HCI_SIZE_PARAM(tcdm) ( `HCI_SIZE_PARAM(tcdm) )
  ) i_sink (
    .clk_i       ( clk_i                       ),
    .rst_ni      ( rst_ni                      ),
    .test_mode_i ( test_mode_i                 ),
    .clear_i     ( clear_i                     ),
    .enable_i    ( 1'b1                        ),
    .tcdm        ( virt_tcdm [1]               ),
    .stream      ( data_out                    ),
    .ctrl_i      ( ctrl_i.data_out_sink_ctrl   ),
    .flags_o     ( flags_o.data_out_sink_flags )
  );

  generate
    if(TCDM_FIFO_DEPTH > 0) begin : use_fifo_gen

      // TCDM muxing is not possible in general before a FIFO, because
      // there is no standard way to couple a response with the channel
      // that requested it. Here we bypass the issue by using a mixer
      // that is specifically designed for a LOAD-exclusive channel and
      // a STORE-exclusive channel. It will couple any valid response to
      // the LOAD channel exclusively.
      hci_core_load_store_mixer #(
        .DW ( BANDWIDTH ),
        .BW ( BW ),
        .AW ( AW ),
        .UW ( UW ),
        .EW ( EW )
      ) i_ld_st_mux_static (
        .clk_i    ( clk_i        ),
        .rst_ni   ( rst_ni       ),
        .clear_i  ( clear_i      ),
        .in_load  ( virt_tcdm[0] ),
        .in_store ( virt_tcdm[1] ),
        .out      ( tcdm_prefifo )
      );

      // The HCI core FIFO decouples the request path from the response path, easing
      // timing closure when integrating the accelerator in a cluster.
      hci_core_fifo #(
        .FIFO_DEPTH ( TCDM_FIFO_DEPTH )
      ) i_tcdm_fifo (
        .clk_i         ( clk_i             ),
        .rst_ni        ( rst_ni            ),
        .clear_i       ( clear_i           ),
        .flags_o       ( tcdm_fifo_flags   ),
        .tcdm_target   ( tcdm_prefifo      ),
        .tcdm_initiator( tcdm_prefilter[0] )
      );
    end
    else begin : dont_use_fifo_gen

      // If not using a FIFO, it is possible to use a standard mux instead
      // of a mixer.
      hci_core_mux_dynamic #(
        .NB_IN_CHAN  ( 2  ),
        .NB_OUT_CHAN ( 1  ),
        .`HCI_SIZE_PARAM(in)(( `HCI_SIZE_PARAM(tcdm) ))
      ) i_ld_st_mux_static (
        .clk_i   ( clk_i          ),
        .rst_ni  ( rst_ni         ),
        .clear_i ( clear_i        ),
        .in      ( virt_tcdm[1:0] ),
        .out     ( tcdm_prefilter )
      );
      assign tcdm_fifo_flags.empty = 1'b1;

    end
  endgenerate

  // The HCI core filter is meant to filter out r_valid strobes that the
  // cluster may generate even when the TCDM access is a write. These
  // pollute HCI TCDM FIFOs and mixers, and it is better to remove them
  // altogether.
  hci_core_r_valid_filter #(
    .`HCI_SIZE_PARAM(tcdm_target) ( `HCI_SIZE_PARAM(tcdm) )
  ) i_tcdm_filter (
    .clk_i         ( clk_i                ),
    .rst_ni        ( rst_ni               ),
    .clear_i       ( clear_i              ),
    .enable_i      ( 1'b1                 ),
    .tcdm_target   ( tcdm_prefilter[0].target ),
    .tcdm_initiator( tcdm                 )
  );
  assign flags_o.tcdm_fifo_empty = tcdm_fifo_flags.empty;

endmodule // datamover_streamer