¿Por qué Xilinx ISE no infiere Block Ram para esta matriz?

1

Tengo una entidad que tiene un tipo de matriz como se muestra a continuación:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;

Entity LCD_Memory is
  port (CLK, Reset, WR : IN std_logic;
        I : IN std_logic_vector(7 Downto 0); 
        Addr : IN std_logic_vector(7 Downto 0);

        O : OUT std_logic_vector(7 Downto 0));
End LCD_Memory;

Architecture Behavier of LCD_Memory is
 Type LCD_Memory_Array is Array(1 to 200) of std_logic_vector(7 Downto 0);
 Signal LCDMem : LCD_Memory_Array :=

          ("01010000", "01010010", "01001111", "01000111", "01010010", "01000001", "01001101", "00100000", -- Line_PK - 1
           "10110000", "00100000", "01001011", "01000101", "01011001", "00100000", "00111010", "00100000", -- Line_PK - 9

           "01000101", "01001110", "01010100", "01000101", "01010010", "00100000", "01010010", "01010101", -- Line_GM - 17
           "01001110", "00100000", "01001101", "01001111", "01000100", "01000101", "00100000", "00111010", -- Line_GM - 25

           "01000101", "01001110", "01010100", "01000101", "01010010", "00100000", "01010010", "01010101", -- Line_GD - 33
              "01001110", "00100000", "01000100", "01000101", "01001100", "01000001", "01011001", "00111010", -- Line_GD - 41

           "01010010", "01010101", "01001110", "10110000", "01000100", "00100000", "00100000", "00100000", -- Line_RD - 49        

           "01010010", "01010101", "01001110", "10110000", "01001110", "00100000", "00100000", "00100000", -- Line_RN - 57

           "01000100", "01001111", "01001110", "01000101", "00100000", "00100000", "00100000", "00100000", -- Line_DN - 65

           "01001101", "01000101", "01001101", "01001111", "01010010", "01011001", "00100000", "00111010", -- Line_Mem - 73
           "01000001", "01000011", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", -- Line_AC - 81
           "01000100", "01010010", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", -- Line_DR - 89
           "01001001", "01010010", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", -- Line_IR - 97
           "01010100", "01010010", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", -- Line_TR - 105
           "01000001", "01010010", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", -- Line_AR - 113
           "01001001", "01001110", "01010000", "01010010", "00100000", "00111010", "00100000", "00100000", -- Line_INPR - 121
           "01001111", "01010101", "01010100", "01010010", "00100000", "00111010", "00100000", "00100000", -- Line_OUTR - 129

           "01001001", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", "00100000", -- Line_I - 137
           "01010011", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", "00100000", -- Line_S - 145
           "01000101", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", "00100000", -- Line_E - 153
           "01010010", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", "00100000", -- Line_R - 161
           "01001001", "01000101", "01001110", "00100000", "00111010", "00100000", "00100000", "00100000", -- Line_IEN - 169
           "01000110", "01000111", "01001001", "00100000", "00111010", "00100000", "00100000", "00100000", -- Line_FGI - 177
           "01000110", "01000111", "01001111", "00100000", "00111010", "00100000", "00100000", "00100000", -- Line_FGO - 185
           "00100000", "00100000", "00100000", "00100000", "00100000", "00100000", "00100000", "00100000"); -- Null_1 - 193
--            "00100000", "00100000", "00100000", "00100000", "00100000", "00100000", "00100000", "00100000"); -- Null_2 - 201

 attribute ram_style : string;
 attribute ram_style of LCDMem : signal is "block";
begin

 Process(CLK)
 begin
  if (CLK'Event and CLK = '1') then
   if Reset = '0' then
     if WR = '1' then
      LCDMem(conv_integer(Addr)) <= I;
      O <= I;
     else
      O <= LCDMem(conv_integer(Addr));
     end if;
    end if;
  end if;
 end Process;

end Behavier;

Quiero poner esta matriz en una RAM de bloque para reducir las LUT utilizadas, pero cuando sintetizo este código, XST no puede inferir una RAM de bloque y muestra esta advertencia:

  

INFO: Xst - HDL ADVISOR - No se puede extraer una RAM de bloque para la señal   . La sincronización de lectura / escritura parece ser READ_FIRST   y no está disponible para la familia seleccionada.   Por lo general, se creará una memoria RAM distribuida. Tomar ventaja   de los recursos de memoria RAM del bloque, es posible que desee revisar su RAM   sincronizar o verificar las familias de dispositivos disponibles.

¡Pero este código está en modo de escritura primero! Tengo otra memoria que es exactamente igual a esta y XST extrajo un Block Ram para ello.

Esta RAM debe ser de solo lectura (como una ROM), por lo que he mapeado las señales de Restablecer, WR e I a '0'. ¿Es la razón?

Estoy usando XIlinx Spartan 2 XC2S50 Chip FPGA, es compatible con el modo Write-First para Block Rams. ¿Qué cambios debo hacer en mi entidad para obtener trabajo?

Editar :

Cuando configuro esta entidad como un módulo superior, XST la implementa como una RAM de bloque. Creo que no hay problema en la entidad, el problema es que Reset , WR y I están asignados a '0', ahora la pregunta es cómo usar una RAM de bloque como una ROM de bloque en Write- ¿Primer modo?

    
pregunta G3ntle_Man

4 respuestas

1

Cambié mi Entidad a esto:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;

Entity LCD_Memory is
  port (CLK : IN std_logic;
        Addr : IN std_logic_vector(7 Downto 0);

        O : OUT std_logic_vector(7 Downto 0));
End LCD_Memory;

Architecture Behavier of LCD_Memory is
 Type LCD_Memory_Array is Array(1 to 200) of std_logic_vector(7 Downto 0);
 Constant LCDMem : LCD_Memory_Array :=

          ("01010000", "01010010", "01001111", "01000111", "01010010", "01000001", "01001101", "00100000", -- Line_PK - 1
           "10110000", "00100000", "01001011", "01000101", "01011001", "00100000", "00111010", "00100000", -- Line_PK - 9

           "01000101", "01001110", "01010100", "01000101", "01010010", "00100000", "01010010", "01010101", -- Line_GM - 17
           "01001110", "00100000", "01001101", "01001111", "01000100", "01000101", "00100000", "00111010", -- Line_GM - 25

           "01000101", "01001110", "01010100", "01000101", "01010010", "00100000", "01010010", "01010101", -- Line_GD - 33
              "01001110", "00100000", "01000100", "01000101", "01001100", "01000001", "01011001", "00111010", -- Line_GD - 41

           "01010010", "01010101", "01001110", "10110000", "01000100", "00100000", "00100000", "00100000", -- Line_RD - 49        

           "01010010", "01010101", "01001110", "10110000", "01001110", "00100000", "00100000", "00100000", -- Line_RN - 57

           "01000100", "01001111", "01001110", "01000101", "00100000", "00100000", "00100000", "00100000", -- Line_DN - 65

           "01001101", "01000101", "01001101", "01001111", "01010010", "01011001", "00100000", "00111010", -- Line_Mem - 73
           "01000001", "01000011", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", -- Line_AC - 81
           "01000100", "01010010", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", -- Line_DR - 89
           "01001001", "01010010", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", -- Line_IR - 97
           "01010100", "01010010", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", -- Line_TR - 105
           "01000001", "01010010", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", -- Line_AR - 113
           "01001001", "01001110", "01010000", "01010010", "00100000", "00111010", "00100000", "00100000", -- Line_INPR - 121
           "01001111", "01010101", "01010100", "01010010", "00100000", "00111010", "00100000", "00100000", -- Line_OUTR - 129

           "01001001", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", "00100000", -- Line_I - 137
           "01010011", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", "00100000", -- Line_S - 145
           "01000101", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", "00100000", -- Line_E - 153
           "01010010", "00100000", "00111010", "00100000", "00100000", "00100000", "00100000", "00100000", -- Line_R - 161
           "01001001", "01000101", "01001110", "00100000", "00111010", "00100000", "00100000", "00100000", -- Line_IEN - 169
           "01000110", "01000111", "01001001", "00100000", "00111010", "00100000", "00100000", "00100000", -- Line_FGI - 177
           "01000110", "01000111", "01001111", "00100000", "00111010", "00100000", "00100000", "00100000", -- Line_FGO - 185
           "00100000", "00100000", "00100000", "00100000", "00100000", "00100000", "00100000", "00100000"); -- Null_1 - 193
--            "00100000", "00100000", "00100000", "00100000", "00100000", "00100000", "00100000", "00100000"); -- Null_2 - 201

-- attribute rom_style : string;
-- attribute rom_style of LCDMem : signal is "block";
begin

 Process(CLK)
 begin
  if (CLK'Event and CLK = '1') then
    O <= LCDMem(conv_integer(Addr));
  end if;
 end Process;

end Behavier;

Ahora, XST lo implementa como una RAM de bloque de solo lectura. tal vez útil para alguien ...

    
respondido por el G3ntle_Man
3

Tal vez algo así:

Process(CLK)
 begin
  if (CLK'Event and CLK = '1') then

     O <= LCDMem(conv_integer(Addr));

     if WR = '1' then
      LCDMem(conv_integer(Addr)) <= I;
     end if;

    end if;
  end if;
 end Process;
  • Hay puertos de lectura y escritura de hardware en las RAM de bloque. La lectura se produce al mismo tiempo que las escrituras.
  • Puede intercambiar las partes leídas y escritas arriba si el ISE aún se queja de "leer primero", también hay atributos. Puede probar "no_rw_check" si no le importa la propagación directa de datos entre lecturas y escrituras.
  • Y, por supuesto, si es una ROM, puedes descartar por completo la parte de escritura.
respondido por el TEMLIB
0

Nunca debes usar restablecimientos para RAM. Recuerde que esto se incluye en el hardware, por lo que cuando utiliza una señal de reinicio para controlar la salida de la memoria, ese comportamiento no se define explícitamente para el bloque BRAM. Si desea restablecer cualquier cosa que rodea el bloque BRAM, deben ser sus registros de salida. Entonces, lo que hay que hacer es tomar los datos de la memoria RAM de lectura sincronizada y almacenarlos en un registro adicional que se pueda restablecer de forma síncrona. Activo alto es el preferido. Recomiendo encarecidamente agregar un proceso de registro adicional tomando:

O_reg < = O;

en un proceso sincronizado con reinicio de sincronización. Esto inferirá los registros de salida en su memoria y ayudará a ubicar / mejorar el tiempo.

    
respondido por el Rami
0

También podrías haber usado una IP de BRAM y poner la matriz en un archivo de coeficiente que se encuentra dentro de la BRAM.

    
respondido por el samjay

Lea otras preguntas en las etiquetas