Quartus® Prime Pro Edition User Guide: Design Recommendations
1.4.1.12. 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.
Altera 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.