1 votos

¿Por qué Xilinx ISE no infiere la ram en bloque para esta matriz?

Tengo una Entidad que tiene un tipo de array como el siguiente:

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 este array en una RAM de bloque para reducir las LUTs usadas, pero cuando sintetizo este código, XST es incapaz de inferir una RAM de bloque y muestra esta advertencia :

INFO:Xst - HDL ADVISOR - No se puede extraer un bloque de RAM 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 RAM distribuida en su lugar. Para aprovechar de los recursos de la RAM de bloque, es posible que desee volver a revisar la sincronización de la RAM o comprobar las familias de dispositivos disponibles.

Pero este código está en modo "write-first". Tengo otra memoria que es exactamente igual a esta y XST extrajo un Block Ram para ella.

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

Estoy usando un chip FPGA XIlinx Spartan 2 XC2S50, que soporta el modo Write-First para Block Rams.

Editar :

Cuando establezco esta entidad como un módulo superior, XST lo implementa como un bloque Ram. Creo que no hay ningún problema en la entidad, el problema es que Reset , WR y I se asignan a '0', ahora la pregunta es ¿cómo utilizar una RAM de bloque como una ROM de bloque en el modo Write-First?

3voto

TEMLIB Puntos 1200

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 por hardware en las RAM de bloque. La lectura se produce al mismo tiempo que la escritura.
  • Puedes intercambiar las partes de lectura y escritura de arriba si ISE todavía se queja de "leer primero", también hay atributos, Puedes probar "no_rw_check" si no te importa tener propagación directa de datos entre lecturas y escrituras.
  • Y por supuesto, si se trata de una ROM, se puede descartar por completo la parte de escritura.

1voto

lpreams Puntos 11

He cambiado mi Entidad por esta :

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 sólo lectura. tal vez útil para alguien ...

0voto

Jackie Moon Puntos 46

También podrías haber utilizado una IP BRAM y poner la matriz en un archivo de coeficientes que va dentro de la BRAM.

0voto

CoryG Puntos 1

Nunca debes usar resets para la RAM. Recuerda que esto está puesto en el hardware, así que cuando estás usando una señal de reset para controlar la salida de la memoria entonces ese comportamiento no está explícitamente definido para el bloque BRAM. Si quieres resetear algo de lo que rodea al bloque BRAM deben ser sus registros de salida. Así que lo que hay que hacer es tomar los datos de lectura de la RAM con reloj y almacenarlos en un registro adicional que pueda ser reseteado de forma sincronizada. Es preferible que sea activo alto. Yo sugeriría añadir un proceso de registro adicional tomando:

O_reg <= O;

en un proceso con reloj y reinicio de sincronización. Esto inferirá los regs de salida en su memoria y ayudará en la colocación/mejora de la sincronización.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X