Description
How do I infer BRAM72K_SDPs when targeting a Speedster7t device? What is the process?
Answer
The block RAM primitive BRAM72K_SDP implements a 72-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 BRAM72K_SDP.
The BRAM72K_SDP is inferrable using RTL constructs commonly used for synchronous RAMs and ROMs, with a variety of clock enable and reset schemes and polarities.
Note
ECC functionality is not inferrable.
To ensure a BRAM72K_SDP is inferred as opposed to an LRAM2K_SDP, in the memory declaration, use one of the following synthesis attributes.
// Infer BRAM memory array. Will create memory using BRAM72K_SDP set to a maximum width of 72-bit
logic [DATA_WIDTH-1:0] mem [(2**ADDR_WIDTH)-1:0] /* synthesis syn_ramstyle = "block_ram" */;
// Alternatively infer wide BRAM memory array with BRAM72K_SDP primitives set to 144-bit width
logic [DATA_WIDTH-1:0] mem [(2**ADDR_WIDTH)-1:0] /* synthesis syn_ramstyle = "large_ram" */;
Below is an example of BRAM72K_SDP inferencing.
BRAM72K_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.
//
//---------------------------------------------------------------------------
// Description : BRAM72K_SDP Inference
// An example to infer a BRAM72K_SDP in
// a Speedster7t design
//---------------------------------------------------------------------------
`timescale 1ps / 1ps
module bram72k_sdp
#(
parameter ADDR_WIDTH = 5,
parameter DATA_WIDTH = 80,
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 rd_en,
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
);
localparam WIDE_BRAM = (DATA_WIDTH > 72) ? 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;
generate if ( WIDE_BRAM == 1 ) begin : gb_wide_bram
logic [DATA_WIDTH-1:0] mem [(2**ADDR_WIDTH)-1:0] /* synthesis syn_ramstyle = "large_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
always @(posedge wr_clk)
if( we )
begin
mem[wr_addr] <= wr_data;
end
// BRAM72K_SDP supports WRITE_FIRST mode only, (write takes precedence over read)
// Calculate if there will be a collision
// write takes priority and read value is invalid
// Both wr_addr and rd_addr have registered operations on the memory array
assign read_collision = (wr_addr == rd_addr) && we;
always @(posedge rd_clk)
if( rd_en )
begin
// Read collisions cannot be modelled in synthesis, so use solely in simulation
// synthesis synthesis_off
if( read_collision )
rd_data_int <= {DATA_WIDTH{1'bx}};
else
// synthesis synthesis_on
rd_data_int <= mem[rd_addr];
end
end
else
begin : gb_bram
logic [DATA_WIDTH-1:0] mem [(2**ADDR_WIDTH)-1:0] /* synthesis syn_ramstyle = "block_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
always @(posedge wr_clk)
if( we )
begin
mem[wr_addr] <= wr_data;
end
// BRAM72K_SDP supports WRITE_FIRST mode only, (write takes precedence over read)
// Calculate if there will be a collision
// write takes priority and read value is invalid
// Both wr_addr and rd_addr have registered operations on the memory array
assign read_collision = (wr_addr == rd_addr) && we;
always @(posedge rd_clk)
if( rd_en )
begin
// Read collisions cannot be modelled in synthesis, so use solely in simulation
// synthesis synthesis_off
if( read_collision )
rd_data_int <= {DATA_WIDTH{1'bx}};
else
// synthesis synthesis_on
rd_data_int <= mem[rd_addr];
end
end
endgenerate
// Select output based on whether output register is enabled
assign rd_data = (OUT_REG_EN) ? rd_data_reg : rd_data_int;
endmodule : bram72k_sdp