|  | // Copyright lowRISC contributors. | 
|  | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  |  | 
|  | `include "prim_assert.sv" | 
|  |  | 
|  | /** | 
|  | * Tile-Link UL adapter for SRAM-like devices | 
|  | * | 
|  | * - Intentionally omitted BaseAddr in case of multiple memory maps are used in a SoC, | 
|  | *   it means that aliasing can happen if target device size in TL-UL crossbar is bigger | 
|  | *   than SRAM size | 
|  | * - At most one of EnableDataIntgGen / EnableDataIntgPt can be enabled. However it | 
|  | *   possible for both to be disabled. | 
|  | *   A module can neither generate an integrity response nor pass through any pre-existing | 
|  | *   integrity.  This might be the case for non-security critical memories where there is | 
|  | *   no stored integrity AND another entity upstream is already generating returning integrity. | 
|  | *   There is however no case where EnableDataIntgGen and EnableDataIntgPt are both true. | 
|  | */ | 
|  | module tlul_adapter_sram | 
|  | import tlul_pkg::*; | 
|  | import prim_mubi_pkg::mubi4_t; | 
|  | #( | 
|  | parameter int SramAw            = 12, | 
|  | parameter int SramDw            = 32, // Must be multiple of the TL width | 
|  | parameter int Outstanding       = 1,  // Only one request is accepted | 
|  | parameter bit ByteAccess        = 1,  // 1: Enables sub-word write transactions. Note that this | 
|  | //    results in read-modify-write operations for integrity | 
|  | //    re-generation if EnableDataIntgPt is set to 1. | 
|  | parameter bit ErrOnWrite        = 0,  // 1: Writes not allowed, automatically error | 
|  | parameter bit ErrOnRead         = 0,  // 1: Reads not allowed, automatically error | 
|  | parameter bit CmdIntgCheck      = 0,  // 1: Enable command integrity check | 
|  | parameter bit EnableRspIntgGen  = 0,  // 1: Generate response integrity | 
|  | parameter bit EnableDataIntgGen = 0,  // 1: Generate response data integrity | 
|  | parameter bit EnableDataIntgPt  = 0,  // 1: Passthrough command/response data integrity | 
|  | parameter bit SecFifoPtr        = 0,  // 1: Duplicated fifo pointers | 
|  | localparam int WidthMult        = SramDw / top_pkg::TL_DW, | 
|  | localparam int IntgWidth        = tlul_pkg::DataIntgWidth * WidthMult, | 
|  | localparam int DataOutW         = EnableDataIntgPt ? SramDw + IntgWidth : SramDw | 
|  | ) ( | 
|  | input   clk_i, | 
|  | input   rst_ni, | 
|  |  | 
|  | // TL-UL interface | 
|  | input   tl_h2d_t          tl_i, | 
|  | output  tl_d2h_t          tl_o, | 
|  |  | 
|  | // control interface | 
|  | input   mubi4_t en_ifetch_i, | 
|  |  | 
|  | // SRAM interface | 
|  | output logic                req_o, | 
|  | output mubi4_t              req_type_o, | 
|  | input                       gnt_i, | 
|  | output logic                we_o, | 
|  | output logic [SramAw-1:0]   addr_o, | 
|  | output logic [DataOutW-1:0] wdata_o, | 
|  | output logic [DataOutW-1:0] wmask_o, | 
|  | output logic                intg_error_o, | 
|  | input        [DataOutW-1:0] rdata_i, | 
|  | input                       rvalid_i, | 
|  | input        [1:0]          rerror_i // 2 bit error [1]: Uncorrectable, [0]: Correctable | 
|  | ); | 
|  |  | 
|  | localparam int SramByte = SramDw/8; | 
|  | localparam int DataBitWidth = prim_util_pkg::vbits(SramByte); | 
|  | localparam int WoffsetWidth = (SramByte == top_pkg::TL_DBW) ? 1 : | 
|  | DataBitWidth - prim_util_pkg::vbits(top_pkg::TL_DBW); | 
|  |  | 
|  | logic error_det; // Internal protocol error checker | 
|  | logic error_internal; // Internal protocol error checker | 
|  | logic wr_attr_error; | 
|  | logic instr_error; | 
|  | logic wr_vld_error; | 
|  | logic rd_vld_error; | 
|  | logic rsp_fifo_error; | 
|  | logic intg_error; | 
|  | logic tlul_error; | 
|  |  | 
|  | // integrity check | 
|  | if (CmdIntgCheck) begin : gen_cmd_intg_check | 
|  | tlul_cmd_intg_chk u_cmd_intg_chk ( | 
|  | .tl_i(tl_i), | 
|  | .err_o (intg_error) | 
|  | ); | 
|  | end else begin : gen_no_cmd_intg_check | 
|  | assign intg_error = '0; | 
|  | end | 
|  |  | 
|  | // permanently latch integrity error until reset | 
|  | logic intg_error_q; | 
|  | always_ff @(posedge clk_i or negedge rst_ni) begin | 
|  | if (!rst_ni) begin | 
|  | intg_error_q <= '0; | 
|  | end else if (intg_error || rsp_fifo_error) begin | 
|  | intg_error_q <= 1'b1; | 
|  | end | 
|  | end | 
|  |  | 
|  | // integrity error output is permanent and should be used for alert generation | 
|  | // or other downstream effects | 
|  | assign intg_error_o = intg_error | rsp_fifo_error | intg_error_q; | 
|  |  | 
|  | // wr_attr_error: Check if the request size, mask are permitted. | 
|  | //    Basic check of size, mask, addr align is done in tlul_err module. | 
|  | //    Here it checks any partial write if ByteAccess isn't allowed. | 
|  | assign wr_attr_error = (tl_i.a_opcode == PutFullData || tl_i.a_opcode == PutPartialData) | 
|  | ? ((ByteAccess == 0) ? | 
|  | (tl_i.a_mask != '1 || tl_i.a_size != 2'h2) : 1'b0) | 
|  | : 1'b0; | 
|  |  | 
|  | // An instruction type transaction is only valid if en_ifetch is enabled | 
|  | // If the instruction type is completely invalid, also considered an instruction error | 
|  | assign instr_error = prim_mubi_pkg::mubi4_test_invalid(tl_i.a_user.instr_type) | | 
|  | (prim_mubi_pkg::mubi4_test_true_strict(tl_i.a_user.instr_type) & | 
|  | prim_mubi_pkg::mubi4_test_false_loose(en_ifetch_i)); | 
|  |  | 
|  | if (ErrOnWrite == 1) begin : gen_no_writes | 
|  | assign wr_vld_error = tl_i.a_opcode != Get; | 
|  | end else begin : gen_writes_allowed | 
|  | assign wr_vld_error = 1'b0; | 
|  | end | 
|  |  | 
|  | if (ErrOnRead == 1) begin: gen_no_reads | 
|  | assign rd_vld_error = tl_i.a_opcode == Get; | 
|  | end else begin : gen_reads_allowed | 
|  | assign rd_vld_error = 1'b0; | 
|  | end | 
|  |  | 
|  | // tlul protocol check | 
|  | tlul_err u_err ( | 
|  | .clk_i, | 
|  | .rst_ni, | 
|  | .tl_i(tl_i), | 
|  | .err_o (tlul_error) | 
|  | ); | 
|  |  | 
|  | // error return is transactional and thus does not used the "latched" intg_err signal | 
|  | assign error_det = wr_attr_error | wr_vld_error | rd_vld_error | instr_error | | 
|  | tlul_error    | intg_error; | 
|  |  | 
|  | // from sram_byte to adapter logic | 
|  | tl_h2d_t tl_i_int; | 
|  | // from adapter logic to sram_byte | 
|  | tl_d2h_t tl_o_int; | 
|  | // from sram_byte to rsp_gen | 
|  | tl_d2h_t tl_out; | 
|  |  | 
|  | // not all parts of tl_i_int are used | 
|  | logic unused_tl_i_int; | 
|  | assign unused_tl_i_int = ^tl_i_int; | 
|  |  | 
|  | tlul_rsp_intg_gen #( | 
|  | .EnableRspIntgGen(EnableRspIntgGen), | 
|  | .EnableDataIntgGen(EnableDataIntgGen) | 
|  | ) u_rsp_gen ( | 
|  | .tl_i(tl_out), | 
|  | .tl_o | 
|  | ); | 
|  |  | 
|  | // byte handling for integrity | 
|  | tlul_sram_byte #( | 
|  | .EnableIntg(ByteAccess & EnableDataIntgPt & !ErrOnWrite), | 
|  | .Outstanding(Outstanding) | 
|  | ) u_sram_byte ( | 
|  | .clk_i, | 
|  | .rst_ni, | 
|  | .tl_i, | 
|  | .tl_o(tl_out), | 
|  | .tl_sram_o(tl_i_int), | 
|  | .tl_sram_i(tl_o_int), | 
|  | .error_i(error_det), | 
|  | .error_o(error_internal) | 
|  | ); | 
|  |  | 
|  | typedef struct packed { | 
|  | logic [top_pkg::TL_DBW-1:0] mask ; // Byte mask within the TL-UL word | 
|  | logic [WoffsetWidth-1:0]    woffset ; // Offset of the TL-UL word within the SRAM word | 
|  | } sram_req_t ; | 
|  |  | 
|  | typedef enum logic [1:0] { | 
|  | OpWrite, | 
|  | OpRead, | 
|  | OpUnknown | 
|  | } req_op_e ; | 
|  |  | 
|  | typedef struct packed { | 
|  | req_op_e                    op ; | 
|  | logic                       error ; | 
|  | prim_mubi_pkg::mubi4_t      instr_type; | 
|  | logic [top_pkg::TL_SZW-1:0] size ; | 
|  | logic [top_pkg::TL_AIW-1:0] source ; | 
|  | } req_t ; | 
|  |  | 
|  | typedef struct packed { | 
|  | logic [top_pkg::TL_DW-1:0] data ; | 
|  | logic [DataIntgWidth-1:0]  data_intg ; | 
|  | logic                      error ; | 
|  | } rsp_t ; | 
|  |  | 
|  | localparam int SramReqFifoWidth = $bits(sram_req_t) ; | 
|  | localparam int ReqFifoWidth = $bits(req_t) ; | 
|  | localparam int RspFifoWidth = $bits(rsp_t) ; | 
|  |  | 
|  | // FIFO signal in case OutStand is greater than 1 | 
|  | // If request is latched, {write, source} is pushed to req fifo. | 
|  | // Req fifo is popped when D channel is acknowledged (v & r) | 
|  | // D channel valid is asserted if it is write request or rsp fifo not empty if read. | 
|  | logic reqfifo_wvalid, reqfifo_wready; | 
|  | logic reqfifo_rvalid, reqfifo_rready; | 
|  | req_t reqfifo_wdata,  reqfifo_rdata; | 
|  |  | 
|  | logic sramreqfifo_wvalid, sramreqfifo_wready; | 
|  | logic sramreqfifo_rready; | 
|  | sram_req_t sramreqfifo_wdata, sramreqfifo_rdata; | 
|  |  | 
|  | logic rspfifo_wvalid, rspfifo_wready; | 
|  | logic rspfifo_rvalid, rspfifo_rready; | 
|  | rsp_t rspfifo_wdata,  rspfifo_rdata; | 
|  |  | 
|  | logic a_ack, d_ack, sram_ack; | 
|  | assign a_ack    = tl_i_int.a_valid & tl_o_int.a_ready ; | 
|  | assign d_ack    = tl_o_int.d_valid & tl_i_int.d_ready ; | 
|  | assign sram_ack = req_o        & gnt_i ; | 
|  |  | 
|  | // Valid handling | 
|  | logic d_valid, d_error; | 
|  | always_comb begin | 
|  | d_valid = 1'b0; | 
|  |  | 
|  | if (reqfifo_rvalid) begin | 
|  | if (reqfifo_rdata.error) begin | 
|  | // Return error response. Assume no request went out to SRAM | 
|  | d_valid = 1'b1; | 
|  | end else if (reqfifo_rdata.op == OpRead) begin | 
|  | d_valid = rspfifo_rvalid; | 
|  | end else begin | 
|  | // Write without error | 
|  | d_valid = 1'b1; | 
|  | end | 
|  | end else begin | 
|  | d_valid = 1'b0; | 
|  | end | 
|  | end | 
|  |  | 
|  |  | 
|  |  | 
|  | always_comb begin | 
|  | d_error = 1'b0; | 
|  |  | 
|  | if (reqfifo_rvalid) begin | 
|  | if (reqfifo_rdata.op == OpRead) begin | 
|  | d_error = rspfifo_rdata.error | reqfifo_rdata.error; | 
|  | end else begin | 
|  | d_error = reqfifo_rdata.error; | 
|  | end | 
|  | end else begin | 
|  | d_error = 1'b0; | 
|  | end | 
|  | end | 
|  |  | 
|  | logic vld_rd_rsp; | 
|  | assign vld_rd_rsp = d_valid & reqfifo_rvalid & rspfifo_rvalid & (reqfifo_rdata.op == OpRead); | 
|  | // If the response data is not valid, we set it to an illegal blanking value which is determined | 
|  | // by whether the current transaction is an instruction fetch or a regular read operation. | 
|  | logic [top_pkg::TL_DW-1:0] error_blanking_data; | 
|  | assign error_blanking_data = (prim_mubi_pkg::mubi4_test_true_strict(reqfifo_rdata.instr_type)) ? | 
|  | DataWhenInstrError : | 
|  | DataWhenError; | 
|  |  | 
|  | // Since DataWhenInstrError and DataWhenError can be arbitrary parameters | 
|  | // we statically calculate the correct integrity values for these parameters here so that | 
|  | // they do not have to be supplied externally. | 
|  | logic [top_pkg::TL_DW-1:0] unused_instr, unused_data; | 
|  | logic [DataIntgWidth-1:0] error_instr_integ, error_data_integ; | 
|  | tlul_data_integ_enc u_tlul_data_integ_enc_instr ( | 
|  | .data_i(DataMaxWidth'(DataWhenInstrError)), | 
|  | .data_intg_o({error_instr_integ, unused_instr}) | 
|  | ); | 
|  | tlul_data_integ_enc u_tlul_data_integ_enc_data ( | 
|  | .data_i(DataMaxWidth'(DataWhenError)), | 
|  | .data_intg_o({error_data_integ, unused_data}) | 
|  | ); | 
|  |  | 
|  | logic [DataIntgWidth-1:0] error_blanking_integ; | 
|  | assign error_blanking_integ = (prim_mubi_pkg::mubi4_test_true_strict(reqfifo_rdata.instr_type)) ? | 
|  | error_instr_integ : | 
|  | error_data_integ; | 
|  |  | 
|  | logic [top_pkg::TL_DW-1:0] d_data; | 
|  | assign d_data = (vld_rd_rsp & ~d_error) ? rspfifo_rdata.data   // valid read | 
|  | : error_blanking_data; // write or TL-UL error | 
|  |  | 
|  | // If this a write response with data fields set to 0, we have to set all ECC bits correctly | 
|  | // since we are using an inverted Hsiao code. | 
|  | logic [DataIntgWidth-1:0] data_intg; | 
|  | assign data_intg = (vld_rd_rsp && reqfifo_rdata.error) ? error_blanking_integ    : // TL-UL error | 
|  | (vld_rd_rsp)                        ? rspfifo_rdata.data_intg : // valid read | 
|  | prim_secded_pkg::SecdedInv3932ZeroEcc;                          // valid write | 
|  |  | 
|  | assign tl_o_int = '{ | 
|  | d_valid  : d_valid , | 
|  | d_opcode : (d_valid && reqfifo_rdata.op != OpRead) ? AccessAck : AccessAckData, | 
|  | d_param  : '0, | 
|  | d_size   : (d_valid) ? reqfifo_rdata.size : '0, | 
|  | d_source : (d_valid) ? reqfifo_rdata.source : '0, | 
|  | d_sink   : 1'b0, | 
|  | d_data   : d_data, | 
|  | d_user   : '{default: '0, data_intg: data_intg}, | 
|  | d_error  : d_valid && d_error, | 
|  | a_ready  : (gnt_i | error_internal) & reqfifo_wready & sramreqfifo_wready | 
|  | }; | 
|  |  | 
|  | // a_ready depends on the FIFO full condition and grant from SRAM (or SRAM arbiter) | 
|  | // assemble response, including read response, write response, and error for unsupported stuff | 
|  |  | 
|  | // Output to SRAM: | 
|  | //    Generate request only when no internal error occurs. If error occurs, the request should be | 
|  | //    dropped and returned error response to the host. So, error to be pushed to reqfifo. | 
|  | //    In this case, it is assumed the request is granted (may cause ordering issue later?) | 
|  | assign req_o      = tl_i_int.a_valid & reqfifo_wready & ~error_internal; | 
|  | assign req_type_o = tl_i_int.a_user.instr_type; | 
|  | assign we_o       = tl_i_int.a_valid & (tl_i_int.a_opcode inside {PutFullData, PutPartialData}); | 
|  | assign addr_o     = (tl_i_int.a_valid) ? tl_i_int.a_address[DataBitWidth+:SramAw] : '0; | 
|  |  | 
|  | // Support SRAMs wider than the TL-UL word width by mapping the parts of the | 
|  | // TL-UL address which are more fine-granular than the SRAM width to the | 
|  | // SRAM write mask. | 
|  | logic [WoffsetWidth-1:0] woffset; | 
|  | if (top_pkg::TL_DW != SramDw) begin : gen_wordwidthadapt | 
|  | assign woffset = tl_i_int.a_address[DataBitWidth-1:prim_util_pkg::vbits(top_pkg::TL_DBW)]; | 
|  | end else begin : gen_no_wordwidthadapt | 
|  | assign woffset = '0; | 
|  | end | 
|  |  | 
|  | // The size of the data/wmask depends on whether passthrough integrity is enabled. | 
|  | // If passthrough integrity is enabled, the data is concatenated with the integrity passed through | 
|  | // the user bits.  Otherwise, it is the data only. | 
|  | localparam int DataWidth = EnableDataIntgPt ? top_pkg::TL_DW + DataIntgWidth : top_pkg::TL_DW; | 
|  |  | 
|  | // Final combined wmask / wdata | 
|  | logic [WidthMult-1:0][DataWidth-1:0] wmask_combined; | 
|  | logic [WidthMult-1:0][DataWidth-1:0] wdata_combined; | 
|  |  | 
|  | // Original tlul portion | 
|  | logic [WidthMult-1:0][top_pkg::TL_DW-1:0] wmask_int; | 
|  | logic [WidthMult-1:0][top_pkg::TL_DW-1:0] wdata_int; | 
|  |  | 
|  | // Integrity portion | 
|  | logic [WidthMult-1:0][DataIntgWidth-1:0] wmask_intg; | 
|  | logic [WidthMult-1:0][DataIntgWidth-1:0] wdata_intg; | 
|  |  | 
|  | always_comb begin | 
|  | wmask_int = '0; | 
|  | wdata_int = '0; | 
|  |  | 
|  | if (tl_i_int.a_valid) begin | 
|  | for (int i = 0 ; i < top_pkg::TL_DW/8 ; i++) begin | 
|  | wmask_int[woffset][8*i +: 8] = {8{tl_i_int.a_mask[i]}}; | 
|  | wdata_int[woffset][8*i +: 8] = (tl_i_int.a_mask[i] && we_o) ? tl_i_int.a_data[8*i+:8] : '0; | 
|  | end | 
|  | end | 
|  | end | 
|  |  | 
|  | always_comb begin | 
|  | wmask_intg  = '0; | 
|  | wdata_intg  = '0; | 
|  |  | 
|  | if (tl_i_int.a_valid) begin | 
|  | wmask_intg[woffset] = {DataIntgWidth{1'b1}}; | 
|  | wdata_intg[woffset] = tl_i_int.a_user.data_intg; | 
|  | end | 
|  | end | 
|  |  | 
|  | for (genvar i = 0; i < WidthMult; i++) begin : gen_write_output | 
|  | if (EnableDataIntgPt) begin : gen_combined_output | 
|  | assign wmask_combined[i] = {wmask_intg[i], wmask_int[i]}; | 
|  | assign wdata_combined[i] = {wdata_intg[i], wdata_int[i]}; | 
|  | end else begin : gen_ft_output | 
|  | logic unused_w; | 
|  | assign wmask_combined[i] = wmask_int[i]; | 
|  | assign wdata_combined[i] = wdata_int[i]; | 
|  | assign unused_w = |wmask_intg & |wdata_intg; | 
|  | end | 
|  | end | 
|  |  | 
|  | assign wmask_o = wmask_combined; | 
|  | assign wdata_o = wdata_combined; | 
|  |  | 
|  | assign reqfifo_wvalid = a_ack ; // Push to FIFO only when granted | 
|  | assign reqfifo_wdata  = '{ | 
|  | op:     (tl_i_int.a_opcode != Get) ? OpWrite : OpRead, // To return AccessAck for opcode error | 
|  | error:  error_internal, | 
|  | instr_type: tl_i_int.a_user.instr_type, | 
|  | size:   tl_i_int.a_size, | 
|  | source: tl_i_int.a_source | 
|  | }; // Store the request only. Doesn't have to store data | 
|  | assign reqfifo_rready = d_ack ; | 
|  |  | 
|  | // push together with ReqFIFO, pop upon returning read | 
|  | assign sramreqfifo_wdata = '{ | 
|  | mask    : tl_i_int.a_mask, | 
|  | woffset : woffset | 
|  | }; | 
|  | assign sramreqfifo_wvalid = sram_ack & ~we_o; | 
|  | assign sramreqfifo_rready = rspfifo_wvalid; | 
|  |  | 
|  | assign rspfifo_wvalid = rvalid_i & reqfifo_rvalid; | 
|  |  | 
|  | // Make sure only requested bytes are forwarded | 
|  | logic [WidthMult-1:0][DataWidth-1:0] rdata_reshaped; | 
|  | logic [DataWidth-1:0] rdata_tlword; | 
|  |  | 
|  | // This just changes the array format so that the correct word can be selected by indexing. | 
|  | assign rdata_reshaped = rdata_i; | 
|  |  | 
|  | if (EnableDataIntgPt) begin : gen_no_rmask | 
|  | always_comb begin | 
|  | // If the read mask is set to zero, all read data is zeroed out by the mask. | 
|  | // We have to set the ECC bits accordingly since we are using an inverted Hsiao code. | 
|  | rdata_tlword = prim_secded_pkg::SecdedInv3932ZeroWord; | 
|  | // Otherwise, if at least one mask bit is nonzero, we are passing through the integrity. | 
|  | // In that case we need to feed back the entire word since otherwise the integrity | 
|  | // will not calculate correctly. | 
|  | if (|sramreqfifo_rdata.mask) begin | 
|  | // Select correct word. | 
|  | rdata_tlword = rdata_reshaped[sramreqfifo_rdata.woffset]; | 
|  | end | 
|  | end | 
|  | end else begin : gen_rmask | 
|  | logic [DataWidth-1:0] rmask; | 
|  | always_comb begin | 
|  | rmask = '0; | 
|  | for (int i = 0 ; i < top_pkg::TL_DW/8 ; i++) begin | 
|  | rmask[8*i +: 8] = {8{sramreqfifo_rdata.mask[i]}}; | 
|  | end | 
|  | end | 
|  | // Select correct word and mask it. | 
|  | assign rdata_tlword = rdata_reshaped[sramreqfifo_rdata.woffset] & rmask; | 
|  | end | 
|  |  | 
|  | assign rspfifo_wdata  = '{ | 
|  | data      : rdata_tlword[top_pkg::TL_DW-1:0], | 
|  | data_intg : EnableDataIntgPt ? rdata_tlword[DataWidth-1 -: DataIntgWidth] : '0, | 
|  | error     : rerror_i[1] // Only care for Uncorrectable error | 
|  | }; | 
|  | assign rspfifo_rready = (reqfifo_rdata.op == OpRead & ~reqfifo_rdata.error) | 
|  | ? reqfifo_rready : 1'b0 ; | 
|  |  | 
|  | // This module only cares about uncorrectable errors. | 
|  | logic unused_rerror; | 
|  | assign unused_rerror = rerror_i[0]; | 
|  |  | 
|  | // FIFO instance: REQ, RSP | 
|  |  | 
|  | // ReqFIFO is to store the Access type to match to the Response data. | 
|  | //    For instance, SRAM accepts the write request but doesn't return the | 
|  | //    acknowledge. In this case, it may be hard to determine when the D | 
|  | //    response for the write data should send out if reads/writes are | 
|  | //    interleaved. So, to make it in-order (even TL-UL allows out-of-order | 
|  | //    responses), storing the request is necessary. And if the read entry | 
|  | //    is write op, it is safe to return the response right away. If it is | 
|  | //    read reqeust, then D response is waiting until read data arrives. | 
|  | prim_fifo_sync #( | 
|  | .Width   (ReqFifoWidth), | 
|  | .Pass    (1'b0), | 
|  | .Depth   (Outstanding) | 
|  | ) u_reqfifo ( | 
|  | .clk_i, | 
|  | .rst_ni, | 
|  | .clr_i   (1'b0), | 
|  | .wvalid_i(reqfifo_wvalid), | 
|  | .wready_o(reqfifo_wready), | 
|  | .wdata_i (reqfifo_wdata), | 
|  | .rvalid_o(reqfifo_rvalid), | 
|  | .rready_i(reqfifo_rready), | 
|  | .rdata_o (reqfifo_rdata), | 
|  | .full_o  (), | 
|  | .depth_o (), | 
|  | .err_o   () | 
|  | ); | 
|  |  | 
|  | // sramreqfifo: | 
|  | //    While the ReqFIFO holds the request until it is sent back via TL-UL, the | 
|  | //    sramreqfifo only needs to hold the mask and word offset until the read | 
|  | //    data returns from memory. | 
|  | prim_fifo_sync #( | 
|  | .Width   (SramReqFifoWidth), | 
|  | .Pass    (1'b0), | 
|  | .Depth   (Outstanding) | 
|  | ) u_sramreqfifo ( | 
|  | .clk_i, | 
|  | .rst_ni, | 
|  | .clr_i   (1'b0), | 
|  | .wvalid_i(sramreqfifo_wvalid), | 
|  | .wready_o(sramreqfifo_wready), | 
|  | .wdata_i (sramreqfifo_wdata), | 
|  | .rvalid_o(), | 
|  | .rready_i(sramreqfifo_rready), | 
|  | .rdata_o (sramreqfifo_rdata), | 
|  | .full_o  (), | 
|  | .depth_o (), | 
|  | .err_o   () | 
|  | ); | 
|  |  | 
|  | // Rationale having #Outstanding depth in response FIFO. | 
|  | //    In normal case, if the host or the crossbar accepts the response data, | 
|  | //    response FIFO isn't needed. But if in any case it has a chance to be | 
|  | //    back pressured, the response FIFO should store the returned data not to | 
|  | //    lose the data from the SRAM interface. Remember, SRAM interface doesn't | 
|  | //    have back-pressure signal such as read_ready. | 
|  | prim_fifo_sync #( | 
|  | .Width   (RspFifoWidth), | 
|  | .Pass    (1'b1), | 
|  | .Depth   (Outstanding), | 
|  | .Secure  (SecFifoPtr) | 
|  | ) u_rspfifo ( | 
|  | .clk_i, | 
|  | .rst_ni, | 
|  | .clr_i   (1'b0), | 
|  | .wvalid_i(rspfifo_wvalid), | 
|  | .wready_o(rspfifo_wready), | 
|  | .wdata_i (rspfifo_wdata), | 
|  | .rvalid_o(rspfifo_rvalid), | 
|  | .rready_i(rspfifo_rready), | 
|  | .rdata_o (rspfifo_rdata), | 
|  | .full_o  (), | 
|  | .depth_o (), | 
|  | .err_o   (rsp_fifo_error) | 
|  | ); | 
|  |  | 
|  | // below assertion fails when SRAM rvalid is asserted even though ReqFifo is empty | 
|  | `ASSERT(rvalidHighReqFifoEmpty, rvalid_i |-> reqfifo_rvalid) | 
|  |  | 
|  | // below assertion fails when outstanding value is too small (SRAM rvalid is asserted | 
|  | // even though the RspFifo is full) | 
|  | `ASSERT(rvalidHighWhenRspFifoFull, rvalid_i |-> rspfifo_wready) | 
|  |  | 
|  | // If both ErrOnWrite and ErrOnRead are set, this block is useless | 
|  | `ASSERT_INIT(adapterNoReadOrWrite, (ErrOnWrite & ErrOnRead) == 0) | 
|  |  | 
|  | `ASSERT_INIT(SramDwHasByteGranularity_A, SramDw % 8 == 0) | 
|  | `ASSERT_INIT(SramDwIsMultipleOfTlulWidth_A, SramDw % top_pkg::TL_DW == 0) | 
|  |  | 
|  | // These parameter options cannot both be true at the same time | 
|  | `ASSERT_INIT(DataIntgOptions_A, ~(EnableDataIntgGen & EnableDataIntgPt)) | 
|  |  | 
|  | // make sure outputs are defined | 
|  | `ASSERT_KNOWN(TlOutKnown_A,    tl_o.d_valid) | 
|  | `ASSERT_KNOWN_IF(TlOutPayloadKnown_A, tl_o, tl_o.d_valid) | 
|  | `ASSERT_KNOWN(ReqOutKnown_A,   req_o  ) | 
|  | `ASSERT_KNOWN(WeOutKnown_A,    we_o   ) | 
|  | `ASSERT_KNOWN(AddrOutKnown_A,  addr_o ) | 
|  | `ASSERT_KNOWN(WdataOutKnown_A, wdata_o) | 
|  | `ASSERT_KNOWN(WmaskOutKnown_A, wmask_o) | 
|  |  | 
|  | endmodule |