Description
How do I Infer LRAMs when targeting a Speedcore™ design? What is the process?
Answer
The logic RAM (LRAM) implements a 4096-bit memory block with one write port and one read port. Refer to the Memories chapter in the Speedcore IP Component Library User Guide (UG065) for details on the LRAM.
An example of how to infer an LRAM with an output register is shown below.
LRAM 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: LRAM Inference
// An example to infer an LRAM in Speedcore designs
//---------------------------------------------------------------------------------
`timescale 1ps / 1ps
module lram
#(
parameter ADDR_WIDTH = 7,
parameter DATA_WIDTH = 32,
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 LRAM
localparam MEM_LRAM = ((DATA_WIDTH <= 32) && (ADDR_WIDTH <= 7)) ? 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_ram" */;
// 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
// LRAM 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 BRAM)
// 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 : lram