Warum leitet Xilinx ISE Block Ram für dieses Array nicht ab?

Ich habe eine Entität, die einen Array-Typ wie folgt hat:

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;

Ich möchte dieses Array in ein Block-RAM einfügen, um die verwendeten LUTs zu reduzieren, aber wenn ich diesen Code synthetisiere, kann XST kein Block-RAM ableiten und zeigt diese Warnung an:

INFO:Xst - HDL ADVISOR - Ein Block-RAM für Signal kann nicht extrahiert werden. Die Lese-/Schreibsynchronisierung scheint READ_FIRST zu sein und ist für die ausgewählte Familie nicht verfügbar. Stattdessen wird normalerweise ein verteiltes RAM erstellt. Um Block-RAM-Ressourcen zu nutzen, sollten Sie Ihre RAM-Synchronisierung erneut überprüfen oder verfügbare Gerätefamilien überprüfen.

Aber dieser Code ist im Write-First-Modus !. Ich habe einen anderen Speicher, der genau so ist, und XST hat einen Block-Ram dafür extrahiert.

Dieser RAM sollte schreibgeschützt sein (wie ein ROM), also habe ich Reset-, WR- und I-Signale auf '0' abgebildet. Ist es der Grund?

Ich verwende den XIlinx Spartan 2 XC2S50 FPGA-Chip, er unterstützt den Write-First-Modus für Block-Rams. Welche Änderungen sollte ich an meinem Unternehmen vornehmen, um Arbeit zu bekommen?

Bearbeiten :

Wenn ich diese Entität als Top-Modul einstelle, implementiert XST sie als Block-Ram. Ich denke, es gibt kein Problem in der Entität, das Problem ist, dass Reset, WR, und Iauf '0' abgebildet werden, jetzt ist die Frage, wie man ein Block-RAM als Block-ROM im Write-First-Modus verwendet?

Versuchen Sie es mit 0 bis 255 statt 1 bis 200.
Ihr Code sieht parallel zum Single-Port-Write-First-RAM- Beispiel von Xilinx auf Seite 132 aus, aber ich würde ein aktiv-hohes Signal (z. B. en) anstelle von versuchen Reset.
@BrianCarlton, danke, aber es gibt kein Problem im Array-Index, siehe Abschnitt Bearbeiten
@ahmedus danke, aber das ist nicht das Problem, siehe Abschnitt Bearbeiten

Antworten (4)

Vielleicht so etwas:

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;
  • Es gibt Hardware-Lese- und -Schreibports in Block-RAMs. Das Lesen findet gleichzeitig mit dem Schreiben statt.
  • Sie können die Lese- und Schreibteile oben austauschen, wenn sich ISE immer noch über "read first" beschwert, es gibt auch Attribute. Sie können "no_rw_check" versuchen, wenn Sie sich nicht für eine direkte Weitergabe von Daten zwischen Lese- und Schreibvorgängen interessieren.
  • Und wenn es sich um ein ROM handelt, können Sie den Schreibteil natürlich vollständig verwerfen.

Ich habe meine Entität in diese geändert:

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;

Jetzt implementiert XST es als Read-Only Block RAM. vielleicht nützlich für jemanden ...

Sie sollten niemals Resets für RAM verwenden. Denken Sie daran, dass dies in der Hardware hinterlegt ist. Wenn Sie also ein Reset-Signal verwenden, um die Ausgabe des Speichers zu steuern, ist dieses Verhalten nicht explizit für den BRAM-Block definiert. Wenn Sie etwas rund um den BRAM-Block zurücksetzen möchten, sollten es seine Ausgangsregister sein. Was also getan werden muss, ist, die getakteten gelesenen RAM-Daten zu nehmen und sie in einem zusätzlichen Register zu speichern, das synchron zurückgesetzt werden kann. Aktives High wird bevorzugt. Ich würde dringend vorschlagen, einen zusätzlichen Registrierungsprozess hinzuzufügen, der Folgendes umfasst:

O_reg <= O;

in einem getakteten Prozess mit Sync-Reset. Dies wird Ausgaberegs in Ihrem Speicher ableiten und bei der Platzierung helfen/das Timing verbessern.

Sie hätten auch eine BRAM-IP verwenden und das Array in eine Koeffizientendatei einfügen können, die in das BRAM eingefügt wird.