Forum Discussion
Altera_Forum
Honored Contributor
10 years agoAs you are doing the read in a clock process, I agree that your code shouldn't generate a memory with new read-during-write behaviour. But the code you posted here differs from the recommended altera hdl styles (https://documentation.altera.com/#/00030683-aa$nt00064438) and it's hard to predict how the synthesis tool will implement this. Sometimes it can do some really crazy stuff, and different stuff with different versions. I would recommend instead to make an entity that sticks as much as possible to the recommended style and put your own wrapper logic around it: (you can put both read/write accesses in the same process and avoid using a shared variable if you want though, it works with all the Quartus versions that I tried):
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.
shared variable 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 the same port returns NEW data
q_a <= data_a;
else
-- Read-during-write on the 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 the same port returns NEW data
q_b <= data_b;
else
-- Read-during-write on the mixed port returns OLD data
q_b <= ram(addr_b);
end if;
end if;
end process;
end rtl; I think the key is to have only two address signals, and have your own logic to connect them to I_selS1, I_selS2 or I_selD depending on the current operation. That way you ensure Quartus will recognize your code and implement it correctly. That said, I see that the recommended HDL in fact uses new read-during-write, and they say in the text that this is what most FPGA memories natively support. If you see it still generates extra logic around the memory block, you can try and move the read operation outside the if. But stick to two address signals to avoid confusing the synthesizer IMHO.