VHDL-Code-Kompilierung auf Quartus II

Sehen Sie sich dieses Stück Code an (Bild auf X umdrehen)

PROCESS(iCLK) 
BEGIN
  IF (rising_edge(iCLK)) THEN 
    -- Mise en mémoire du pixel
    ram(640*IdxC + PixX) <=  PIXIN; 
    -- Choix traitement
    IF (SWITCH='1') THEN
      PIXOUT <= ram(640*((IdxC + 1) mod 2) + PixX);
    ELSE
      PIXOUT <= ram(640*(2-IdxC) - PixX + 1);
    END IF; 
  END IF;   
END PROCESS;

Wenn ich es kompiliere, nimmt das Gesamtprojekt etwa 15 % der Logikelemente und 13 % der gesamten Speicherbits ein (QuartusII auf Zyklon III). Wenn ich den Code auf ändere

PROCESS (iCLK)
BEGIN
  IF(rising_edge(iCLK)) THEN 
    -- Mise en mémoire du pixel
    ram(640*IdxC + PixX) <=  PIXIN; 
    -- Choix traitement
    IF (SWITCH='1') THEN
      PIXOUT <= ram(640*((IdxC + 1) mod 2) + PixX);
    ELSE
      IF (PixX > 1 AND PixX < 640) THEN
        PIXOUT <= ram(640*(2-IdxC) - PixX + 1);
      ELSE
        PIXOUT <= x"111";
      END IF;
    END IF; 
  END IF;   
END PROCESS;

Ich bekomme

Error (276003): Cannot convert all sets of registers into RAM megafunctions when creating nodes. The resulting number of registers remaining in design exceeds the number of registers in the device or the number specified by the assignment max_number_of_registers_from_uninferred_rams. This can cause longer compilation time or result in insufficient memory to complete Analysis and Synthesis

Das scheint, dass ich das Design nicht mehr anpassen kann. Ich glaube das nicht. Gibt es einen Fehler im Compiler oder mache ich etwas falsch?

Ich habe die Quartus II Web Edition

Fügen Sie einfach einige --Kommentare wie folgt in die Zeilen ein und es wird erneut kompiliert:

PROCESS (iCLK)
BEGIN
  IF (rising_edge(iCLK)) THEN
    -- Mise en mémoire du pixel
    ram(640*IdxC + PixX) <= PIXIN;
    -- Choix traitement
    IF (SWITCH='1') THEN
      PIXOUT <= ram(640*((IdxC + 1) mod 2) + PixX);
    ELSE
   -- IF (PixX > 1 AND PixX < 640) THEN
        PIXOUT <= ram(640*(2-IdxC) - PixX + 1);
   -- ELSE
   --   PIXOUT <= x"111";
   -- END IF;
    END IF;
  END IF;
END PROCESS;

Dieser Code funktioniert mit dem Megafunktions-RAM 2-Port:

PROCESS (iCLK)
BEGIN
  IF rising_edge(iCLK) THEN     
    -- Ecrire linéairement dans la RAM le pixel de la cam
    RAMWRITE <= TO_UNSIGNED(640*IdxC + PixX - 1, 11);
    -- Choix traitement
    IF (SWITCH='1') THEN
      RAMREAD <= TO_UNSIGNED(640*((IdxC + 1) mod 2) + PixX - 1, 11);
      PIXOUT <= PIXMEM;
    ELSE
      RAMREAD <= TO_UNSIGNED(640*(2-IdxC) - PixX, 11);
      IF (PixX > 1 AND PixX < 640) THEN
        PIXOUT <= PIXMEM;
      ELSE
        PIXOUT <= x"FFF";
      END IF;
    END IF;     
  END IF;                       
END PROCESS;
Sind Sie absolut sicher, dass das das Einzige ist, was sich am gesamten Design geändert hat?
Absolut, nur etwas -- kommentieren Sie die Zeilen so und es wird erneut kompiliert: PROCESS(iCLK) BEGIN IF(rising_edge(iCLK)) THEN -- Mise en mémoire du pixel ram(640*IdxC + PixX) <= PIXIN; -- Choix traitement IF (SWITCH='1') THEN PIXOUT <= ram(640*((IdxC + 1) mod 2) + PixX); ELSE – IF (PixX > 1 AND PixX < 640) THEN PIXOUT <= ram(640*(2-IdxC) – PixX + 1); -- ELSE -- PIXOUT <= x"111"; -- ENDE WENN; ENDE WENN; ENDE WENN; PROZESS BEENDEN;
Sieht so aus, als ob Sie eher auf eine Einschränkung des Synthesetools als auf einen fehlerhaften VHDL-Code gestoßen sind. Es wurde entschieden, dass es den RAM nicht erkennen und aufgrund der zusätzlichen Klausel auf einen RAM-Block schließen kann. Um dies zu umgehen, versuchen Sie, eine Variable (oder ein Signal) zu erstellen, die eine reine RAM-Ausgabe ist (nicht unbedingt gültig), und eine separate Logik, um sie bei Bedarf zu löschen, anstatt beide Aufgaben in einer verschachtelten "IF" -Anweisung auszuführen. Sollte aber in einem einzigen Prozess funktionieren.
Ich habe Ihren Kommentar wieder in die Frage eingefügt, damit er lesbar ist. Aber ich bin verblüfft, warum diese einfache Änderung dazu führen sollte, dass das Design "explodiert". Vielleicht sollten Sie uns den Rest des Moduls zeigen, in dem dies vorkommt.
Sie werden vielleicht feststellen, dass es sogar else PIXOUT <= ram(some addr) or x"111";ausreichen wird ...
Ich habe meinen RAM-Puffer in einen Megafunktions-RAM2PORT-Typ geändert und den Prozess so geändert, dass er nur Variationen der Adressbeeinflussung enthält (keine RAM-zu-Signal-Beeinflussung mehr) und jetzt funktioniert es. Siehe meine Bearbeitung für Code

Antworten (1)

Ich würde nicht sagen, dass es ein Fehler ist, es ist eher eine Einschränkung, und in gewisser Weise macht es absolut Sinn. Sie wollen, dass es auf ein Dual-Port-Ram schlussfolgert, der Compiler will auf ein Dual-Port-RAM schliessen, aber der Prozess im Problem-Snippet beschreibt die Adresseingabe des Leseports des Rams nicht richtig, weil nicht alle Pfade abgedeckt sind, also es müsste ein Latch ableiten, während Sie wirklich wollen, dass es egal ist. Damit machst du es dem Compiler im Grunde schwer.

Beachten Sie, dass zum Ableiten des RAM auch einige Signale und deren Werte abgeleitet werden müssen, von denen eines der Adresseingang ist. Im synchronen Verfahren ist der Wert für dieses abgeleitete Signal für den Fall, der in PIXOUT <= x"111" endet, nicht definiert. Es müsste also ein Latch abgeleitet werden, und die Warnung wäre ein umständliches "Schluss-Latch auf abgeleitetes Adresssignal des abgeleiteten RAM". Am Ende ist es etwas zu viel, also gibt es wahrscheinlich auf, aber dann passt die alternative Lösung nicht zum Gerät. Ich sage nicht, dass dies der genaue Grund ist, warum es aufgibt, aber es sollte klar sein, dass der Compiler Schwierigkeiten haben würde, die Lücken für den abgeleiteten RAM zu füllen, wenn man bedenkt, wie dieser Prozess codiert wurde.

Alle Lösungen, die funktionieren, decken alle Fälle für das Adresssignal ab, gefolgert oder nicht. Sie könnten das Deklarieren des Signals testen und es dann auf die gleiche Weise codieren, sodass es auf einen Latch schließen muss, und es kann sogar kompiliert werden, da es jetzt zumindest ein explizit deklariertes Signal hätte, auf das es sich beziehen kann.

Die Codierungsstile zum Ableiten von RAM-Blöcken für Altera finden Sie unter http://www.altera.com/literature/hb/qts/qts_qii51007.pdf#page13

Dies ist einer der Gründe, warum dringend empfohlen wird, dass Sie, wenn Sie vorhandene Hardwareblöcke verwenden möchten, diese entweder als solche instanziieren, um Mehrdeutigkeiten zu vermeiden, oder den geeigneten Codierungsstilen folgen, damit sie einfach und angemessen abgeleitet werden können.

Beachten Sie auch, dass sich ein Simulator damit nicht befassen müsste, da er nicht per se auf einen RAM-Block schließen und sich mit dem mehrdeutigen Don't Care vs Latch dieses Phantomsignals befassen müsste, da es in der Simulation nicht existiert.