VHDL: Sollen if-else- und case-Anweisungen dieselbe Hardware synthetisieren?

Die if-else- und case-Anweisungen sind äquivalent. Letzteres ist vielleicht einfacher zu lesen, wenn viele Möglichkeiten geprüft werden.

Eine Bedingung soll Mux in Hardware ableiten. Es gibt jedoch einen Unterschied zwischen einer Kette von 2-zu-1-Mux und einem großen n-zu-1-Mux, die dasselbe in Bezug auf die Ausbreitungsverzögerung tun.

Sollen die if-else-Anweisung und die case-Anweisung dieselbe Hardware ableiten ? Oder gibt es einen Unterschied, wie sie synthetisiert werden?

ja ... es gibt einen "Fehler" in der APA-Synthese, so dass ein großes if/elseif/... ein massives kaskadiertes UND-Netzwerk erzeugt, um dies zu erreichen, das LUT frisst und die Ausbreitungsverzögerung erhöht. Warum nicht eine Case-Anweisung verwenden, wenn Sie viele Möglichkeiten haben, dies zu überprüfen
Schauen Sie einfach unter der " RTL-Ansicht " nach, nachdem Sie synthetisiert haben. Es zeigt Ihnen, wie der Compiler es zusammengestellt hat.
Im Gegensatz zu dem, was Sie unten lesen könnten, kann ein Syntheseanbieter alles tun, was der Simulationssemantik der Sprache entspricht; ihre Ausgabe wird dann per Definition korrekt sein, Punkt. Als ich dieses Zeug unterrichtete, sagte ich den Schülern, dass sie in einem Fall einen Mux und in dem anderen einen Prioritätscodierer / eine Prioritätskette erwarten sollten.

Antworten (2)

Nein: if-else ist sequentiell; Fall ist gleichzeitig. Ein einzelnes if gefolgt von einem else entspricht einem Multiplexer mit zwei Eingängen. Eine If-Else-Anweisung gefolgt von einer If-Else-Anweisung entspricht einer Reihe von zwei Eingangsmultiplexern wie dieser: MuxDies liegt daran, dass die Reihenfolge, in der Sie die Bedingungen der If-Else-Anweisung prüfen, von Bedeutung ist, dh Sie haben Priorität.

Eine Fallangabe hingegen ist gleichzeitig. Alles geschieht gleichzeitig.

Ich möchte nur eine Anmerkung hinzufügen, dass Multiplexer selbst nicht wirklich eine Sache in einem FPGA sind, LUTs sind es, also ist ein schematisches Rendering von Multiplexern nicht besonders diagnostisch dafür, was tatsächlich in Bezug auf die Platznutzung auf dem FPGA-Fabric getan wird. Moderne FPGAs haben oft 6 Eingangs-LUTs, sodass die oben genannten aller Wahrscheinlichkeit nach tatsächlich auf zwei LUTs zusammenfallen werden.
@DanMills Ich stimme im Allgemeinen zu. Moderne FPGAs können jedoch nur 4 Eingänge zu ihren LUTs haben, z. B. MAX 10, Cyclone V. Außerdem ist es eine gute Praxis, Code zu schreiben, der skalierbar ist. Jeder Codestandard, den ich gesehen habe, erfordert, dass Sie Fälle verwenden, in denen keine Priorität erforderlich ist. In den meisten Fällen besteht einfach keine Notwendigkeit, if-else zu verwenden. Sie müssen auch berücksichtigen, was passiert, wenn Sie die Hardware ändern oder sich für eine ASIC-Implementierung entscheiden.
Case ist keine gleichzeitige Anweisung ... Die gleichzeitige Version von case ist eine with/select "Anweisung". Der eigentliche Name ist die gewählte Signalzuordnung. Es ist ein Sonderfall, dass if/elsif/else- und case-Anweisungen als Multiplexer abgeleitet werden. Dies gilt nur, wenn in den Zweigen oder in den Auswahlmöglichkeiten einer case-Anweisung dieselbe Ausgabe zugewiesen wird. Der Unterschied zwischen if und case besteht darin, dass if eine Prioritätslogik erzeugen kann, während Entscheidungen in einem case gleich gewichtet sind.

Keine der Aussagen wird notwendigerweise einem Multiplexer zugeordnet.

Der HDL-Code wird zu einer Zwischenform kompiliert, die sowohl durch Vereinfachung von Aussagen (z. B. Eliminierung von Tautologien) als auch durch Finden einer optimalen Abbildung auf tatsächliche Hardware, die auch Laufzeitverzögerungen berücksichtigt, optimiert wird.

Zum Beispiel

if(input)
then
    output <= '1';
end if;

wird wahrscheinlich output <= '1';vom Compiler optimiert, da der Anfangszustand undefiniert ist und ein fester Wert die geringsten Ressourcen verbraucht. Place&Route geht dann weiter und konfiguriert den Ausgabetreiber für den festen Wert, sodass nicht einmal ein einziges Register verwendet wird.

Ausbreitungsverzögerungen müssen in Ihrem Design berücksichtigt werden, wenn Schnittstellen erwarten, dass Daten an einer bestimmten Taktflanke ankommen, daher sollte dies bereits Teil der Schnittstellenspezifikation gewesen sein.

Wenn ich beispielsweise einen FIR-Filter baue, erzeuge ich auch ein validSignal, das gesetzt wird, wenn nach einem Reset ein stabiler Zustand erreicht wird, und ein markerSignal, das einfach eine Verzögerung an Eingangsmarkern ist. Die offensichtliche Implementierung generiertvalid N T A P S nach Reset, und die Markerverzögerung ist N T A P S 2 , aber das ist in der Schnittstelle nicht garantiert. Wenn ich ein besseres Pipelining-Verhalten erzielen kann, indem ich mehr Registerstufen in der Mitte hinzufüge, kann ich dies tun, ohne verbundene Komponenten zu beschädigen, und die Logik wird fast immer einfach optimiert, wenn der Compiler feststellt, dass die Gesamtverzögerung zur Kompilierzeit festgelegt ist.

In Ihrem Beispiel führt keine weitere Zuweisung zu outputzu einem Latch ... Unvollständige Zuweisungsbeschreibungen führen zu Speicherelementen.
@Paebbels Nur wahr in einem kombinatorischen Kontext. Es ist nur ein Code-Snippet, es ist sinnlos, es pingelig zu machen.
@Paebbels, ja, wenn Sie den Optimierer nicht über das Design laufen lassen. Der Optimierer sieht, dass es einen Latch mit einem Zustand gibt, der entweder '1'oder ist 'U', vereinfacht das zu '1', gibt den festen Wert an den Ausgangspuffer weiter und eliminiert den Latch, die Tabelle davor und die Verbindung zum Ausgangspuffer.
Das ist nicht richtig. Anfangs hat Udie Synthese keinen Wert. Nur 0, 1, Zund -. Nehmen wir zweitens an, dass Ihr unvollständiger Code Teil eines kombinatorischen Prozesses ist, dann wird die Ausgabe an einen Latch abgeleitet. Nehmen wir weiter an, dass der Ausgang entweder nicht initialisiert ( U) oder auf initialisiert wurde 0, dann ändert Ihr Latch nur einen Zustand, wenn der Eingang hoch geht. Der einzige Fall, in dem die Synthese die Ausgabe auf eine Konstante optimieren kann, ist, wenn die Ausgabe auf initialisiert wurde 1. Das ist sehr unwahrscheinlich.... .
Selbst wenn Sie Ihren Code in einen getakteten Prozess einfügen, wird die Synthese auf dasselbe Verhalten schließen, aber ein Flip-Flop anstelle eines Latch verwenden! Wenn Sie mir nicht glauben, dann schreiben Sie einen Beispielcode für ein beliebiges Synthesetool und senden Sie ihn an meine E-Mail-Adresse. Ich werde dieses Verhalten als Fehler für Sie einreichen :).
@jalalipop Das passiert in getakteten Prozessen. Der Unterschied besteht darin, dass Sie ein Flip-Flop erhalten, aber niemals einen Multiplexer.
@Paebbels, ich stimme zu, dass ein Latch generiert würde, aber der Optimierer wird ihn wieder entfernen, da der einzige definierte Wert, den die Ausgabe annehmen kann, ist '1'. Mein Punkt ist, dass der Optimierer größere Änderungen vornehmen wird, als der Unterschied zwischen ifund casejemals sein könnte.
Nein, es kann auf FPGAs nicht entfernt/optimiert werden (wir diskutieren eine FPGA-Frage basierend auf der Kennzeichnung dieser Frage). Dies ist ein Latch mit Anfangswert 0, der ein hohes aktives Ereignis benötigt input. Wenn das Ereignis nie bereitgestellt wird, outputkann es für immer niedrig bleiben. Normalerweise werden solche Latches (oder wahrscheinlicher Flip-Flops) verwendet, um Startbedingungen aufzuzeichnen.
@Paebbels, Signale haben keine Standardwerte in der Synthese. Deshalb benötigen Sie ein explizites Reset-Signal.
Nein das stimmt wieder nicht. Bitte lesen Sie IEEE Std. 1076.6-2004 (allgemein bekannt als VHDL-Synthesestandard). Es beschreibt, wie Standardwerte von Signalen in Anfangswerte von Registern oder Latches übersetzt werden. Der Standard wurde von IEEE zurückgezogen, aber Altera/Intel, Synopsys und Xilinx halten an diesem Teil des Standards fest. Vollständige Offenlegung: Ich bin einer der stellvertretenden Vorsitzenden der P1076 VSAG :).
@Paebbels Stimmt, ich denke, Ihr Hauptpunkt war, dass die Art und Weise, wie der Code geschrieben wird, nicht optimiert werden würde, wie Simon sagte, was für mich Sinn macht.
@Paebbels, getestet auf Quartus Prime 16.1, Kompilieren für EP4CE22E22C8 mit diesem Testcode: Der RTL-Viewer zeigt 'output', dass er fest mit 1h. Dies gilt auch dann, wenn ich dies mit einem lokalen Signal erweitere'0' , das auf initialisiert ist .
@Paebbels, ich habe es geschafft, einen Latch zu erstellen, indem ich den Prozess empfindlich gemacht habe input– in diesem Fall ifist der immer noch optimiert und der D-Eingang des Flip-Flops ist mit verbunden 1, aber jetzt ist der Eingang mit dem Takteingang des FF verbunden.
Ich kann Ihre Ergebnisse in Quartus Prime 17.0 nicht reproduzieren. RTL Viewer und Technology Map Viewer zeigen das von mir beschriebene Verhalten. Getestet habe ich Flipflops und Latches sowie no init value, init to 0und init to 1. Wenn outputinitialisiert wird, 1dann entfernt die Optimierung das Speicherelement wie erwartet. Ich bin mir sehr sicher, dass ich diese Funktion vor Jahren in Quartus II 13.0 verwendet habe.