Visible to Intel only — GUID: mwh1409959587208
Ixiasoft
Visible to Intel only — GUID: mwh1409959587208
Ixiasoft
2.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 Intel® 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—This mode matches the behavior of synchronous memory blocks.
- Read old data— This mode is supported only in device families that support M144K and M9K memory blocks.
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— Intel® Quartus® Prime Standard Edition integrated synthesis supports this mode by creating bypass logic around the synchronous memory block.
- Read old data—Synchronous memory blocks 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 Intel memory . 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
module true_dual_port_ram_single_clock #(parameter DATA_WIDTH = 8, 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]; always @ (posedge clk) begin // Port a if (we_a) begin ram[addr_a] <= data_a; q_a <= data_a; end else q_a <= ram[addr_a]; end always @ (posedge clk) begin // Port b if (we_b) begin ram[addr_b] <= data_b; q_b <= data_b; end else 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 is undefined. 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
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 signal. signal ram : memory_t; begin process(clk) begin if(rising_edge(clk)) then -- Port A if(we_a = '1') then ram(addr_a) <= data_a; -- Read-during-write on same port returns NEW data q_a <= data_a; else -- Read-during-write on mixed port returns OLD data q_a <= ram(addr_a); end if; end if; end process; process(clk) begin if(rising_edge(clk)) then -- Port B if(we_b = '1') then ram(addr_b) <= data_b; -- Read-during-write on same port returns NEW data q_b <= data_b; else -- Read-during-write on mixed port returns OLD data q_b <= ram(addr_b); end if; end if; end process; end rtl;
PORT_A_READ_DURING_WRITE_MODE = "new_data_no_nbe_read" PORT_B_READ_DURING_WRITE_MODE = "new_data_no_nbe_read" MIXED_PORT_FEED_THROUGH_MODE = "old"