Forum Discussion
14 Replies
- Altera_Forum
Honored 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
Honored 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 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 intendedif 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; - Altera_Forum
Honored Contributor
Shared variables should not be synthesizable, but it appears they are in Quartus!.
- Altera_Forum
Honored 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";