blob: e168dac8ae2630345adf7b5364ba5f1703e9def8 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// N:1 SRAM arbiter
//
// Parameter
// N: Number of requst port
// DW: Data width (SECDED is not included)
// Aw: Address width
// ArbiterImpl: can be either PPC or BINTREE.
`include "prim_assert.sv"
module prim_sram_arbiter #(
parameter int unsigned N = 4,
parameter int unsigned SramDw = 32,
parameter int unsigned SramAw = 12,
parameter ArbiterImpl = "PPC",
parameter bit EnMask = 1'b 0 // Disable wmask if 0
) (
input clk_i,
input rst_ni,
input [ N-1:0] req_i,
input [SramAw-1:0] req_addr_i [N],
input [ N-1:0] req_write_i,
input [SramDw-1:0] req_wdata_i[N],
input [SramDw-1:0] req_wmask_i[N],
output logic [ N-1:0] gnt_o,
output logic [ N-1:0] rsp_rvalid_o, // Pulse
output logic [SramDw-1:0] rsp_rdata_o[N],
output logic [ 1:0] rsp_error_o[N],
// SRAM Interface
output logic sram_req_o,
output logic [SramAw-1:0] sram_addr_o,
output logic sram_write_o,
output logic [SramDw-1:0] sram_wdata_o,
output logic [SramDw-1:0] sram_wmask_o,
input sram_rvalid_i,
input [SramDw-1:0] sram_rdata_i,
input [1:0] sram_rerror_i
);
typedef struct packed {
logic write;
logic [SramAw-1:0] addr;
logic [SramDw-1:0] wdata;
logic [SramDw-1:0] wmask;
} req_t;
req_t req_packed [N];
for (genvar i = 0 ; i < N ; i++) begin : gen_reqs
assign req_packed[i] = {
req_write_i[i],
req_addr_i [i],
req_wdata_i[i],
(EnMask) ? req_wmask_i[i] : {SramDw{1'b1}}
};
end
localparam int ARB_DW = $bits(req_t);
req_t sram_packed;
assign sram_write_o = sram_packed.write;
assign sram_addr_o = sram_packed.addr;
assign sram_wdata_o = sram_packed.wdata;
assign sram_wmask_o = (EnMask) ? sram_packed.wmask : {SramDw{1'b1}};
if (EnMask == 1'b 0) begin : g_unused
logic unused_wmask;
always_comb begin
unused_wmask = 1'b 1;
for (int unsigned i = 0 ; i < N ; i++) begin
unused_wmask ^= ^req_wmask_i[i];
end
unused_wmask ^= ^sram_packed.wmask;
end
end
if (ArbiterImpl == "PPC") begin : gen_arb_ppc
prim_arbiter_ppc #(
.N (N),
.DW(ARB_DW)
) u_reqarb (
.clk_i,
.rst_ni,
.req_chk_i ( 1'b1 ),
.req_i,
.data_i ( req_packed ),
.gnt_o,
.idx_o ( ),
.valid_o ( sram_req_o ),
.data_o ( sram_packed ),
.ready_i ( 1'b1 )
);
end else if (ArbiterImpl == "BINTREE") begin : gen_tree_arb
prim_arbiter_tree #(
.N (N),
.DW(ARB_DW)
) u_reqarb (
.clk_i,
.rst_ni,
.req_chk_i ( 1'b1 ),
.req_i,
.data_i ( req_packed ),
.gnt_o,
.idx_o ( ),
.valid_o ( sram_req_o ),
.data_o ( sram_packed ),
.ready_i ( 1'b1 )
);
end else begin : gen_unknown
`ASSERT_INIT(UnknownArbImpl_A, 0)
end
logic [N-1:0] steer; // Steering sram_rvalid_i
logic sram_ack; // Ack for rvalid. |sram_rvalid_i
assign sram_ack = sram_rvalid_i & (|steer);
// Request FIFO
prim_fifo_sync #(
.Width (N),
.Pass (1'b0),
.Depth (4) // Assume at most 4 pipelined
) u_req_fifo (
.clk_i,
.rst_ni,
.clr_i (1'b0),
.wvalid_i (sram_req_o & ~sram_write_o), // Push only for read
.wready_o (), // TODO: Generate Error
.wdata_i (gnt_o),
.rvalid_o (), // TODO; Generate error if sram_rvalid_i but rvalid==0
.rready_i (sram_ack),
.rdata_o (steer),
.full_o (),
.depth_o (), // Not used
.err_o ()
);
assign rsp_rvalid_o = steer & {N{sram_rvalid_i}};
for (genvar i = 0 ; i < N ; i++) begin : gen_rsp
assign rsp_rdata_o[i] = sram_rdata_i;
assign rsp_error_o[i] = sram_rerror_i; // No SECDED yet
end
endmodule