¿Tengo que dividir mis memorias RAM de bloque para obtener la utilización completa del dispositivo?

1

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;
    
pregunta Earlz

1 respuesta

1

Inferir el puerto dual con diferentes anchos de datos es un poco molesto, me di por vencido (usar el código de la plantilla no era un iniciador, ya que claramente nunca se había probado con genéricos distintos a los valores predeterminados)

Sostén tu nariz y usa Coregen :(

    
respondido por el Martin Thompson

Lea otras preguntas en las etiquetas