インテル® Quartus® Primeプロ・エディションのユーザーガイド: デザイン上の推奨事項

ID 683082
日付 4/13/2020
Public

このドキュメントの新しいバージョンが利用できます。お客様は次のことを行ってください。 こちらをクリック 最新バージョンに移行する。

ドキュメント目次

1.4.1.8. トゥルー・デュアル・ポート同期RAM

このセクションのコード例は、真のデュアルポート同期RAMを推論するVerilog HDLおよびVHDLコードを示しています。 異なる合成ツールは、これらのタイプのメモリーのサポートが異なる場合があります。

Intel FPGA同期メモリーブロックには2つの独立したアドレスポートがあり、2つの一意のアドレスを同時に操作できます。リード操作とライト操作は、同じアドレスを共有している場合、同じポートを共有できます。

インテル® Quartus® Primeソフトウェアは、Verilog HDLおよびVHDLの真のデュアルポートRAMを推測します。次の特徴があります。

  • 同じクロックサイクルでの独立したリードまたは書き込み操作の任意の組み合わせ。
  • 最大2つの一意のポートアドレス。
  • 1クロックサイクルで、1つまたは2つの一意のアドレスで、以下を実行できます。
    • 2つのリードと1つのライト
    • 2つのライトと1つのリード
    • 2つのライトと2つのリード

同期RAMブロック・アーキテクチャーでは、2つのポート間に優先順位はありません。したがって、両方のポートの同じ場所に同時に書き込む場合、結果はデバイス・アーキテクチャーで不確定になります。デザインを専用ハードウェア・メモリー・ブロックに実装する場合、HDLコードがメモリーブロックへの書き込みの優先順位を暗示していないことを確認する必要があります。たとえば、両方のポートが同じプロセスブロックで定義されている場合、2つのポート間に優先順位が設定されるように、コードが順番に合成およびシミュレートされます。コードに優先順位が含まれている場合、ロジックはデバイスのRAMブロックに実装できず、通常のロジックセルに実装されます。また、RAMブロックをデバイスRAMアーキテクチャーに直接マップできるようにするために、RAMブロックのリード中のリード動作を考慮する必要があります。

同じポートで同じアドレスのread and write動作が発生すると、リード操作は次のように動作します。

  • Read new data インテル® Arria® 10 そして インテル® Stratix® 10 デバイスはこの動作をサポートします。
  • Read old dataサポートされていません。

同じアドレスの異なるポート(混合ポートとも呼ばれる)でリードおよびライト動作が発生すると、リード操作は次のように動作します。

  • Read new data インテル® Quartus® Primeプロ・エディション 合成は、同期メモリーブロックの周りにバイパスロジックを作成することにより、このモードをサポートします。
  • Read old data インテル® Arria® 10そして インテル® Cyclone® 10デバイスはこの動作をサポートします。
  • Read don’t care—同期メモリーブロックは、シンプル・デュアル・ポートモードでこの動作をサポートします。

Verilog HDLシングル・クロック・コード・サンプルは、 同期 インテル® Arria® 10メモリーブロックを直接マップします。同じアドレスの同じポートでリードおよびライト動作が発生すると、メモリーに書き込まれている新しいデータが読み出されます。同じアドレスの異なるポートでリードおよびライト動作が発生すると、メモリー内の古いデータが読み出されます。両方のポートの同じ場所に同時に書き込むと、動作が不確定になります。

同じ動作を説明するこのデザインのデュアル・クロック・バージョンを生成すると、クロック間の関係に依存するため、ターゲットデバイスのメモリーは未定義の混合ポートのead-during-write動作を示します。

Verilog HDL True Dual-Port RAM with Single Clock

/ 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 Read Statement Example

-- 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同期メモリーに直接マップします。同じアドレスの同じポートでread and write動作が発生すると、メモリーへの新しいデータ書き込みが読み出されます。同じアドレスの異なるポートでread and write動作が発生すると、この動作により、 インテル® Arria® 10および インテル® Cyclone® 10デバイスの古いデータが生成され、 インテル® Stratix® 10デバイスの場合は未定義です。両方のポートの同じ場所への同時ライト動作により、不確定な動作が発生します。

同じ動作を説明するこのデザインのデュアル・クロック・バージョンを生成すると、クロック間の関係に依存するため、ターゲットデバイスのメモリーは未定義の混合ポートのread-during-write動作を示します。

VHDL True Dual-Port RAM with Single Clock

-- 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;