Files
Markus Schill 6386d90b35 fpga: lib: Add initial value to ram_2port
Original-commit: da5c64bf4f631012b5969890a751084c998dd154
2025-04-09 13:50:17 -05:00

159 lines
4.3 KiB
Systemverilog

//
// Copyright 2011 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Used by ram_2port.v
// Requires `RAM_MOD_NAME and `RAM_DIRECTIVE to be defined
module `RAM_MOD_NAME #(
parameter DWIDTH = 32, // Width of the memory block
parameter AWIDTH = 9, // log2 of the depth of the memory block
parameter RW_MODE = "READ-FIRST", // Read-write mode {READ-FIRST, WRITE-FIRST, NO-CHANGE, B-READ-ONLY}
parameter OUT_REG = 0, // Instantiate an output register? (+1 cycle of read latency)
parameter INIT_FILE = "", // Optionally initialize memory with this file
parameter INIT_VAL = {DWIDTH{1'b0}} // Optionally initialize output registers with this value and
// memory will be filled with this value if INIT_FILE is empty
) (
input wire clka,
input wire ena,
input wire wea,
input wire [AWIDTH-1:0] addra,
input wire [DWIDTH-1:0] dia,
output wire [DWIDTH-1:0] doa,
input wire clkb,
input wire enb,
input wire web,
input wire [AWIDTH-1:0] addrb,
input wire [DWIDTH-1:0] dib,
output wire [DWIDTH-1:0] dob
);
`RAM_DIRECTIVE reg [DWIDTH-1:0] ram [(1<<AWIDTH)-1:0];
// Initialize ram to a specified file or to all zeros to match hardware
generate if (INIT_FILE != "") begin
initial begin
$readmemh(INIT_FILE, ram, 0, (1<<AWIDTH)-1);
end
end else begin
integer i;
initial begin
for (i = 0; i < (1<<AWIDTH); i = i + 1) begin
ram[i] = INIT_VAL;
end
end
end endgenerate
reg [DWIDTH-1:0] doa_r = INIT_VAL, dob_r = INIT_VAL;
generate if (OUT_REG == 1) begin
// A 2 clock cycle read latency with improve clock-to-out timing
reg [DWIDTH-1:0] doa_rr = INIT_VAL, dob_rr = INIT_VAL;
always @(posedge clka)
if (ena) begin
doa_rr <= doa_r;
end
always @(posedge clkb)
if (enb) begin
dob_rr <= dob_r;
end
assign doa = doa_rr;
assign dob = dob_rr;
end else begin
// A 1 clock cycle read latency at the cost of a longer clock-to-out timing
assign doa = doa_r;
assign dob = dob_r;
end endgenerate
generate if (RW_MODE == "READ-FIRST") begin
// When data is written, the prior memory contents at the write
// address are presented on the output port.
always @(posedge clka) begin
if (ena) begin
if (wea) begin
ram[addra] <= dia;
end
doa_r <= ram[addra];
end
end
always @(posedge clkb) begin
if (enb) begin
if (web) begin
ram[addrb] <= dib;
end
dob_r <= ram[addrb];
end
end
end else if (RW_MODE == "WRITE-FIRST") begin
// The data being written to the RAM also resides on the output port.
always @(posedge clka) begin
if (ena) begin
if (wea) begin
ram[addra] <= dia;
doa_r <= dia;
end else begin
doa_r <= ram[addra];
end
end
end
always @(posedge clkb) begin
if (enb) begin
if (web) begin
ram[addrb] <= dib;
dob_r <= dib;
end else begin
dob_r <= ram[addrb];
end
end
end
end else if (RW_MODE == "NO-CHANGE") begin
// This is a no change RAM which retains the last read value on the output during writes
// which is the most power efficient mode.
always @(posedge clka) begin
if (ena) begin
if (wea) begin
ram[addra] <= dia;
end else begin
doa_r <= ram[addra];
end
end
end
always @(posedge clkb) begin
if (enb) begin
if (web) begin
ram[addrb] <= dib;
end else begin
dob_r <= ram[addrb];
end
end
end
end else if (RW_MODE == "B-READ-ONLY") begin
// This is a RAM where port A is using READ-FIRST strategy and port B supports read only.
always @(posedge clka) begin
if (ena) begin
if (wea) begin
ram[addra] <= dia;
end
doa_r <= ram[addra];
end
end
always @(posedge clkb) begin
if (enb) begin
dob_r <= ram[addrb];
end
end
end else begin : gen_error
ERROR_Invalid_RW_MODE_selection ERROR();
end endgenerate
endmodule