I have a Spartan3E 250K FPGA. I have a dual-mismatched-port block RAM implemented. According to my calculations, making a 8Kbyte RAM should be possible. However, ISE will change my block RAM to a (overmapped) distributed RAM when I try to go over 2Kbytes of RAM. With 2Kbytes though, it says I'm only using 1 of 12 block RAMs
Do I really need to create multiple block RAMs and string them together to get a full 8Kbyte block RAM component?
The code is nearly a straight rip from ISE's template library:
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use ieee.std_logic_arith.all; use IEEE.NUMERIC_STD.ALL; use ieee.std_logic_unsigned.all; entity blockram is generic ( --Port A is for general use. Port B is for fetching WIDTHA : integer := 16; SIZEA : integer := 2048; ADDRWIDTHA : integer := 11; WIDTHB : integer := 32; SIZEB : integer := 1024; ADDRWIDTHB : integer := 10 ); port( Clock : in std_logic; EnableA : in std_logic; EnableB : in std_logic; WriteEnableA : in std_logic; WriteEnableB : in std_logic; AddressA : in std_logic_vector(ADDRWIDTHA-1 downto 0); AddressB : in std_logic_vector(ADDRWIDTHB-1 downto 0); DataInA : in std_logic_vector(WIDTHA-1 downto 0); DataInB : in std_logic_vector(WIDTHB-1 downto 0); DataOutA : out std_logic_vector(WIDTHA-1 downto 0); DataOutB : out std_logic_vector(WIDTHB-1 downto 0) ); end blockram; architecture Behavioral of blockram is function max(L, R: INTEGER) return INTEGER is begin if L > R then return L; else return R; end if; end; function min(L, R: INTEGER) return INTEGER is begin if L < R then return L; else return R; end if; end; function log2 (val: INTEGER) return natural is variable res : natural; begin for i in 0 to 31 loop if (val <= (2**i)) then res := i; exit; end if; end loop; return res; end function log2; constant minWIDTH : integer := min(WIDTHA,WIDTHB); constant maxWIDTH : integer := max(WIDTHA,WIDTHB); constant maxSIZE : integer := max(SIZEA,SIZEB); constant RATIO : integer := maxWIDTH / minWIDTH; -- An asymmetric RAM is modelled in a similar way as a symmetric RAM, with an -- array of array object. Its aspect ratio corresponds to the port with the -- lower data width (larger depth) type ramType is array (0 to maxSIZE-1) of std_logic_vector(minWIDTH-1 downto 0); -- You need to declare <ram> as a shared variable when : -- - the RAM has two write ports, -- - the RAM has only one write port whose data width is maxWIDTH -- In all other cases, <ram> can be a signal. --shared variable ram : ramType := (others => (others => '0')); signal ram: ramType; signal readA : std_logic_vector(WIDTHA-1 downto 0):= (others => '0'); signal readB : std_logic_vector(WIDTHB-1 downto 0):= (others => '0'); signal regA : std_logic_vector(WIDTHA-1 downto 0):= (others => '0'); signal regB : std_logic_vector(WIDTHB-1 downto 0):= (others => '0'); begin process (Clock) begin if rising_edge(Clock) then if EnableA = '1' then readA <= ram(conv_integer(AddressA)); if WriteEnableA = '1' then ram(conv_integer(AddressA)) <= DataInA; end if; end if; regA <= readA; end if; end process; process (Clock) begin if rising_edge(Clock) then if EnableB = '1' then for i in 0 to RATIO-1 loop -- The read statement below is placed before the write statement on purpose -- to ensure read-first synchronization through the variable mechanism readB((i+1)*minWIDTH-1 downto i*minWIDTH) <= ram(conv_integer(AddressB & conv_std_logic_vector(i,log2(RATIO)))); end loop; end if; regB <= readB; end if; end process; DataOutA <= regA; DataOutB <= regB; end behavioral;