Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
16596 Discussions

Question about True Dual Port RAM

Altera_Forum
Honored Contributor II
2,005 Views

Hello, 

 

I'am using True dual port ram one port for write and the other one for read.  

 

When i change the content of an address i get the output on the read port delayed by two cycles. 

 

Is there a possibility to get the new value just one cycle after instead of two?
0 Kudos
6 Replies
Altera_Forum
Honored Contributor II
541 Views

Have you got registered output? You can remove this register to reduce latency at the cost of max clock speed

0 Kudos
Altera_Forum
Honored Contributor II
541 Views

can you please explain to me what does it mean to register an output or an input ? i searched the net but i can't find an example. I though that all the outputs when we do the assignment are called registered but i don't think this what it means isn't it ? 

And before i could understand what did you mean i changed in the code below to get what i want : library ieee; use ieee.std_logic_1164.all; entity merger is generic ( DATA_WIDTH : natural; ADDR_WIDTH : natural ); 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 merger; architecture rtl of merger 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; q_a <= data_a; else q_a<=data_b; end if; 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;  

Is it okay i wrote it like this ? i disable the we_a whenever i want to update the content of the address and read directly the new data ( data_b) (using flags from other modules )
0 Kudos
Altera_Forum
Honored Contributor II
541 Views

To register input or output, you add registers to the pipeline in those input. That means putting the signals in a clocked process. 

 

Your code (lifted I see from the quartus handbook) registers the input and output. As long as you register the read address then the Q output doesnt have to be registered.
0 Kudos
Altera_Forum
Honored Contributor II
541 Views

I tried too but i don't know why there's a cycle where i get a zero as output

0 Kudos
Altera_Forum
Honored Contributor II
541 Views

If you post your code and your testbench, and give more details about the problem, maybe we can help. But we can only guess at the moment.

0 Kudos
Altera_Forum
Honored Contributor II
541 Views

I'm sorry for my delayed reply.  

Here's my code library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.std_logic_signed.all; use ieee.math_real.all; library std; entity association is generic ( DEPTH : natural:=2; LABEL_WIDTH : natural := 8; ADDR_WIDTH : natural := 6 ); port ( clk ,reset , in_fv , in_dv : in std_logic; in_data : in std_logic_vector((LABEL_WIDTH -1) downto 0); addr : in natural range 0 to 2**ADDR_WIDTH - 1; q : out std_logic_vector((LABEL_WIDTH -1) downto 0) ); end association ; architecture rtl of association is component row_buffer is generic ( PIPLINE_LENGHT : integer; WORD_SIZE : integer ); port ( clk_proc : in std_logic; reset_n : in std_logic; enable_i : in std_logic; in_data : in std_logic_vector (WORD_SIZE-1 downto 0); out_data : out std_logic_vector (WORD_SIZE-1 downto 0) ); end component; component merger 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; data_a : in std_logic_vector((DATA_WIDTH-1) downto 0); we_a : in std_logic := '1'; q_a : out std_logic_vector((DATA_WIDTH -1) downto 0) ); end component; signal out1 , out2 : std_logic_vector((LABEL_WIDTH -1) downto 0); begin row_buffer_inst: row_buffer generic map (DEPTH,LABEL_WIDTH) port map (clk,reset,in_fv and in_dv, in_data,out1); merger_inst: merger generic map (LABEL_WIDTH,ADDR_WIDTH) port map (clk,addr,out1,in_fv and in_dv,out2); q<=out2; end rtl;  

the row buffer is a simple shift register : library ieee; use ieee.std_logic_1164.all; entity row_buffer is generic ( PIPLINE_LENGHT : integer; WORD_SIZE : integer ); port ( clk_proc : in std_logic; reset_n : in std_logic; enable_i : in std_logic; in_data : in std_logic_vector (WORD_SIZE-1 downto 0); out_data : out std_logic_vector (WORD_SIZE-1 downto 0) ); end row_buffer; architecture arch of row_buffer is type cell_t is array (0 to (PIPLINE_LENGHT-1)) of std_logic_vector ( (WORD_SIZE-1) downto 0); signal cell : cell_t; begin process(clk_proc,reset_n) variable i : integer := 0; begin if ( reset_n = '1' ) then cell <= (others =>(others => '0')); elsif (rising_edge(clk_proc)) then if (enable_i='1') then cell(0) <= in_data; for i in 1 to (PIPLINE_LENGHT-1) loop cell(i) <= cell(i-1); end loop; out_data<= cell(PIPLINE_LENGHT - 1); end if; end if; end process; end arch;  

and here's the merger (true dual port ram ) : library ieee; use ieee.std_logic_1164.all; entity merger 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 merger; architecture rtl of merger 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; 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; end if; end process; q_a <= ram(addr_a); q_b <= ram(addr_b); end rtl;  

 

This is my testbench :http://www.alteraforum.com/forum/attachment.php?attachmentid=13045&stc=1
0 Kudos
Reply