Tengo un FPGA Spartan3E 250K. Tengo un bloque de puerto de doble falta de coincidencia implementado. Según mis cálculos, hacer una memoria RAM de 8Kbytes debería ser posible. Sin embargo, ISE cambiará la RAM de mi bloque a una RAM distribuida (sobre mapeada) cuando intente sobrepasar 2Kbytes de RAM. Sin embargo, con 2Kbytes, dice que solo uso 1 de 12 RAM de bloque
¿Realmente necesito crear múltiples RAM de bloque y unirlas para obtener un componente de RAM de bloque de 8Kbytes completo?
El código es casi un rip directo de la biblioteca de plantillas de ISE:
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;