Die Verilog- always
Anweisung, nämlich
always @(/* condition */)
/* block of code */
führt das aus , block of code
wann condition
immer erfüllt ist. Wie wird ein solcher always
Block in Hardware implementiert?
Beachten Sie zunächst, dass nicht alle Verilog-Designs synthetisierbar sind. Üblicherweise kann nur eine ganz bestimmte Teilmenge von Konstrukten in einem Design verwendet werden, das in Hardware realisiert werden soll.
Eine wichtige Einschränkung, die auftaucht, ist, dass jede reg
Variable nur in höchstens einer always
Anweisung zugewiesen werden kann. Mit anderen Worten, reg
s haben eine Affinität zu always
Blöcken.
Die folgenden Arten von always
Blöcken können allgemein verwendet werden.
always @(*) begin
// combinational
end
always @(posedge clk) begin
// sequential
end
Im ersteren Fall *
zeigt an, dass der Block immer dann ausgeführt werden sollte, wenn sich irgendein in dem Block verwendetes Signal ändert, oder äquivalent, dass der Block kontinuierlich ausgeführt werden sollte. Daher werden reg
s, die Affinität zu kombinatorischen always
Blöcken haben, als Signale implementiert, die aus anderen Signalen unter Verwendung von kombinatorischer Logik, dh Gattern, berechnet werden.
Register, die eine Affinität zu always
Blöcken des letztgenannten Typs haben, sind andererseits Ausgänge von D-Flip-Flops, die auf der ansteigenden Flanke getaktet werden clk
(falls verwendet wird auf der abfallenden Flanke negedge
). Eingänge zu den Flip-Flops werden wiederum mit kombinatorischer Logik aus anderen Signalen berechnet.
Betrachten Sie das folgende, etwas erfundene Beispiel.
reg out, out_n;
always @(*) begin
out_n = !out;
end
always @(posedge clk) begin
out <= !out;
end
Dabei out_n
ist dem ersten always
Block out
der zweite zugeordnet. out_n
wird mit einem einzelnen NICHT-Gatter implementiert, das ansteuert out_n
und angesteuert wird out
(beachten Sie, dass es sich um eine reine kombinatorische Logik handelt). Andererseits out
wird von einem Flip-Flop getaktet von angesteuert clk
. Der Eingang zum Flip-Flop wird wieder von einem NICHT-Gatter aus berechnet out
(das von dem oben erwähnten Flip-Flop angesteuert wird). Optimierende Synthesizer kombinieren die beiden NICHT-Gatter und verwenden ein NICHT-Gatter und ein Flip-Flop.
Abhängig von der Ihnen zur Verfügung stehenden Hardware können auch andere Arten von Konstrukten verwendet werden. Wenn zum Beispiel die Flip-Flops asynchrone Rücksetzungen haben, ist das folgende Konstrukt auch synthetisierbar.
always @(posedge clk or posedge rst) begin
if (rst)
// reset
else
// sequential
end
*
, dachte ich, dass es darauf hindeutet, dass der Block ausgeführt werden sollte, wenn sich ein Signal im Block ändert (im Gegensatz zum Design ).Ein always
Block wird üblicherweise verwendet, um ein Flip-Flop, ein Latch oder einen Multiplexer zu beschreiben. Der Code würde mit einem Flip-Flop, einem Latch oder einem Multiplexer implementiert werden.
In einem FPGA sind ein Flip-Flop und ein Latch im Allgemeinen nur zwei verschiedene Konfigurationen eines allgemeineren Registergeräts. Ein Multiplexer würde aus einem oder mehreren Universallogikelementen (LUTs) aufgebaut werden.
Im Allgemeinen gibt es zwei Möglichkeiten, mit Verilog an das Design heranzugehen:
Visualisieren Sie die gewünschte Logik in Form von Gattern und Registern und finden Sie dann heraus, wie Sie sie in Verilog beschreiben können. Die Synthese-Leitfäden der FPGA-Anbieter oder Anbieter von Synthese-Tools enthalten Musterbeispiele für die gängigsten Strukturen, mit denen Sie möglicherweise arbeiten möchten.
Schreiben Sie einfach Verilog und machen Sie sich keine Gedanken darüber, wie die zugrunde liegende Hardware aussieht. Aber selbst wenn Sie dies tun, müssen Sie immer noch wissen, was synthetisierbar ist und was nicht. Sie werden sich also wieder die von Ihrem Tool-Anbieter bereitgestellte Boilerplate ansehen und diese an Ihre Anwendung anpassen.
BEARBEITEN
Avakars Antwort ist viel besser für Ihre Frage, aber dies hat einige interessante Diskussionen über die Unterschiede zwischen Xilinx und Altera ausgelöst, sodass ich sie nicht löschen werde.
Wie gesagt wurde, sind nicht alle Always-Blöcke synthetisierbar. Es gibt auch einige Blöcke, die die Synthesewerkzeuge akzeptieren, die aber Ergebnisse erzeugen, die sich von denen eines Simulators unterscheiden.
Zunächst einmal die Empfindlichkeitsliste. Die übliche Regel ist, dass es entweder nur Kantenerkennungskonstrukte enthalten muss (und es gibt normalerweise eine begrenzte Auswahl an möglichen Kombinationen) oder es muss (möglicherweise durch die Verwendung von * oder von systemverilogs always_comb) jedes Signal enthalten, das als Eingang für den Block verwendet wird. Wir nennen ersteren einen sequentiellen Block und letzteren einen kombinatorischen Block. Wenn Sie nur eine Teilmenge von Eingaben in eine kombinatorische Blocksynthese einbeziehen, werden Sie normalerweise von Werkzeugen ignoriert und so getan, als ob die vollständige Liste angegeben worden wäre (Erzeugung von Simulations-/Synthese-Nichtübereinstimmungen).
Zweite Blockierung vs. Noblocking-Zuweisungen. In einem kombinatorischen Block spielt der Unterschied keine große Rolle, aber in einem sequentiellen Block ist er sehr wichtig.
In einem sequentiellen Block modellieren nicht blockierende Zuweisungen ein Register ziemlich direkt, während Blockzuweisungen Variablen modellieren (die je nach Reihenfolge des Setzens und Lesens Register implizieren können oder nicht). In der Regel sollte ein "reg"-Satz, der blockierende Zuweisungen in einem sequentiellen Block verwendet, nur im selben Block gelesen werden, und blockierende und nicht blockierende Zuweisungen sollten nicht auf demselben "reg" gemischt werden.
Das Mischen von blockierenden und nicht blockierenden Zuweisungen für dasselbe Element führt wahrscheinlich zu Synthesefehlern. Das Vornehmen einer blockierenden Zuweisung in einem Block und das Lesen in einem anderen führt wahrscheinlich zu Simulations-/Synthese-Nichtübereinstimmungen (und möglicherweise sogar zu Nichtübereinstimmungen zwischen verschiedenen Simulationsläufen).
Jetzt haben wir die Grundregeln für die Überlegung, wie der Compiler Code in Logik umwandelt.
Der erste Schritt besteht darin, alle Schlaufen aufzurollen. Das bedeutet, dass Schleifen eine maximale Iterationszahl haben müssen, die zur Synthesezeit bestimmt werden kann, oder Sie erhalten einen Synthesefehler.
Dann kann das Tool den Kontrollfluss des Blocks analysieren und in einen Datenfluss umwandeln. Jede Variable wird zu einem oder mehreren Signalen. Jede if-Anweisung oder ein ähnliches Konstrukt wird zu einem oder mehreren Multiplexern, die auswählen, welche Ergebnismenge tatsächlich verwendet wird. Wenn eine Variable ihren Wert von einem Lauf eines kombinatorischen Always-Blocks zum nächsten behält, wird ein Register generiert, um den Wert zu behalten.
Das Tool wird dann wahrscheinlich versuchen, einige Optimierungen anzuwenden.
In quartus können Sie die Ergebnisse dieses Prozesses sehen, nachdem Sie Ihr Projekt erstellt haben, indem Sie zu "Tools->Netzlisten-Viewer->RTL-Viewer" gehen.
Nach der Generierung dieser strukturellen Darstellung in Form von abstrakten Logikelementen geht das Tool dann dazu über, diese abstrakten Elemente auf die Ressourcen abzubilden, über die der Chip tatsächlich verfügt.
m.Alin
block of code
ist..Justin
posedge x
oder geradex
Zufallsblau
posedge
.