Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Valued Contributor III
1,465 Views

Question about True Dual Port RAM

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
Highlighted
Valued Contributor III
1 View

Re: Question about True Dual Port RAM

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

0 Kudos
Highlighted
Valued Contributor III
1 View

Re: Question about True Dual Port RAM

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
Highlighted
Valued Contributor III
1 View

Re: Question about True Dual Port RAM

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
Highlighted
Valued Contributor III
1 View

Re: Question about True Dual Port RAM

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

0 Kudos
Highlighted
Valued Contributor III
1 View

Re: Question about True Dual Port RAM

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
Highlighted
Valued Contributor III
1 View

Re: Question about True Dual Port RAM

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