blob: 25d7b404a57ea251c21cafc998c06d311eb3c748 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Intercepts an outbound TL interface to instantiate an SRAM used for simulation.
module sim_sram #(
parameter bit InstantiateSram = 1'b0, // 0: leave it as an empty sink, 1: instantiate the SRAM.
parameter int AddrWidth = 32, // Should default to system address width.
parameter int Width = 32, // Should default to system data width.
parameter int Depth = 8, // 8 locations - can be higher if sim demands it.
parameter bit ErrOnRead = 1'b1 // CPU only sinks info.
) (
input logic clk_i,
input logic rst_ni,
// Incoming TL access.
input tlul_pkg::tl_h2d_t tl_in_i,
output tlul_pkg::tl_d2h_t tl_in_o,
// Outgoing TL access.
output tlul_pkg::tl_h2d_t tl_out_o,
input tlul_pkg::tl_d2h_t tl_out_i
);
`ifdef SYNTHESIS
// Induce a compilation error by instantiating a non-existent module. This file should not be
// compiled for synthesis.
illegal_preprocessor_branch_taken u_illegal_preprocessor_branch_taken();
`else
`include "prim_assert.sv"
`ASSERT_INIT(WidthAlignment_A, Width[2:0] == 0)
localparam int WidthBytes = Width >> 3;
// Socket signals.
tlul_pkg::tl_h2d_t tl_socket_h2d[2];
tlul_pkg::tl_d2h_t tl_socket_d2h[2];
logic dev_select;
// Separate interface to set the SRAM start address (done by the testbench) & monitor the SRAM
// access.
sim_sram_if #(
.AddrWidth(AddrWidth)
) u_sim_sram_if (
.clk_i,
.rst_ni,
.tl_h2d(tl_socket_h2d[1]),
.tl_d2h(tl_socket_d2h[1])
);
// Split the incoming access into two.
tlul_socket_1n #(
.N (2),
.HReqPass (1'b1),
.HRspPass (1'b1),
.DReqPass ({2{1'b1}}),
.DRspPass ({2{1'b1}}),
.HReqDepth(4'h0),
.HRspDepth(4'h0),
.DReqDepth({2{4'h0}}),
.DRspDepth({2{4'h0}})
) u_socket (
.clk_i,
.rst_ni,
.tl_h_i (tl_in_i),
.tl_h_o (tl_in_o),
.tl_d_o (tl_socket_h2d),
.tl_d_i (tl_socket_d2h),
.dev_select_i({1'b0, dev_select})
);
// Logic to select SRAM address range.
assign dev_select = (tl_in_i.a_address >= u_sim_sram_if.start_addr &&
tl_in_i.a_address < (u_sim_sram_if.start_addr + (Depth * WidthBytes)));
// Wire output 0 of the socket to outbound TL interface.
assign tl_out_o = tl_socket_h2d[0];
assign tl_socket_d2h[0] = tl_out_i;
if (InstantiateSram) begin : gen_sram_inst
localparam int SramAddrWidth = $clog2(Depth);
logic sram_req;
logic sram_we;
logic [SramAddrWidth-1:0] sram_addr;
logic [ Width-1:0] sram_wdata;
logic [ Width-1:0] sram_wmask;
logic [ Width-1:0] sram_rdata;
logic sram_rvalid;
tlul_adapter_sram #(
.SramAw (SramAddrWidth),
.SramDw (Width),
.ErrOnRead (ErrOnRead),
.Outstanding(2)
) u_tl_adapter_sim_sram (
.clk_i,
.rst_ni,
.tl_i(tl_socket_h2d[1]),
.tl_o(tl_socket_d2h[1]),
.req_o (sram_req),
.gnt_i (1'b1),
.we_o (sram_we),
.addr_o (sram_addr),
.wdata_o (sram_wdata),
.wmask_o (sram_wmask),
.rdata_i (sram_rdata),
.rvalid_i(sram_rvalid),
.rerror_i(2'b00)
);
prim_ram_1p #(
.Width (Width),
.Depth (Depth),
.DataBitsPerMask(WidthBytes)
) u_sram (
.clk_i,
.req_i (sram_req),
.write_i(sram_we),
.addr_i (sram_addr),
.wdata_i(sram_wdata),
.wmask_i(sram_wmask),
.rdata_o(sram_rdata)
);
// Valid data from the SRAM appears 1 cycle after the sram_req.
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
sram_rvalid <= 1'b0;
end else begin
sram_rvalid <= sram_req & ~sram_we;
end
end
end : gen_sram_inst
else begin : gen_no_sram
tlul_sink u_tlul_sink (
.clk_i,
.rst_ni,
.tl_i(tl_socket_h2d[1]),
.tl_o(tl_socket_d2h[1])
);
end : gen_no_sram
`endif
endmodule