Files
b210-k7-fpga/lib/control/ram_2port_impl.vh
T
Javier Valenzuela 27aae37722 fpga: lib: Add read-only strategy for port B in 2-port RAM
Original-commit: 69c549efab2fd536808f1ba032c278085217ba6d
2022-06-28 16:33:05 -05:00

157 lines
4.1 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
) (
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] = {DWIDTH{1'b0}};
end
end
end endgenerate
reg [DWIDTH-1:0] doa_r = 'h0, dob_r = 'h0;
generate if (OUT_REG == 1) begin
// A 2 clock cycle read latency with improve clock-to-out timing
reg [DWIDTH-1:0] doa_rr = 'h0, dob_rr = 'h0;
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
ERROR_Invalid_RW_MODE_selection();
end endgenerate
endmodule