Altera_Forum
Honored Contributor
14 years agoinferring 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?