|  | // Copyright lowRISC contributors. | 
|  | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  | // | 
|  | // SRAM controller. | 
|  | // | 
|  |  | 
|  | `include "prim_assert.sv" | 
|  |  | 
|  | module sram_ctrl | 
|  | import sram_ctrl_pkg::*; | 
|  | import sram_ctrl_reg_pkg::*; | 
|  | #( | 
|  | // Number of words stored in the SRAM. | 
|  | parameter int MemSizeRam = 32'h1000, | 
|  | // Enable asynchronous transitions on alerts. | 
|  | parameter logic [NumAlerts-1:0] AlertAsyncOn          = {NumAlerts{1'b1}}, | 
|  | // Enables the execute from SRAM feature. | 
|  | parameter bit InstrExec                               = 1, | 
|  | // Random netlist constants | 
|  | parameter otp_ctrl_pkg::sram_key_t   RndCnstSramKey   = RndCnstSramKeyDefault, | 
|  | parameter otp_ctrl_pkg::sram_nonce_t RndCnstSramNonce = RndCnstSramNonceDefault, | 
|  | parameter lfsr_seed_t                RndCnstLfsrSeed  = RndCnstLfsrSeedDefault, | 
|  | parameter lfsr_perm_t                RndCnstLfsrPerm  = RndCnstLfsrPermDefault | 
|  | ) ( | 
|  | // SRAM Clock | 
|  | input  logic                                       clk_i, | 
|  | input  logic                                       rst_ni, | 
|  | // OTP Clock (for key interface) | 
|  | input  logic                                       clk_otp_i, | 
|  | input  logic                                       rst_otp_ni, | 
|  | // Bus Interface (device) for SRAM | 
|  | input  tlul_pkg::tl_h2d_t                          ram_tl_i, | 
|  | output tlul_pkg::tl_d2h_t                          ram_tl_o, | 
|  | // Bus Interface (device) for CSRs | 
|  | input  tlul_pkg::tl_h2d_t                          regs_tl_i, | 
|  | output tlul_pkg::tl_d2h_t                          regs_tl_o, | 
|  | // Alert outputs. | 
|  | input  prim_alert_pkg::alert_rx_t [NumAlerts-1:0]  alert_rx_i, | 
|  | output prim_alert_pkg::alert_tx_t [NumAlerts-1:0]  alert_tx_o, | 
|  | // Life-cycle escalation input (scraps the scrambling keys) | 
|  | // SEC_CM: LC_ESCALATE_EN.INTERSIG.MUBI | 
|  | input  lc_ctrl_pkg::lc_tx_t                        lc_escalate_en_i, | 
|  | // SEC_CM: LC_HW_DEBUG_EN.INTERSIG.MUBI | 
|  | input  lc_ctrl_pkg::lc_tx_t                        lc_hw_debug_en_i, | 
|  | // Otp configuration for sram execution | 
|  | // SEC_CM: EXEC.INTERSIG.MUBI | 
|  | input  prim_mubi_pkg::mubi8_t                      otp_en_sram_ifetch_i, | 
|  | // Key request to OTP (running on clk_fixed) | 
|  | // SEC_CM: SCRAMBLE.KEY.SIDELOAD | 
|  | output otp_ctrl_pkg::sram_otp_key_req_t            sram_otp_key_o, | 
|  | input  otp_ctrl_pkg::sram_otp_key_rsp_t            sram_otp_key_i, | 
|  | // config | 
|  | input  prim_ram_1p_pkg::ram_1p_cfg_t               cfg_i | 
|  | ); | 
|  |  | 
|  | import lc_ctrl_pkg::lc_tx_t; | 
|  | import lc_ctrl_pkg::lc_tx_test_true_loose; | 
|  | import lc_ctrl_pkg::lc_tx_bool_to_lc_tx; | 
|  | import lc_ctrl_pkg::lc_tx_or_hi; | 
|  | import lc_ctrl_pkg::lc_tx_inv; | 
|  | import lc_ctrl_pkg::lc_to_mubi4; | 
|  |  | 
|  | // This is later on pruned to the correct width at the SRAM wrapper interface. | 
|  | parameter int unsigned Depth = MemSizeRam >> 2; | 
|  | parameter int unsigned AddrWidth = prim_util_pkg::vbits(Depth); | 
|  |  | 
|  | `ASSERT_INIT(NonceWidthsLessThanSource_A, NonceWidth + LfsrWidth <= otp_ctrl_pkg::SramNonceWidth) | 
|  |  | 
|  |  | 
|  | ///////////////////////////////////// | 
|  | // Anchor incoming seeds and constants | 
|  | ///////////////////////////////////// | 
|  | localparam int TotalAnchorWidth = $bits(otp_ctrl_pkg::sram_key_t) + | 
|  | $bits(otp_ctrl_pkg::sram_nonce_t); | 
|  |  | 
|  | otp_ctrl_pkg::sram_key_t cnst_sram_key; | 
|  | otp_ctrl_pkg::sram_nonce_t cnst_sram_nonce; | 
|  |  | 
|  | prim_sec_anchor_buf #( | 
|  | .Width(TotalAnchorWidth) | 
|  | ) u_seed_anchor ( | 
|  | .in_i({RndCnstSramKey, | 
|  | RndCnstSramNonce}), | 
|  | .out_o({cnst_sram_key, | 
|  | cnst_sram_nonce}) | 
|  | ); | 
|  |  | 
|  |  | 
|  | ////////////////////////// | 
|  | // CSR Node and Mapping // | 
|  | ////////////////////////// | 
|  |  | 
|  | // We've got two bus interfaces + an lc_gate in this module, | 
|  | // hence three integ failure sources. | 
|  | logic [2:0] bus_integ_error; | 
|  |  | 
|  | sram_ctrl_regs_reg2hw_t reg2hw; | 
|  | sram_ctrl_regs_hw2reg_t hw2reg; | 
|  |  | 
|  | // SEC_CM: CTRL.CONFIG.REGWEN | 
|  | // SEC_CM: EXEC.CONFIG.REGWEN | 
|  | sram_ctrl_regs_reg_top u_reg_regs ( | 
|  | .clk_i, | 
|  | .rst_ni, | 
|  | .tl_i      (regs_tl_i), | 
|  | .tl_o      (regs_tl_o), | 
|  | .reg2hw, | 
|  | .hw2reg, | 
|  | // SEC_CM: BUS.INTEGRITY | 
|  | .intg_err_o(bus_integ_error[0]), | 
|  | .devmode_i (1'b1) | 
|  | ); | 
|  |  | 
|  | // Key and attribute outputs to scrambling device | 
|  | logic [otp_ctrl_pkg::SramKeyWidth-1:0]   key_d, key_q; | 
|  | logic [otp_ctrl_pkg::SramNonceWidth-1:0] nonce_d, nonce_q; | 
|  |  | 
|  | // tie-off unused nonce bits | 
|  | if (otp_ctrl_pkg::SramNonceWidth > NonceWidth) begin : gen_nonce_tieoff | 
|  | logic unused_nonce; | 
|  | assign unused_nonce = ^nonce_q[otp_ctrl_pkg::SramNonceWidth-1:NonceWidth]; | 
|  | end | 
|  |  | 
|  | ////////////////// | 
|  | // Alert Sender // | 
|  | ////////////////// | 
|  |  | 
|  | logic alert_test; | 
|  | assign alert_test = reg2hw.alert_test.q & reg2hw.alert_test.qe; | 
|  |  | 
|  | assign hw2reg.status.bus_integ_error.d  = 1'b1; | 
|  | assign hw2reg.status.bus_integ_error.de = |bus_integ_error; | 
|  |  | 
|  | logic init_error; | 
|  | assign hw2reg.status.init_error.d  = 1'b1; | 
|  | assign hw2reg.status.init_error.de = init_error; | 
|  |  | 
|  | logic alert_req; | 
|  | assign alert_req = (|bus_integ_error) | init_error; | 
|  |  | 
|  | prim_alert_sender #( | 
|  | .AsyncOn(AlertAsyncOn[0]), | 
|  | .IsFatal(1) | 
|  | ) u_prim_alert_sender_parity ( | 
|  | .clk_i, | 
|  | .rst_ni, | 
|  | .alert_test_i  ( alert_test    ), | 
|  | .alert_req_i   ( alert_req     ), | 
|  | .alert_ack_o   (               ), | 
|  | .alert_state_o (               ), | 
|  | .alert_rx_i    ( alert_rx_i[0] ), | 
|  | .alert_tx_o    ( alert_tx_o[0] ) | 
|  | ); | 
|  |  | 
|  | ///////////////////////// | 
|  | // Escalation Triggers // | 
|  | ///////////////////////// | 
|  |  | 
|  | lc_tx_t [1:0] escalate_en; | 
|  | prim_lc_sync #( | 
|  | .NumCopies (2) | 
|  | ) u_prim_lc_sync ( | 
|  | .clk_i, | 
|  | .rst_ni, | 
|  | .lc_en_i (lc_escalate_en_i), | 
|  | .lc_en_o (escalate_en) | 
|  | ); | 
|  |  | 
|  | // SEC_CM: KEY.GLOBAL_ESC | 
|  | logic escalate; | 
|  | assign escalate = lc_tx_test_true_loose(escalate_en[0]); | 
|  | assign hw2reg.status.escalated.d  = 1'b1; | 
|  | assign hw2reg.status.escalated.de = escalate; | 
|  |  | 
|  | // SEC_CM: KEY.LOCAL_ESC | 
|  | // Aggregate external and internal escalation sources. | 
|  | // This is used in countermeasures further below (key reset and transaction blocking). | 
|  | logic local_esc, local_esc_reg; | 
|  | // This signal only aggregates registered escalation signals and is used for transaction | 
|  | // blocking further below, which is on a timing-critical path. | 
|  | assign local_esc_reg = reg2hw.status.escalated.q  | | 
|  | reg2hw.status.init_error.q | | 
|  | reg2hw.status.bus_integ_error.q; | 
|  | // This signal aggregates all escalation trigger signals, including the ones that are generated in | 
|  | // the same cycle such as init_error and bus_integ_error. It is used for countermeasures that are | 
|  | // not on the critical path (such as clearing the scrambling keys). | 
|  | assign local_esc = escalate           | | 
|  | init_error         | | 
|  | (|bus_integ_error) | | 
|  | local_esc_reg; | 
|  |  | 
|  | // Convert registered, local escalation sources to a multibit signal and combine this with | 
|  | // the incoming escalation enable signal before feeding into the TL-UL gate further below. | 
|  | lc_tx_t lc_tlul_gate_en; | 
|  | assign lc_tlul_gate_en = lc_tx_inv(lc_tx_or_hi(escalate_en[1], | 
|  | lc_tx_bool_to_lc_tx(local_esc_reg))); | 
|  | /////////////////////// | 
|  | // HW Initialization // | 
|  | /////////////////////// | 
|  |  | 
|  | // A write to the init register reloads the LFSR seed, resets the init counter and | 
|  | // sets init_q to flag a pending initialization request. | 
|  | logic init_trig; | 
|  | assign init_trig = reg2hw.ctrl.init.q & reg2hw.ctrl.init.qe; | 
|  |  | 
|  | logic init_d, init_q, init_done; | 
|  | assign init_d = (init_done) ? 1'b0 : | 
|  | (init_trig) ? 1'b1 : init_q; | 
|  |  | 
|  | always_ff @(posedge clk_i or negedge rst_ni) begin : p_init_reg | 
|  | if(!rst_ni) begin | 
|  | init_q <= 1'b0; | 
|  | end else begin | 
|  | init_q <= init_d; | 
|  | end | 
|  | end | 
|  |  | 
|  | // This waits until the scrambling keys are actually valid (this allows the SW to trigger | 
|  | // key renewal and initialization at the same time). | 
|  | logic init_req; | 
|  | logic [AddrWidth-1:0] init_cnt; | 
|  | logic key_req_pending_d, key_req_pending_q; | 
|  | assign init_req  = init_q & ~key_req_pending_q; | 
|  | assign init_done = (init_cnt == AddrWidth'(Depth - 1)) & init_req; | 
|  |  | 
|  | // We employ two redundant counters to guard against FI attacks. | 
|  | // If any of the two is glitched and the two counter states do not agree, | 
|  | // we trigger an alert. | 
|  | // SEC_CM: INIT.CTR.REDUN | 
|  | prim_count #( | 
|  | .Width(AddrWidth) | 
|  | ) u_prim_count ( | 
|  | .clk_i, | 
|  | .rst_ni, | 
|  | .clr_i(init_trig), | 
|  | .set_i(1'b0), | 
|  | .set_cnt_i('0), | 
|  | .incr_en_i(init_req), | 
|  | .decr_en_i(1'b0), | 
|  | .step_i(AddrWidth'(1)), | 
|  | .cnt_o(init_cnt), | 
|  | .cnt_next_o(), | 
|  | .err_o(init_error) | 
|  | ); | 
|  |  | 
|  | // Clear this bit on local escalation. | 
|  | assign hw2reg.status.init_done.d  = init_done & ~init_trig & ~local_esc; | 
|  | assign hw2reg.status.init_done.de = init_done | init_trig | local_esc; | 
|  |  | 
|  | //////////////////////////// | 
|  | // Scrambling Key Request // | 
|  | //////////////////////////// | 
|  |  | 
|  | // The scrambling key and nonce have to be requested from the OTP controller via a req/ack | 
|  | // protocol. Since the OTP controller works in a different clock domain, we have to synchronize | 
|  | // the req/ack protocol as described in more details here: | 
|  | // https://docs.opentitan.org/hw/ip/otp_ctrl/doc/index.html#interfaces-to-sram-and-otbn-scramblers | 
|  | logic key_req, key_ack; | 
|  | assign key_req = reg2hw.ctrl.renew_scr_key.q & reg2hw.ctrl.renew_scr_key.qe; | 
|  | assign key_req_pending_d = (key_req) ? 1'b1 : | 
|  | (key_ack) ? 1'b0 : key_req_pending_q; | 
|  |  | 
|  | // The SRAM scrambling wrapper will not accept any transactions while | 
|  | // the key req is pending or if we have escalated. | 
|  | // Note that we're not using key_valid_q here, such that the SRAM can be used | 
|  | // right after reset, where the keys are reset to the default netlist constant. | 
|  | logic key_valid; | 
|  | assign key_valid = ~(key_req_pending_q | reg2hw.status.escalated.q); | 
|  |  | 
|  | // Clear this bit on local escalation. | 
|  | assign hw2reg.status.scr_key_valid.d   = key_ack & ~key_req & ~local_esc; | 
|  | assign hw2reg.status.scr_key_valid.de  = key_req | key_ack | local_esc; | 
|  |  | 
|  | // Clear this bit on local escalation. | 
|  | logic key_seed_valid; | 
|  | assign hw2reg.status.scr_key_seed_valid.d  = key_seed_valid & ~local_esc; | 
|  | assign hw2reg.status.scr_key_seed_valid.de = key_ack | local_esc; | 
|  |  | 
|  | always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs | 
|  | if (!rst_ni) begin | 
|  | key_req_pending_q <= 1'b0; | 
|  | // reset case does not use buffered values as the | 
|  | // reset value will be directly encoded into flop types | 
|  | key_q             <= RndCnstSramKey; | 
|  | nonce_q           <= RndCnstSramNonce; | 
|  | end else begin | 
|  | key_req_pending_q <= key_req_pending_d; | 
|  | if (key_ack) begin | 
|  | key_q   <= key_d; | 
|  | nonce_q <= nonce_d; | 
|  | end | 
|  | // This scraps the keys. | 
|  | // SEC_CM: KEY.GLOBAL_ESC | 
|  | // SEC_CM: KEY.LOCAL_ESC | 
|  | if (local_esc) begin | 
|  | key_q   <= cnst_sram_key; | 
|  | nonce_q <= cnst_sram_nonce; | 
|  | end | 
|  | end | 
|  | end | 
|  |  | 
|  | prim_sync_reqack_data #( | 
|  | .Width($bits(otp_ctrl_pkg::sram_otp_key_rsp_t)-1), | 
|  | .DataSrc2Dst(1'b0) | 
|  | ) u_prim_sync_reqack_data ( | 
|  | .clk_src_i  ( clk_i              ), | 
|  | .rst_src_ni ( rst_ni             ), | 
|  | .clk_dst_i  ( clk_otp_i          ), | 
|  | .rst_dst_ni ( rst_otp_ni         ), | 
|  | .req_chk_i  ( 1'b1               ), | 
|  | .src_req_i  ( key_req_pending_q  ), | 
|  | .src_ack_o  ( key_ack            ), | 
|  | .dst_req_o  ( sram_otp_key_o.req ), | 
|  | .dst_ack_i  ( sram_otp_key_i.ack ), | 
|  | .data_i     ( {sram_otp_key_i.key, | 
|  | sram_otp_key_i.nonce, | 
|  | sram_otp_key_i.seed_valid} ), | 
|  | .data_o     ( {key_d, | 
|  | nonce_d, | 
|  | key_seed_valid}          ) | 
|  | ); | 
|  |  | 
|  | logic unused_csr_sigs; | 
|  | assign unused_csr_sigs = ^{reg2hw.status.init_done.q, | 
|  | reg2hw.status.scr_key_seed_valid.q}; | 
|  |  | 
|  | //////////////////// | 
|  | // SRAM Execution // | 
|  | //////////////////// | 
|  |  | 
|  | import prim_mubi_pkg::mubi4_t; | 
|  | import prim_mubi_pkg::MuBi4True; | 
|  | import prim_mubi_pkg::MuBi4False; | 
|  | import prim_mubi_pkg::mubi8_test_true_strict; | 
|  |  | 
|  | mubi4_t en_ifetch; | 
|  | if (InstrExec) begin : gen_instr_ctrl | 
|  | mubi4_t lc_ifetch_en; | 
|  | mubi4_t reg_ifetch_en; | 
|  | // SEC_CM: INSTR.BUS.LC_GATED | 
|  | assign lc_ifetch_en = lc_to_mubi4(lc_hw_debug_en_i); | 
|  | // SEC_CM: EXEC.CONFIG.MUBI | 
|  | assign reg_ifetch_en = mubi4_t'(reg2hw.exec.q); | 
|  | // SEC_CM: EXEC.INTERSIG.MUBI | 
|  | assign en_ifetch = (mubi8_test_true_strict(otp_en_sram_ifetch_i)) ? reg_ifetch_en : | 
|  | lc_ifetch_en; | 
|  | end else begin : gen_tieoff | 
|  | assign en_ifetch = MuBi4False; | 
|  |  | 
|  | // tie off unused signals | 
|  | logic unused_sigs; | 
|  | assign unused_sigs = ^{lc_hw_debug_en_i, | 
|  | reg2hw.exec.q, | 
|  | otp_en_sram_ifetch_i}; | 
|  | end | 
|  |  | 
|  | ///////////////////////// | 
|  | // Initialization LFSR // | 
|  | ///////////////////////// | 
|  |  | 
|  | logic [LfsrWidth-1:0] lfsr_out; | 
|  | prim_lfsr #( | 
|  | .LfsrDw      ( LfsrWidth       ), | 
|  | .EntropyDw   ( LfsrWidth       ), | 
|  | .StateOutDw  ( LfsrWidth       ), | 
|  | .DefaultSeed ( RndCnstLfsrSeed ), | 
|  | .StatePermEn ( 1'b1            ), | 
|  | .StatePerm   ( RndCnstLfsrPerm ) | 
|  | ) u_lfsr ( | 
|  | .clk_i, | 
|  | .rst_ni, | 
|  | .lfsr_en_i(init_req), | 
|  | .seed_en_i(init_trig), | 
|  | .seed_i(nonce_q[NonceWidth +: LfsrWidth]), | 
|  | .entropy_i('0), | 
|  | .state_o(lfsr_out) | 
|  | ); | 
|  |  | 
|  | // Compute the correct integrity alongside for the pseudo-random initialization values. | 
|  | logic [DataWidth - 1 :0] lfsr_out_integ; | 
|  | tlul_data_integ_enc u_tlul_data_integ_enc ( | 
|  | .data_i(lfsr_out), | 
|  | .data_intg_o(lfsr_out_integ) | 
|  | ); | 
|  |  | 
|  | //////////////////////////// | 
|  | // SRAM TL-UL Access Gate // | 
|  | //////////////////////////// | 
|  |  | 
|  | tlul_pkg::tl_h2d_t ram_tl_in_gated; | 
|  | tlul_pkg::tl_d2h_t ram_tl_out_gated; | 
|  |  | 
|  | tlul_lc_gate #( | 
|  | .NumGatesPerDirection(2) | 
|  | ) u_tlul_lc_gate ( | 
|  | .clk_i, | 
|  | .rst_ni, | 
|  | .tl_h2d_i(ram_tl_i), | 
|  | .tl_d2h_o(ram_tl_o), | 
|  | .tl_h2d_o(ram_tl_in_gated), | 
|  | .tl_d2h_i(ram_tl_out_gated), | 
|  | .lc_en_i (lc_tlul_gate_en), | 
|  | .err_o   (bus_integ_error[2]) | 
|  | ); | 
|  |  | 
|  | ///////////////////////////////// | 
|  | // SRAM with scrambling device // | 
|  | ///////////////////////////////// | 
|  |  | 
|  | logic tlul_req, tlul_gnt, tlul_we; | 
|  | logic [AddrWidth-1:0] tlul_addr; | 
|  | logic [DataWidth-1:0] tlul_wdata, tlul_wmask; | 
|  |  | 
|  | logic sram_intg_error, sram_req, sram_gnt, sram_we, sram_rvalid; | 
|  | logic [AddrWidth-1:0] sram_addr; | 
|  | logic [DataWidth-1:0] sram_wdata, sram_wmask, sram_rdata; | 
|  |  | 
|  | tlul_adapter_sram #( | 
|  | .SramAw(AddrWidth), | 
|  | .SramDw(DataWidth - tlul_pkg::DataIntgWidth), | 
|  | .Outstanding(2), | 
|  | .ByteAccess(1), | 
|  | .CmdIntgCheck(1), | 
|  | .EnableRspIntgGen(1), | 
|  | .EnableDataIntgGen(0), | 
|  | .EnableDataIntgPt(1), // SEC_CM: MEM.INTEGRITY | 
|  | .SecFifoPtr      (1)  // SEC_CM: TLUL_FIFO.CTR.REDUN | 
|  | ) u_tlul_adapter_sram ( | 
|  | .clk_i, | 
|  | .rst_ni, | 
|  | .tl_i        (ram_tl_in_gated), | 
|  | .tl_o        (ram_tl_out_gated), | 
|  | .en_ifetch_i (en_ifetch), | 
|  | .req_o       (tlul_req), | 
|  | .req_type_o  (), | 
|  | .gnt_i       (tlul_gnt), | 
|  | .we_o        (tlul_we), | 
|  | .addr_o      (tlul_addr), | 
|  | .wdata_o     (tlul_wdata), | 
|  | .wmask_o     (tlul_wmask), | 
|  | // SEC_CM: BUS.INTEGRITY | 
|  | .intg_error_o(bus_integ_error[1]), | 
|  | .rdata_i     (sram_rdata), | 
|  | .rvalid_i    (sram_rvalid), | 
|  | .rerror_i    ('0) | 
|  | ); | 
|  |  | 
|  | // Interposing mux logic for initialization with pseudo random data. | 
|  | assign sram_req        = tlul_req | init_req; | 
|  | assign tlul_gnt        = sram_gnt & ~init_req; | 
|  | assign sram_we         = tlul_we | init_req; | 
|  | assign sram_intg_error = |bus_integ_error[2:1] & ~init_req; | 
|  | assign sram_addr       = (init_req) ? init_cnt          : tlul_addr; | 
|  | assign sram_wdata      = (init_req) ? lfsr_out_integ    : tlul_wdata; | 
|  | assign sram_wmask      = (init_req) ? {DataWidth{1'b1}} : tlul_wmask; | 
|  |  | 
|  | // SEC_CM: MEM.SCRAMBLE, ADDR.SCRAMBLE | 
|  | prim_ram_1p_scr #( | 
|  | .Width(DataWidth), | 
|  | .Depth(Depth), | 
|  | .EnableParity(0), | 
|  | .DataBitsPerMask(DataWidth), | 
|  | .DiffWidth(DataWidth) | 
|  | ) u_prim_ram_1p_scr ( | 
|  | .clk_i, | 
|  | .rst_ni, | 
|  |  | 
|  | .key_valid_i (key_valid), | 
|  | .key_i       (key_q), | 
|  | .nonce_i     (nonce_q[NonceWidth-1:0]), | 
|  |  | 
|  | .req_i       (sram_req), | 
|  | .intg_error_i(sram_intg_error), | 
|  | .gnt_o       (sram_gnt), | 
|  | .write_i     (sram_we), | 
|  | .addr_i      (sram_addr), | 
|  | .wdata_i     (sram_wdata), | 
|  | .wmask_i     (sram_wmask), | 
|  | .rdata_o     (sram_rdata), | 
|  | .rvalid_o    (sram_rvalid), | 
|  | .rerror_o    ( ), | 
|  | .raddr_o     ( ), | 
|  | .cfg_i | 
|  | ); | 
|  |  | 
|  | //////////////// | 
|  | // Assertions // | 
|  | //////////////// | 
|  |  | 
|  | `ASSERT_KNOWN(RegsTlOutKnown_A,  regs_tl_o) | 
|  | `ASSERT_KNOWN(RamTlOutKnown_A,   ram_tl_o.d_valid) | 
|  | `ASSERT_KNOWN_IF(RamTlOutPayLoadKnown_A, ram_tl_o, ram_tl_o.d_valid) | 
|  | `ASSERT_KNOWN(AlertOutKnown_A,   alert_tx_o) | 
|  | `ASSERT_KNOWN(SramOtpKeyKnown_A, sram_otp_key_o) | 
|  |  | 
|  | // Alert assertions for redundant counters. | 
|  | `ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT(CntCheck_A, | 
|  | u_prim_count, alert_tx_o[0]) | 
|  | `ASSERT_PRIM_FSM_ERROR_TRIGGER_ERR(LcGateFsmCheck_A, | 
|  | u_tlul_lc_gate.u_state_regs, alert_tx_o[0]) | 
|  |  | 
|  | // Alert assertions for reg_we onehot check. | 
|  | `ASSERT_PRIM_REG_WE_ONEHOT_ERROR_TRIGGER_ALERT(RegWeOnehotCheck_A, | 
|  | u_reg_regs, alert_tx_o[0]) | 
|  |  | 
|  | // Alert assertions for redundant counters. | 
|  | `ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT(FifoWptrCheck_A, | 
|  | u_tlul_adapter_sram.u_rspfifo.gen_normal_fifo.u_fifo_cnt.gen_secure_ptrs.u_wptr, | 
|  | alert_tx_o[0]) | 
|  | `ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT(FifoRptrCheck_A, | 
|  | u_tlul_adapter_sram.u_rspfifo.gen_normal_fifo.u_fifo_cnt.gen_secure_ptrs.u_rptr, | 
|  | alert_tx_o[0]) | 
|  |  | 
|  | endmodule : sram_ctrl |