mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-22 04:47:25 -04:00
It turned out that with the default value of 1, Vivado infers a separate 18 Kbit BRAM instance for each bit of the 32-bit word for the FPGA examples. This can be very wasteful in terms of resource utilization especially for smaller configurations. As our examples don't use ECC or parity and mainly target simualation and FPGA, it's better to use a value of 8 for the DataBitsPerMask parameter. Vivado will then not distribute words across different BRAM instances which results in more efficient FPGA resource utilization. For a detailed analysis and explanation, please refer to lowRISC/Ibex#1587. Signed-off-by: Pirmin Vogel <vogelpi@lowrisc.org>
91 lines
2.2 KiB
Systemverilog
91 lines
2.2 KiB
Systemverilog
// Copyright lowRISC contributors.
|
|
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
/**
|
|
* Dual-port RAM with 1 cycle read/write delay, 32 bit words.
|
|
*/
|
|
|
|
`include "prim_assert.sv"
|
|
|
|
module ram_2p #(
|
|
parameter int Depth = 128,
|
|
parameter MemInitFile = ""
|
|
) (
|
|
input clk_i,
|
|
input rst_ni,
|
|
|
|
input a_req_i,
|
|
input a_we_i,
|
|
input [ 3:0] a_be_i,
|
|
input [31:0] a_addr_i,
|
|
input [31:0] a_wdata_i,
|
|
output logic a_rvalid_o,
|
|
output logic [31:0] a_rdata_o,
|
|
|
|
input b_req_i,
|
|
input b_we_i,
|
|
input [ 3:0] b_be_i,
|
|
input [31:0] b_addr_i,
|
|
input [31:0] b_wdata_i,
|
|
output logic b_rvalid_o,
|
|
output logic [31:0] b_rdata_o
|
|
);
|
|
|
|
localparam int Aw = $clog2(Depth);
|
|
|
|
logic [Aw-1:0] a_addr_idx;
|
|
assign a_addr_idx = a_addr_i[Aw-1+2:2];
|
|
logic [31-Aw:0] unused_a_addr_parts;
|
|
assign unused_a_addr_parts = {a_addr_i[31:Aw+2], a_addr_i[1:0]};
|
|
|
|
logic [Aw-1:0] b_addr_idx;
|
|
assign b_addr_idx = b_addr_i[Aw-1+2:2];
|
|
logic [31-Aw:0] unused_b_addr_parts;
|
|
assign unused_b_addr_parts = {b_addr_i[31:Aw+2], b_addr_i[1:0]};
|
|
|
|
// Convert byte mask to SRAM bit mask.
|
|
logic [31:0] a_wmask;
|
|
logic [31:0] b_wmask;
|
|
always_comb begin
|
|
for (int i = 0 ; i < 4 ; i++) begin
|
|
// mask for read data
|
|
a_wmask[8*i+:8] = {8{a_be_i[i]}};
|
|
b_wmask[8*i+:8] = {8{b_be_i[i]}};
|
|
end
|
|
end
|
|
|
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
|
if (!rst_ni) begin
|
|
a_rvalid_o <= '0;
|
|
b_rvalid_o <= '0;
|
|
end else begin
|
|
a_rvalid_o <= a_req_i;
|
|
b_rvalid_o <= b_req_i;
|
|
end
|
|
end
|
|
|
|
prim_ram_2p #(
|
|
.Width(32),
|
|
.Depth(Depth),
|
|
.DataBitsPerMask(8),
|
|
.MemInitFile(MemInitFile)
|
|
) u_ram (
|
|
.clk_a_i (clk_i),
|
|
.clk_b_i (clk_i),
|
|
.cfg_i ('0),
|
|
.a_req_i (a_req_i),
|
|
.a_write_i (a_we_i),
|
|
.a_addr_i (a_addr_idx),
|
|
.a_wdata_i (a_wdata_i),
|
|
.a_wmask_i (a_wmask),
|
|
.a_rdata_o (a_rdata_o),
|
|
.b_req_i (b_req_i),
|
|
.b_write_i (b_we_i),
|
|
.b_wmask_i (b_wmask),
|
|
.b_addr_i (b_addr_idx),
|
|
.b_wdata_i (b_wdata_i),
|
|
.b_rdata_o (b_rdata_o)
|
|
);
|
|
|
|
endmodule
|