Visible to Intel only — GUID: mwh1409959587208
Ixiasoft
Visible to Intel only — GUID: mwh1409959587208
Ixiasoft
1.4.1.8. True Dual-Port Synchronous RAM
Intel FPGA synchronous memory blocks have two independent address ports, allowing for operations on two unique addresses simultaneously. A read operation and a write operation can share the same port if they share the same address.
The Quartus® Prime software infers true dual-port RAMs in Verilog HDL and VHDL, with the following characteristics:
- Any combination of independent read or write operations in the same clock cycle.
- At most two unique port addresses.
- In one clock cycle, with one or two unique addresses, they can perform:
- Two reads and one write
- Two writes and one read
- Two writes and two reads
In the synchronous RAM block architecture, there is no priority between the two ports. Therefore, if you write to the same location on both ports at the same time, the result is indeterminate in the device architecture. You must ensure your HDL code does not imply priority for writes to the memory block, if you want the design to be implemented in a dedicated hardware memory block. For example, if both ports are defined in the same process block, the code is synthesized and simulated sequentially so that there is a priority between the two ports. If your code does imply a priority, the logic cannot be implemented in the device RAM blocks and is implemented in regular logic cells. You must also consider the read-during-write behavior of the RAM block to ensure that it can be mapped directly to the device RAM architecture.
When a read and write operation occurs on the same port for the same address, the read operation may behave as follows:
- Read new data— Arria® 10 and Stratix® 10 devices support this behavior.
- Read old data—Not supported.
When a read and write operation occurs on different ports for the same address (also known as mixed port), the read operation may behave as follows:
- Read new data— Quartus® Prime Pro Edition synthesis supports this mode by creating bypass logic around the synchronous memory block.
- Read old data— Arria® 10 and Cyclone® 10 devices support this behavior.
- Read don’t care—Synchronous memory blocks support this behavior in simple dual-port mode.
The Verilog HDL single-clock code sample maps directly into synchronous Arria® 10 memory blocks. When a read and write operation occurs on the same port for the same address, the new data being written to the memory is read. When a read and write operation occurs on different ports for the same address, the old data in the memory is read. Simultaneous writes to the same location on both ports results in indeterminate behavior.
If you generate a dual-clock version of this design describing the same behavior, the inferred memory in the target device presents undefined mixed port read-during-write behavior, because it depends on the relationship between the clocks.
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;
The VHDL single-clock code sample maps directly into Intel FPGA synchronous memory. When a read and write operation occurs on the same port for the same address, the new data writing to the memory is read. When a read and write operation occurs on different ports for the same address, the behavior results in old data for Arria® 10 and Cyclone® 10 devices , and is undefined for Stratix® 10 devices. Simultaneous write operations to the same location on both ports results in indeterminate behavior.
If you generate a dual-clock version of this design describing the same behavior, the memory in the target device presents undefined mixed port read-during-write behavior because it depends on the relationship between the clocks.
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;