Description
How do I Infer LRAM2K_SDPs when targeting a Speedster®7t device? What is the process?
Answer
LRAM2K_SDP implements a 2-kb simple-dual-port (SDP) memory block with one write port and one read port. Refer to the Memories chapter in the Speedster7t IP Component User Guide (UG086) for details on the LRAM2K_SDP. The LRAM2K_SDP is inferrable using RTL constructs commonly used to infer synchronous and combinatorial RAMs and ROMs, with a variety of clock enable and reset schemes and polarities.
Below is an example of LRAM2K_SDP inferencing.
LRAM2K_SDP Inference
//---------------------------------------------------------------------------------
//
// Copyright (c) 2020 Achronix Semiconductor Corp.
// All Rights Reserved.
//
//
// This software constitutes an unpublished work and contains
// valuable proprietary information and trade secrets belonging
// to Achronix Semiconductor Corp.
//
// This software may not be used, copied, distributed or disclosed
// without specific prior written authorization from
// Achronix Semiconductor Corp.
//
// The copyright notice above does not evidence any actual or intended
// publication of such software.
//
//
//---------------------------------------------------------------------------------
// Design: LRAM2K_SDP Inference
// An example to infer an LRAM2K_SDP in a Speedster7t design
//---------------------------------------------------------------------------------
`timescale 1ps / 1ps
module lram2k_sdp
#(
parameter ADDR_WIDTH = 5,
parameter DATA_WIDTH = 72,
parameter OUT_REG_EN = 0,
parameter INIT_FILE_NAME = ""
)
(
// Clocks and resets
input wire wr_clk,
input wire rd_clk,
// Enables
input wire we,
input wire rstreg,
// Address and data
input wire [ADDR_WIDTH-1:0] wr_addr,
input wire [ADDR_WIDTH-1:0] rd_addr,
input wire [DATA_WIDTH-1:0] wr_data,
// Output
output reg [DATA_WIDTH-1:0] rd_data
);
// Determine if size is small enough for an LRAM2K_SDP
localparam MEM_LRAM = ( ((DATA_WIDTH <= 36) && (ADDR_WIDTH <= 6)) ||
((DATA_WIDTH <= 72) && (ADDR_WIDTH <= 5)) ||
((DATA_WIDTH <= 144) && (ADDR_WIDTH <= 4)) ) ? 1 : 0;
// Define combinatorial and registered outputs from memory array
logic [DATA_WIDTH-1:0] rd_data_int;
logic [DATA_WIDTH-1:0] rd_data_reg;
logic read_collision;
always @(posedge rd_clk)
if (~rstreg)
rd_data_reg <= {DATA_WIDTH{1'b0}};
else
rd_data_reg <= rd_data_int;
// Need a generate block to apply the appropriate syn_ramstyle to the memory array
// Rest of the the code has to be within the generate block to access that variable
generate if ( MEM_LRAM == 1) begin : gb_lram
logic [DATA_WIDTH-1:0] mem [(2**ADDR_WIDTH)-1:0] /* synthesis syn_ramstyle = "logic" */;
// If an initialisation file exists, then initialise the memory
if ( INIT_FILE_NAME != "" ) begin : gb_init
initial
$readmemh( INIT_FILE_NAME, mem );
end
// Writing. Inference does not currently support byte enables
// Also generate the signals to detect if there is a memory collision
logic [ADDR_WIDTH-1:0] wr_addr_d;
always @(posedge wr_clk)
if( we ) begin
mem[wr_addr] <= wr_data;
wr_addr_d <= wr_addr;
end
// LRAM2K_SDP only supports the WRITE_FIRST mode. So if rd_addr = wr_addr then
// write takes priority and read value is invalid
// The value from the array is combinatorial, (this is different than for BRAM72K_SDP)
// Write address is effective on the cycle it is writing to the memory, (i.e. it is registered)
assign read_collision = (wr_addr_d == rd_addr);
assign rd_data_int = (read_collision) ? {DATA_WIDTH{1'bx}} : mem[rd_addr];
end
endgenerate
// Select output based on whether output register is enabled
assign rd_data = (OUT_REG_EN) ? rd_data_reg : rd_data_int;
endmodule : lram2k_sdp