Quartus® Prime Pro Edition User Guide: Design Recommendations

ID 683082
Date 12/11/2024
Public
Document Table of Contents

1.4.1.11. Specifying Initial Memory Contents at Power-Up

Your synthesis tool may offer various ways to specify the initial contents of an inferred memory. There are slight power-up and initialization differences between dedicated RAM blocks and the MLAB memory, due to the continuous read of the MLAB.

Intel FPGA dedicated RAM block outputs always power-up to zero, and are set to the initial value on the first read. For example, if address 0 is pre-initialized to FF, the RAM block powers up with the output at 0. A subsequent read after power-up from address 0 outputs the pre-initialized value of FF. Therefore, if a RAM powers up and an enable (read enable or clock enable) is held low, the power-up output of 0 maintains until the first valid read cycle. The synthesis tool implements MLAB using registers that power-up to 0, but initialize to their initial value immediately at power-up or reset. Therefore, the initial value is seen, regardless of the enable status. The Quartus® Prime software maps inferred memory to MLABs when the HDL code specifies an appropriate ramstyle attribute.

In Verilog HDL, you can use an initial block to initialize the contents of an inferred memory. Quartus® Prime Pro Edition synthesis automatically converts the initial block into a Memory Initialization File (.mif) for the inferred RAM.

Verilog HDL RAM with Initialized Contents

module ram_with_init(
   output reg [7:0] q,
   input [7:0] d,
   input [4:0] write_address, read_address,
   input we, clk
);
   reg [7:0] mem [0:31];
   integer i;

   initial begin
      for (i = 0; i < 32; i = i + 1)
         mem[i] = i[7:0];
   end

   always @ (posedge clk) begin
      if (we)
         mem[write_address] <= d;
      q <= mem[read_address];
   end
endmodule

Quartus® Prime Pro Edition synthesis and other synthesis tools also support the $readmemb and $readmemh attributes. These attributes allow RAM initialization and ROM initialization work identically in synthesis and simulation.

Verilog HDL RAM Initialized with the readmemb Command

reg [7:0] ram[0:15];
initial 
begin
	$readmemb("ram.txt", ram);
end

In VHDL, you can initialize the contents of an inferred memory by specifying a default value for the corresponding signal. Quartus® Prime Pro Edition synthesis automatically converts the default value into a .mif file for the inferred RAM.

VHDL RAM with Initialized Contents

LIBRARY ieee;
USE ieee.std_logic_1164.all;
use ieee.numeric_std.all;

ENTITY ram_with_init IS
    PORT(
            clock: IN STD_LOGIC;
            data: IN UNSIGNED (7 DOWNTO 0);
            write_address: IN integer RANGE 0 to 31;
            read_address: IN integer RANGE 0 to 31;
            we: IN std_logic;
            q: OUT UNSIGNED (7 DOWNTO 0));
END;

ARCHITECTURE rtl OF ram_with_init IS

    TYPE MEM IS ARRAY(31 DOWNTO 0) OF unsigned(7 DOWNTO 0);
    FUNCTION initialize_ram
        return MEM is
        variable result : MEM;
    BEGIN 
        FOR i IN 31 DOWNTO 0 LOOP
            result(i) := to_unsigned(natural(i), natural'(8));
        END LOOP; 
        RETURN result;
    END initialize_ram;

    SIGNAL ram_block : MEM := initialize_ram;
BEGIN
    PROCESS (clock)
    BEGIN
        IF (rising_edge(clock)) THEN
            IF (we = '1') THEN
            ram_block(write_address) <= data;
            END IF;
            q <= ram_block(read_address);
        END IF;
    END PROCESS;
END rtl;

Verilog HDL Single-Clock, Simple Dual-Port RAM with Synchronous Reset

// Simple Dual-Port Block with Single Clock

module simple_dual_port_ram_single_clock
#(
   parameter DATA_WIDTH = 8,
   parameter ADDR_WIDTH = 6
)
(
	input clk, clr, we,
	input [ADDR_WIDTH-1:0] waddr,
	input [ADDR_WIDTH-1:0] raddr,
	input [DATA_WIDTH-1:0] data_in,
	output reg [DATA_WIDTH-1:0] data_out
);

(*ramstyle = "M20K"*) reg [DATA_WIDTH-1:0] memory[2**ADDR_WIDTH-1:0];

always @(posedge clk) begin
	if (clr) begin
	   data_out <= 0;
	end
	else begin
          data_out <= memory[raddr];
	end
end

always @(posedge clk) begin
	if (we) begin
	   memory[waddr] <= data_in;
	end
end	
	

endmodule

RAM inference with synchronous reset is supported for single-port, simple-dual port, and true dual port RAM.

Verilog HDL Single-Clock, Simple Dual-Port RAM with Asynchronous Reset

// Simple Dual-Port Block with Single Clock

module simple_dual_port_ram_single_clock_aclr
#(
   parameter DATA_WIDTH = 8,
   parameter ADDR_WIDTH = 6
)
(
	input clk, clr, we,
	input [ADDR_WIDTH-1:0] waddr,
	input [ADDR_WIDTH-1:0] raddr,
	input [DATA_WIDTH-1:0] data_in,
	output reg [DATA_WIDTH-1:0] data_out
);

(*ramstyle = "M20K"*) reg [DATA_WIDTH-1:0] memory[2**ADDR_WIDTH-1:0];


always @(posedge clk or posedge clr) begin
	if (clr) begin
	   data_out <= 0;
	end
	else begin
           data_out <= memory[raddr];
	end
end

always @(posedge clk) begin
	if (we) begin
		memory[waddr] <= data_in;
	end
end	
	

endmodule

RAM inference with asynchronous reset is supported for single-port and simple-dual port RAM.