Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
14 years ago

inferring rams with read enable port ?

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?

4 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- 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.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    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?

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    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.