Effizientes Ableiten von BRAM mit ungenutzten Adressen

Was ist ein korrekter Weg, um auf einen RAM mit einigen nicht verwendeten höheren Adressen (unter Verwendung von Block-RAMs) zu schließen?
Mit dem folgenden Code (Standardwerte für Generika, Xilinx-Synthesizer und Karte) erhalte ich einen RAM mit der gleichen Größe, als ob die Tiefe auf eingestellt wäre 2**ADDRWIDTH:

entity foo is
    generic (
        DATAWIDTH : positive := 8;
        DATADEPTH : positive := 5000;
        ADDRWIDTH : positive := 13
    );
    port (
        clk_a  : in std_logic;
        we_a   : in std_logic;
        addr_a : in std_logic_vector(ADDRWIDTH-1 downto 0);
        di_a   : in std_logic_vector(DATAWIDTH-1 downto 0);
        do_a   : out std_logic_vector(DATAWIDTH-1 downto 0)
    );
end foo;

architecture bar of foo is
    type myram_type is array (DATADEPTH-1 downto 0) of std_logic_vector(DATAWIDTH-1 downto 0); --! type for ram content
    shared variable myram : myram_type; --! ram
begin
    process (clk_a)
    begin
        if rising_edge(clk_a) then
            if we_a = '1' then
                myram(conv_integer(addr_a)) := di_a;
            end if;
            do_a <= myram(conv_integer(addr_a));
        end if;
    end process;
end bar;

Zum Beispiel möchte ich einen RAM mit DATAWIDTH = 8und DATADEPTH = 5000, also muss die Adresse sein ADDRWIDTH = 13, weil ADDRWIDTH = 12nur 4096 RAM-Speicherplätze adressiert werden können. Nehmen wir an, eine Block-RAM-Ressource auf meinem FPGA kann 8192 Bits aufnehmen. Wenn ich dies von Hand codierte, benötigte ich 5000 * 8/8192 aufgerundet = 5 Block-RAM-Ressourcen. Mit dem obigen Code führt die Synthese und Abbildung von Xilinx jedoch dazu, dass 8 Block-RAM-Ressourcen verwendet werden, da dies mit 13-Bit-Adressen adressiert werden kann ... Nichtsdestotrotz ist dies keine
wirklich effiziente Ressourcennutzung, da 3 von 8 Block-RAMs werden niemals verwendet.
Ich habe versucht zu prüfen, ob die Adresse am Eingang größer ist als DATADEPTHund dann don't cares für die Daten zuzuweisen, aber das führt dazu, dass der gesamte RAM als verteiltes RAM / LUTRAM implementiert wird.
Übersehe ich etwas Wichtiges oder muss ich dafür ein großes hässliches Generieren verwenden?

Antworten (3)

Tatsächlich ist die Verwendung von 8 BRAMs in einer 8K×1-Konfiguration anstelle von 5 BRAMs in einer 1K×8-Konfiguration in mehrfacher Hinsicht effizienter .

Mit den 8 BRAMs können Sie einfach alle Adress- und Steuerleitungen mit allen BRAMs und ein Bit von den Dateneingangs- und Datenausgangsbussen mit jedem der BRAMs verbinden. Es ist überhaupt keine andere Logik erforderlich.

Andererseits benötigen Sie bei der 5-BRAM-Konfiguration zusätzliche Logik, um die oberen 3 Adressbits zu decodieren, um jeweils ein BRAM zu aktivieren, und Sie benötigen außerdem einen 5:1-Multiplexer auf dem Datenausgabebus Wählen Sie beim Lesen die Daten aus dem richtigen BRAM aus. Dies verbraucht zusätzliche Ressourcen innerhalb des FPGA und wirkt sich auch nachteilig auf das Timing aus, wodurch die maximal verwendbare Taktfrequenz verringert wird.

Wenn Sie die BRAM- Kapazität wirklich so effizient wie möglich nutzen müssen und sich nicht um Timing- und Ressourcenprobleme kümmern, müssen Sie Ihren Speicher explizit als Modul codieren, das intern fünf 1K×8-Speicher verwendet.

Eine bessere 5-BRAM-Konfiguration wären in diesem Fall vier 4Kx2 und eine 1Kx8, mit einem 2:1-Ausgangs-Mux und einem einzelnen Adressbit-Decoder zum Schreiben.

Das Ableiten von harten Modulen (wie Block-RAMs) aus Code ist ein ziemlich fragiles Unterfangen, daher stellen Synthesizer normalerweise Codierungsrichtlinien bereit, von denen Sie vermutlich die „RAMs Hardware Description Language (HDL) Coding Guidelines“ von Xilinx verwendet haben.

Wenn Sie diese Richtlinien lesen und feststellen, dass bestimmte Codierungsstile, die vollkommen gültig erscheinen (wie die Verwendung von Signalen anstelle von gemeinsam genutzten Variablen für einen Dual-Port-RAM), nicht wirklich funktionieren, bekommen Sie ein Gefühl dafür, wie begrenzt Inferenztechniken sind.

Daher denke ich, dass es entweder bei Xilinx eine solche Einschränkung gibt, oder das Tool entscheidet sich dafür, die BRAM-Nutzung nicht zugunsten anderer Optimierungen zu minimieren (wie in Dave Tweeds Antwort erwähnt).

Es scheint also, dass Sie leider beschränkt sind auf:

  • Explizite Kaskadierung der erforderlichen BRAMs.
  • Kaskadieren mehrerer Erinnerungen, die auf die vereinfachte Art und Weise der „Richtlinie“ codiert sind.
  • Verwendung des CORE-Generators.
  • Lassen Sie die zusätzlichen BRAMs verschwenden und machen Sie weiter - vielleicht tut das Tool, wenn die Bedingungen stimmen, das, was Sie erwartet haben, und verwendet 5 BRAMs.

Wenn Sie 13 Adressbits für Ihr RAM verwenden müssen, müssen diese 13 physikalischen Adresssignale für ein BRAM Ihrem RAM zugewiesen werden. Die Adresszeilen können nicht einfach mit anderen Modulen geteilt werden, sodass Sie effektiv den gesamten physischen RAM erhalten, auf den über diese 13 Adresszeilen zugegriffen wird. Wenn Sie 5000 Wörter benötigen, erhalten Sie 8192 Wörter BRAM. Wie Sie bemerkt haben, können Sie, wenn Sie den RAM aus LUTs synthetisieren, einen RAM mit nur 5000 Wörtern erstellen, aber Sie verlieren die Effizienz des BRAM.