Quartus® Prime Pro Edition User Guide: Design Recommendations

ID 683082
Date 9/30/2024
Public
Document Table of Contents

1.4.1.7. Simple Dual-Port, Dual-Clock Synchronous RAM

With dual-clock designs, synthesis tools cannot accurately infer the read-during-write behavior because it depends on the timing of the two clocks within the target device. Therefore, the read-during-write behavior of the synthesized design is undefined and may differ from your original HDL code.

Verilog HDL Simple Dual-Port, Dual-Clock Synchronous RAM

module simple_dual_port_ram_dual_clock
#(parameter DATA_WIDTH=8, parameter ADDR_WIDTH=6)
(
	input [(DATA_WIDTH-1):0] data,
	input [(ADDR_WIDTH-1):0] read_addr, write_addr,
	input we, read_clock, write_clock,
	output reg [(DATA_WIDTH-1):0] q
);

	// Declare the RAM variable
	reg [DATA_WIDTH-1:0] ram[2**ADDR_WIDTH-1:0];
	
	always @ (posedge write_clock)
	begin
		// Write
		if (we)
			ram[write_addr] <= data;
	end
	
	always @ (posedge read_clock)
	begin
		// Read 
		q <= ram[read_addr];
	end
	
endmodule

VHDL Simple Dual-Port, Dual-Clock Synchronous RAM

LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY dual_clock_ram IS
	PORT (
		clock1, clock2: IN STD_LOGIC;
		data: IN STD_LOGIC_VECTOR (3 DOWNTO 0);
		write_address: IN INTEGER RANGE 0 to 31;
		read_address: IN INTEGER RANGE 0 to 31;
		we: IN STD_LOGIC;
		q: OUT STD_LOGIC_VECTOR (3 DOWNTO 0)
	);
END dual_clock_ram;
ARCHITECTURE rtl OF dual_clock_ram IS
	TYPE MEM IS ARRAY(0 TO 31) OF STD_LOGIC_VECTOR(3 DOWNTO 0);
	SIGNAL ram_block: MEM;
	SIGNAL read_address_reg : INTEGER RANGE 0 to 31;
BEGIN
	PROCESS (clock1)
	BEGIN
		IF (rising_edge(clock1)) THEN
			IF (we = '1') THEN
				ram_block(write_address) <= data;
			END IF;
		END IF;
	END PROCESS;
	PROCESS (clock2)
	BEGIN
		IF (rising_edge(clock2)) THEN
			q <= ram_block(read_address_reg);
			read_address_reg <= read_address;
		END IF;
	END PROCESS;
END rtl;