Forum Discussion

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

How to instantiate a dual RAM with different widths on the R/W port

Hi,

the dual RAM:

Write port:128×16-bits

reading port: 2048×1-bit

I pefer HDL design input such VHDL or Verilog, please DO NOT tell me to instantiate this dual RAM by megawizard:)

Thanks a lot!

14 Replies

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

    Quartus II 8.0 fail to infer following code to RAM:

    library IEEE;

    use IEEE.STD_LOGIC_1164.ALL;

    use IEEE.STD_LOGIC_ARITH.ALL;

    use IEEE.STD_LOGIC_UNSIGNED.ALL;

    entity test_build is

    port (

    clka : in std_logic;

    clkb : in std_logic;

    addr_a : in std_logic_vector(6 downto 0);--in natural range 0 to 127;

    data_a : in std_logic_vector(63 downto 0);

    addr_b : in std_logic_vector(8 downto 0 );--in natural range 0 to 511;

    q_b : out std_logic_vector(15 downto 0)

    );

    end entity;

    architecture rtl of test_build is

    -- Build a 2-D array type for the RAM

    type word_t is array (2**9-1 downto 0) of std_logic_vector (15 downto 0);

    shared variable mem : word_t;

    signal addr_b_r : std_logic_vector(8 downto 0);--integer;

    begin

    process(clka)

    begin

    if rising_edge(clka) then

    --mem(conv_integer(addr_a)) := data_a;

    mem(conv_integer(addr_a) * 4+0) := data_a(15 downto 0);

    mem(conv_integer(addr_a) * 4+1) := data_a(31 downto 16);

    mem(conv_integer(addr_a) * 4+2) := data_a(47 downto 32);

    mem(conv_integer(addr_a) * 4+3) := data_a(63 downto 48);

    end if;

    end process;

    --rd_addr_t <= std_logic_vector(to_unsigned(addr_b, 9) );

    process(clkb)

    begin

    if rising_edge(clkb) then

    addr_b_r <= addr_b;

    q_b <= mem(conv_integer(addr_b_r));

    -- case (addr_b_r(1 downto 0)) is

    -- when "11" =>

    -- q_b <= q_t(63 downto 48);

    -- when "10" =>

    -- q_b <= q_t(47 downto 32);

    -- when "01" =>

    -- q_b <= q_t(31 downto 16);

    -- when "00" =>

    -- q_b <= q_t(15 downto 0);

    -- when others =>

    -- q_b <= x"0000";

    -- end case;

    end if;

    end process;

    --q_b <= mem(addr_b_r);

    --alt_ram : altsyncram

    --generic map (

    -- Width_a => 64,

    -- width_b => 16,

    --

    -- widthad_a => 7,

    -- widthad_b => 9

    --

    --)

    --port map (

    --

    -- clock0 => clka,

    -- clock1 => clkb,

    --

    -- data_a => data_a,

    -- address_a => std_logic_vector(to_unsigned(addr_a, 7) ),

    --

    -- address_b => std_logic_vector(to_unsigned(addr_b, 9) ),

    -- q_b => q_b

    --

    --);

    end architecture rtl;

    As Tricky posted, it's not a bad idea to add muxes on the output, like the quoted part using "case" above. U need to asure the width of R/W ports is same, as well as the address.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I don't see a purpose of using a shared variable for RAM inference, also I doubt if it's supported in this place by Quartus? It's never mentioned in the Quartus Handbook.

    In the above code, you are trying to write to four consecutive RAM addresses simultanously. This can't work in a single clock cycle.

    if rising_edge(clka) then 
    --mem(conv_integer(addr_a)) := data_a;
    mem(conv_integer(addr_a) * 4+0) := data_a(15 downto 0);
    mem(conv_integer(addr_a) * 4+1) := data_a(31 downto 16);
    mem(conv_integer(addr_a) * 4+2) := data_a(47 downto 32);
    mem(conv_integer(addr_a) * 4+3) := data_a(63 downto 48);
    end if;

    If you want to emulate different port width's with equal port width RAM, you must do it the other way around: Define the RAM width the larger width and use individual byteenable signals, when writing to the smaller port is intended
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Shared variables should not be synthesizable, but it appears they are in Quartus!.

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

    Quartus II 8.0 DO infer following code to dual port RAM:

    library IEEE;

    use IEEE.STD_LOGIC_1164.ALL;

    use IEEE.STD_LOGIC_ARITH.ALL;

    use IEEE.STD_LOGIC_UNSIGNED.ALL;

    --use ieee.numeric_std.all;

    entity test_build is

    generic

    (

    DATA_WIDTH : natural := 64;

    ADDR_WIDTH : natural := 7

    );

    port (

    clka : in std_logic;

    clkb : in std_logic;

    wren : in std_logic := '1';

    addr_a : in std_logic_vector(ADDR_WIDTH-1 downto 0);--in natural range 0 to 127;

    data_a : in std_logic_vector(DATA_WIDTH-1 downto 0);

    rden : in std_logic := '1';

    addr_b : in std_logic_vector(ADDR_WIDTH-1 downto 0 );--in natural range 0 to 511;

    q_b : out std_logic_vector(15 downto 0)

    );

    end entity;

    architecture rtl of test_build is

    --type mem_t is array(0 to 511) of std_logic_vector(15 downto 0);

    -- Build a 2-D array type for the RAM

    type word_t is array (2**ADDR_WIDTH-1 downto 0) of std_logic_vector (DATA_WIDTH-1 downto 0);

    shared variable mem : word_t;

    --attribute ramstyle : string;

    --attribute ramstyle of mem : variable is "no_rw_check";

    signal addr_b_r : std_logic_vector(ADDR_WIDTH-1 downto 0);--integer;

    signal q_t : std_logic_vector(DATA_WIDTH-1 downto 0);

    begin

    process(clka)

    begin

    if rising_edge(clka) then

    if(wren = '1') then

    mem(conv_integer(addr_a)) := data_a;

    -- mem(conv_integer(addr_a) * 4+0) := data_a(15 downto 0);

    -- mem(conv_integer(addr_a) * 4+1) := data_a(31 downto 16);

    -- mem(conv_integer(addr_a) * 4+2) := data_a(47 downto 32);

    -- mem(conv_integer(addr_a) * 4+3) := data_a(63 downto 48);

    end if;

    end if;

    end process;

    process(clkb)

    begin

    if rising_edge(clkb) then

    if(rden = '1') then

    addr_b_r <= addr_b;

    q_t <= mem(conv_integer(addr_b_r));

    --q_b <= q_t(to_unsigned(addr_b(1 downto 0)));

    --q_b <= mem(conv_integer(addr_b_r));

    end if;

    case (addr_b_r(1 downto 0)) is

    when "11" =>

    q_b <= q_t(63 downto 48);

    when "10" =>

    q_b <= q_t(47 downto 32);

    when "01" =>

    q_b <= q_t(31 downto 16);

    when "00" =>

    q_b <= q_t(15 downto 0);

    when others =>

    q_b <= x"0000";

    end case;

    end if;

    end process;

    --q_b <= mem(addr_b_r);

    --alt_ram : altsyncram

    --generic map (

    -- Width_a => 64,

    -- width_b => 16,

    --

    -- widthad_a => 7,

    -- widthad_b => 9

    --

    --)

    --port map (

    --

    -- clock0 => clka,

    -- clock1 => clkb,

    --

    -- data_a => data_a,

    -- address_a => std_logic_vector(to_unsigned(addr_a, 7) ),

    --

    -- address_b => std_logic_vector(to_unsigned(addr_b, 9) ),

    -- q_b => q_b

    --

    --);

    end architecture rtl;

    Well the data width of R/W port must be the same the R/W enable signals are necessary.Even using "Shared variables", it's easy synthesized by Quartus II 8.0!

    Unfortuntly, I can not use"ramstyle " attribution with "no_rw_check" when using "Shared variables", because "ramstyle " ONLY for "signal" NOT for "variables" as follow code frage:

    signal mem : word_t;

    attribute ramstyle : string;

    attribute ramstyle of mem : signal is "no_rw_check";