Intel® Quartus® Prime Pro Edition用户指南: 设计建议

ID 683082
日期 9/28/2020
Public

本文档可提供新的版本。客户应 单击此处 前往查看最新版本。

文档目录

1.4.1.8. 真双端口同步RAM

本节中的代码示例显示了推断双端口同步RAM的Verilog HDL和VHDL代码。 不同的综合工具对这些类型的存储器的支持可能有所不同。

Intel FPGA同步存储器模块有两个独立的地址端口,允许同时在两个唯一地址上进行操作。如果读取操作和写入操作共享相同的地址,那么它们可以共享相同的端口。

Intel® Quartus® Prime软件可在Verilog HDL和VHDL中推断真双端口RAM,具有以下特征:

  • 在同一时钟周期内独立读取或写入操作的任意组合。
  • 最多两个唯一的端口地址。
  • 在一个时钟周期中,具有一个或两个唯一地址,它们可以执行:
    • 两次读取和一次写入
    • 两次写入和一次读取
    • 两次写入和两次读取

在同步RAM模块体系结构中,两个端口之间没有优先级。因此,如果同时在两个端口上写入相同的位置,那么结果在器件体系结构中是不确定的。如果要在专用硬件存储器模块中实现设计,那么必须确保HDL代码不暗含写入存储器模块的优先级。例如,如果两个端口都在同一处理模块中定义,那么代码将被综合和顺序仿真,以使两个端口之间具有优先级。如果代码确实暗含了优先级,那么该逻辑不能在器件RAM模块中实现,而是在普通逻辑单元中实现。您还必须考虑RAM模块的read-during-write行为,以确保能够将其直接映射到器件RAM体系结构。

当在同一端口上对同一地址进行读取和写入操作时,读取操作可能会表现如下:

  • Read new data Intel® Arria® 10 Intel® Stratix® 10 器件支持此行为。
  • Read old data不支持。

当在同一地址的不同端口上发生读取和写入操作(也称为混合端口)时,读取操作可能会表现如下:

  • Read new data Intel® Quartus® Prime Pro Edition synthesis通过在同步存储器模块周围创建旁路逻辑来支持此模式。
  • Read old data Intel® Arria® 10 Intel® Cyclone® 10器件支持此行为。
  • Read don’t care—同步存储器模块在简单双端口模式下支持此行为。

Verilog HDL单时钟代码样例直接映射到同步 Intel® Arria® 10存储器模块 。当在同一端口上对同一地址进行读写操作时,将读取正在写入存储器的新数据。当在同一地址的不同端口上进行读写操作时,将读取存储器中的旧数据。同时写入两个端口上的相同位置会导致不确定行为。

如果生成此设计的双时钟版本来描述相同的行为,那么目标器件中的推断存储器将呈现未定义的混合端口read-during-write行为,因为这取决于时钟之间的关系。

具有单时钟的Verilog HDL真双端口RAM

/ Quartus Prime Verilog Template
// True Dual Port RAM with single clock
//
// Read-during-write behavior is undefined for mixed ports 
// and "new data" on the same port

module true_dual_port_ram_single_clock
#(parameter DATA_WIDTH=8, parameter ADDR_WIDTH=6)
(
	input [(DATA_WIDTH-1):0] data_a, data_b,
	input [(ADDR_WIDTH-1):0] addr_a, addr_b,
	input we_a, we_b, clk,
	output reg [(DATA_WIDTH-1):0] q_a, q_b
);

	// Declare the RAM variable
	reg [DATA_WIDTH-1:0] ram[2**ADDR_WIDTH-1:0];

	// Port A 
	always @ (posedge clk)
	begin
		if (we_a) 
		begin
			ram[addr_a] = data_a;
		end
		q_a <= ram[addr_a];
	end 

	// Port B 
	always @ (posedge clk)
	begin
		if (we_b) 
		begin
			ram[addr_b] = data_b;
		end
		q_b <= ram[addr_b];
	end

endmodule

VHDL读语句示例

-- Port A
process(clk)
	begin
	if(rising_edge(clk)) then 
		if(we_a = '1') then
			ram(addr_a) := data_a;
		end if;
		q_a <= ram(addr_a);
	end if;
end process;

-- Port B
process(clk)
	begin
	if(rising_edge(clk)) then 
		if(we_b = '1') then
			ram(addr_b) := data_b;
		end if;
		q_b <= ram(addr_b);
	end if;
end process;

VHDL单时钟代码样例直接映射到Intel FPGA同步存储器。当在同一端口上对同一地址进行读写操作时,将读取写入存储器的新数据。当在同一地址的不同端口上进行读取和写入操作时,此行为将 Intel® Arria® 10 Intel® Cyclone® 10器件产生旧数据 对于 Intel® Stratix® 10器件是未定义的 。对两个端口上相同位置的同时写操作将导致不确定的行为。

如果生成此设计的双时钟版本来描述相同的行为,那么目标器件中的存储器将呈现未定义的混合端口read-during-write行为,因为这取决于时钟之间的关系。

具有单时钟的VHDL真双端口RAM

-- Quartus Prime VHDL Template
-- True Dual-Port RAM with single clock
--
-- Read-during-write behavior is undefined for mixed ports 
-- and "new data" on the same port

library ieee;
use ieee.std_logic_1164.all;

entity true_dual_port_ram_single_clock is

	generic 
	(
		DATA_WIDTH : natural := 8;
		ADDR_WIDTH : natural := 6
	);

	port 
	(
		clk		: in std_logic;
		addr_a	: in natural range 0 to 2**ADDR_WIDTH - 1;
		addr_b	: in natural range 0 to 2**ADDR_WIDTH - 1;
		data_a	: in std_logic_vector((DATA_WIDTH-1) downto 0);
		data_b	: in std_logic_vector((DATA_WIDTH-1) downto 0);
		we_a	: in std_logic := '1';
		we_b	: in std_logic := '1';
		q_a		: out std_logic_vector((DATA_WIDTH -1) downto 0);
		q_b		: out std_logic_vector((DATA_WIDTH -1) downto 0)
	);

end true_dual_port_ram_single_clock;

architecture rtl of true_dual_port_ram_single_clock is

	-- Build a 2-D array type for the RAM
	subtype word_t is std_logic_vector((DATA_WIDTH-1) downto 0);
	type memory_t is array(2**ADDR_WIDTH-1 downto 0) of word_t;

	-- Declare the RAM 
	shared variable ram : memory_t;

begin

	-- Port A
	process(clk)
	begin
	if(rising_edge(clk)) then 
		if(we_a = '1') then
			ram(addr_a) := data_a;
		end if;
		q_a <= ram(addr_a);
	end if;
	end process;

	-- Port B 
	process(clk)
	begin
	if(rising_edge(clk)) then 
		if(we_b = '1') then
			ram(addr_b) := data_b;
		end if;
  	    q_b <= ram(addr_b);
	end if;
	end process;

end rtl;