| // 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 |