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

inferring rams with read enable port ?

Altera_Forum
Honored Contributor II
2,675 Views

Hi to everyone, I'm trying to infer a tdpram with rden port , because I need the rden port I insert it in the entity and I tried to use the rden signal . I used the VHDL template for tdpram with mixed port dimensions (asymmetric tdpram) . I tried to synth it with quartus 11.1_sp2 but it shows the error : Error (276001): Cannot synthesize dual-port RAM logic "ram" 

it seems that there is a asynchronous read that cause the error.... 

 

Also there another error the synth think that the rden port seems an another wren port ??? 

you specified logic that acts as RAM with at least two write ports, but Analysis & Synthesis can map the RAM write logic only to the same process block. 

 

Here a part of the VHDL code : 

 

ibrary ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.std_logic_arith.all; use std.textio.all; entity mixed_width_true_dual_port_ram is generic ( o_ff_a : boolean :=true; o_ff_b : boolean := true; DATA_WIDTH1 : natural := 8; ADDRESS_WIDTH1 : natural := 10; ADDRESS_WIDTH2 : natural := 8 ; is_Stratix_V : boolean := true); port ( we1 : in std_logic; we2 : in std_logic; rden_a : in std_logic; rden_b : in std_logic; clk_a : in std_logic; clk_b : in std_logic; addr1 : in std_logic_vector (ADDRESS_WIDTH1-1 downto 0); addr2 : in std_logic_vector (ADDRESS_WIDTH2-1 downto 0); data_in1 : in std_logic_vector(DATA_WIDTH1 - 1 downto 0); data_in2 : in std_logic_vector(DATA_WIDTH1 * (2 ** (ADDRESS_WIDTH1 - ADDRESS_WIDTH2)) - 1 downto 0); data_out1 : out std_logic_vector(DATA_WIDTH1 - 1 downto 0); data_out2 : out std_logic_vector(DATA_WIDTH1 * 2 ** (ADDRESS_WIDTH1 - ADDRESS_WIDTH2) - 1 downto 0)); end mixed_width_true_dual_port_ram; architecture rtl of mixed_width_true_dual_port_ram is constant RATIO : natural := 2 ** (ADDRESS_WIDTH1 - ADDRESS_WIDTH2) ; constant DATA_WIDTH2 : natural := DATA_WIDTH1 * RATIO; constant RAM_DEPTH : natural := 2 ** ADDRESS_WIDTH2; constant numwords_a : integer := (2**ADDRESS_WIDTH1); constant numwords_b : integer := (2**ADDRESS_WIDTH2); -- Use a multidimensional array to model mixed-width type word_t is array(RATIO - 1 downto 0) of std_logic_vector(DATA_WIDTH1 - 1 downto 0); type ram_t is array (0 to RAM_DEPTH - 1) of word_t; -- declare the RAM -- signal ram : ram_t; shared variable ram : ram_t; signal w1_local : word_t; signal q1_local : word_t; signal data_out1_int : std_logic_vector(DATA_WIDTH1 - 1 downto 0); signal data_out1_int_d1 : std_logic_vector(DATA_WIDTH1 - 1 downto 0); signal data_out2_int : std_logic_vector(DATA_WIDTH1 * 2 ** (ADDRESS_WIDTH1 - ADDRESS_WIDTH2) - 1 downto 0); signal data_out2_int_d1 : std_logic_vector(DATA_WIDTH1 * 2 ** (ADDRESS_WIDTH1 - ADDRESS_WIDTH2) - 1 downto 0); signal rden_a1 : std_logic; signal rden_b1 : std_logic; signal addr_1 : std_logic_vector (ADDRESS_WIDTH1-1 downto 0); signal addr_2 : std_logic_vector (ADDRESS_WIDTH2-1 downto 0); begin process (addr1, addr2) variable v_add_1 : std_logic_vector(ADDRESS_WIDTH1-1 downto 0); variable v_add_2 : std_logic_vector(ADDRESS_WIDTH2-1 downto 0); begin v_add_1 := addr1; v_add_2 := addr2; -- synthesis translate_off if conv_integer(addr1)>=numwords_a then v_add_2 := (others=>'0'); end if; if conv_integer(addr2)>=numwords_b then v_add_2 := (others=>'0'); end if; -- synthesis translate_on addr_1 <= v_add_1; addr_2 <= v_add_2; end process; -- rtl -- Re-organize the write data to match the RAM word type unpack: for i in 0 to RATIO - 1 generate w1_local(i) <= data_in2(DATA_WIDTH1*(i+1) - 1 downto DATA_WIDTH1*i); data_out2_int(DATA_WIDTH1*(i+1) - 1 downto DATA_WIDTH1*i) <= q1_local(i); end generate unpack; Stratix_IV : if is_Stratix_V=false generate begin --port A process(clk_a) begin if(rising_edge(clk_a)) then if (rden_b='1') then q1_local <= ram(conv_integer(addr2)); end if; if(we2 = '1') then ram(conv_integer(addr_2)) := w1_local; end if; -- q1_local <= ram(conv_integer(addr_2)); --example by Quartus end if; end process; -- port B process(clk_b) begin if(rising_edge(clk_b)) then if (rden_a='1') then data_out1_int <= ram(conv_integer(addr1) / RATIO )(conv_integer(addr1) mod RATIO); -- example by Quartus end if; if(we1 ='1') then ram(conv_integer(addr_1) / RATIO)(conv_integer(addr_1) mod RATIO) := data_in1; end if; -- data_out1_int <= ram(conv_integer(addr_1) / RATIO )(conv_integer(addr_1) mod RATIO); end if; end process; end generate ; Stratix_V : if is_Stratix_V=true generate begin --port A process(clk_a) begin if(rising_edge(clk_a)) then -- q1_local <= ram(conv_integer(addr2)); if(we2 = '1') then ram(conv_integer(addr_2)) := w1_local; end if; if (rden_a='1')then q1_local <= ram(conv_integer(addr_2)); --example by Quartus end if; end if; end process; -- port B process(clk_b) begin if(rising_edge(clk_b)) then -- data_out1_int <= ram(conv_integer(addr1) / RATIO )(conv_integer(addr1) mod RATIO); -- example by Quartus if(we1 ='1') then ram(conv_integer(addr_1) / RATIO)(conv_integer(addr_1) mod RATIO) := data_in1; end if; if (rden_b='1') then data_out1_int <= ram(conv_integer(addr_1) / RATIO )(conv_integer(addr_1) mod RATIO); end if; end if; end process; end generate ; process(clk_a,clk_b) begin if rising_edge(clk_a) then data_out1_int_d1<=data_out1_int; end if; if rising_edge(clk_b) then data_out2_int_d1<=data_out2_int; end if; end process; data_out1 <= data_out1_int_d1 when o_ff_a= true else data_out1_int ; data_out2 <= data_out2_int_d1 when o_ff_a= true else data_out2_int ; end rtl;  

 

Most of the code has been reused from the Quartus tdpram mixed template, the only differences are the introduction of 2 clocks and the rden_a and rden_b port, 

In the Quartus Handbook there are no examples of using rden port from inferring Rams so could not be inferred the rden port?
0 Kudos
4 Replies
Altera_Forum
Honored Contributor II
1,431 Views

 

--- Quote Start ---  

the only differences are the introduction of 2 clocks and the rden_a and rden_b port 

--- Quote End ---  

 

"The only difference" actually matters. Your code requests synthesis of a RAM output register, that holds the previous value if rd_en is inactive. But there's no equivalent register avaible in the hardware. Please notice that the clocked read action you are associating with rd_en is actually "absorbed" by the register level at the RAM input, so it's not available at the RAM output. 

 

I don't clearly see, what's the purpose of the rd_en action in your design. The RAM itself doesn't require it.
0 Kudos
Altera_Forum
Honored Contributor II
1,431 Views

My question is possible to infer the read enable port in a Vhdl model for Altsyncram without using Altera Megawizard? In some our projects we had some rams generated with megawizard with an effective rden signal (not cabled to '1' value), for portability coding we want to infer Rams directly in VHDL code . Could give us an example of infering a ram with rden enable synthetizable by Quartus II?

0 Kudos
Altera_Forum
Honored Contributor II
1,431 Views

You didn't yet answer about the intended function of the rd_en. Do you have a register holding previous values in your compatible projects? 

 

As I already mentioned, it's impossible to have an synchronous output register and no additional delay of one clock cycle with Altera RAM blocks. You can either implement a transparent latch or a register with delay.
0 Kudos
Altera_Forum
Honored Contributor II
1,431 Views

This sounds interesting to know.. "P

0 Kudos
Reply