Einführung
Auf dieser Seite geht es um source-synchrone Datenausgänge. Diese Technik bedeutet, dass die Datenausgänge synchron zu einem Takt sind, den das FPGA parallel zu diesen Ausgängen erzeugt.
Dieser Ansatz ist die naheliegende Wahl, wenn die Schnittstelle zu einer externen Komponente ausschließlich aus Ausgangs-Ports des FPGAs besteht. Er ist auch dann geeignet, wenn der betroffene I/O bidirektional ist, wie weiter unten auf dieser Seite erläutert wird. Außerdem gibt es eine separate Seite, auf der die Beziehungen zwischen Takt und Daten allgemein behandelt werden.
Die grundlegende Anwendung
Betrachten wir dieses Verilog-Beispiel:
module top (
input clk,
output reg [7:0] data_out,
output reg sync_clk_out
);
always @(posedge clk)
begin
sync_clk_out <= !sync_clk_out;
if (sync_clk_out)
data_out <= data_out + 1;
end
endmodule
Beachten Sie, dass @data_out seinen Wert gleichzeitig mit der fallenden Flanke von @sync_clk_out ändert: Wenn @sync_clk_out low ist, bleibt @data_out unverändert. Wenn @sync_clk_out high ist, nimmt @data_out als Reaktion auf die steigende Flanke von @clk einen neuen Wert an.
Wenn sowohl für @data_out als auch für @sync_clk_out IOB-Register verwendet werden, ändern alle diese Ausgangssignale praktisch gleichzeitig ihren Wert. Die externe Komponente, die diese Signale empfängt, kann @sync_clk_out daher als ihren Takt verwenden. Meist lassen sich die Timing-Anforderungen der externen Komponente auf diese Weise leicht erfüllen, vorausgesetzt, die Abtastung (sampling) von @data_out ist mit der steigenden Flanke von @sync_clk_out synchronisiert.
Verwendung von DDR-Registern
Das obige Beispiel hat einen erheblichen Nachteil: Die Frequenz von @sync_clk_out beträgt nur die Hälfte der Frequenz von @clk. Dadurch ist auch die Datenrate von @data_out auf die halbe Frequenz von @clk begrenzt. Die einzige Ausnahme besteht, wenn die externe Komponente auf beide Taktflanken von @sync_clk_out reagiert (also einen DDR-Eingang besitzt). Das ist allerdings meist nicht der Fall.
Möglich ist es, ein Ausgangs-DDR-Register zu verwenden, um einen Ausgangstakt zu erzeugen, der zu den Datenausgängen ausgerichtet ist. Die Idee besteht darin, ein Flip-Flop zu verwenden, das seinen Wert bei beiden Taktflanken ändert. Ein solches Flip-Flop verhält sich also folgendermaßen:
always @(posedge clk or negedge clk)
if (clk)
sync_clk_out <= 0;
else
sync_clk_out <= 1;
@sync_clk_out geht als Reaktion auf die steigende Flanke von @clk auf low. Bei einer fallenden Flanke passiert das Gegenteil. Das Ergebnis ist ein Ausgangstakt mit derselben Frequenz.
Dieser Verilog-Code wird bei den meisten Synthesewerkzeugen allerdings nicht funktionieren, denn die Flip-Flops im Logik-Fabric sind normalerweise nicht in der Lage, auf beide Taktflanken zu reagieren. Nur IOB-Register besitzen diese Fähigkeit, und das Synthesewerkzeug (englisch: synthesizer) ist selten klug genug, diese Möglichkeit zu erkennen.
Daher ist eine Instanziierung (englisch: instantiation) eines Logik-Primitivs (englisch: primitive) erforderlich. Das Primitiv ist FPGA-spezifisch. Dieses Beispiel zeigt, wie das bei Kintex Ultrascale umgesetzt werden kann:
ODDRE1 ODDR_ins
(.C(clk), .Q(sync_clk_out),
.D1(1'b0), .D2(1'b1),
.SR(1'b0));
Jetzt wird der Takt allerdings mit einem Ausgangs-DDR-Register erzeugt, während die Datensignale mit normalen IOB-Registern erzeugt werden. Die Ausrichtung zwischen Daten und Takt ist nicht mehr so offensichtlich wie zuvor. Daher ist es wichtig, die Timing-Berichte für alle Ausgänge zu lesen und zu prüfen, ob die Unterschiede zwischen den Verzögerungen klein genug sind.
Ebenso ist es möglich, auch für die Daten Ausgangs-DDR-Register zu verwenden: Wenn D1 und D2 derselbe Wert zugeführt wird, wechselt der Ausgang nur einmal pro Taktzyklus:
module top (
input clk,
output [7:0] data_out,
output sync_clk_out
);
reg [7:0] data;
ODDRE1 ODDR_ins
(.C(clk), .Q(sync_clk_out),
.D1(1'b0), .D2(1'b1),
.SR(1'b0));
ODDRE1 ODDR_data_ins [7:0]
(.C(clk), .Q(data_out),
.D1(data), .D2(data),
.SR(1'b0));
always @(posedge clk)
data <= data + 1;
endmodule
Diese Methode stellt sicher, dass Daten und Takt zueinander ausgerichtet sind. Die explizite Instanziierung der Ausgangs-DDR-Register stellt außerdem sicher, dass IOB-Register verwendet werden. Einziger Nachteil dieser Methode ist, dass sie FPGA-spezifisch ist.
Beachten Sie, dass das Verhalten von Ausgangs-DDR-Registern unerwartet und verwirrend sein kann. So ist @data beispielsweise mit der positiven Flanke von @clk synchronisiert. Das ODDRE1 ist jedoch auf beiden Taktflanken aktiv. Machen Sie sich daher in der Dokumentation Ihres FPGAs unbedingt damit vertraut, wie und wann die beiden Dateneingänge abgetastet werden.
Beachten Sie außerdem, dass die Reset-Leitung in diesem Beispiel nicht verwendet wird. Das kann insbesondere bei komplexen FPGAs riskant sein: Das Ausgangs-DDR-Register kann Teil eines komplexeren Logikelements innerhalb des IOB sein. Ein solches Logikelement arbeitet ohne Reset unter Umständen nicht korrekt.
Timing-Constraints
Sind also Timing-Constraints (englisch: timing constraints) bei dieser Methode notwendig? Wenn der Taktausgang und die Datenausgänge dank der Verwendung von IOB-Registern nahezu perfekt ausgerichtet sind, ist das nicht genug?
Die Antwort lautet: Diese Methode kann auch ohne Timing-Constraints einwandfrei funktionieren. Dennoch ist es eine gute Idee, Timing-Constraints zu nutzen. Die Gründe sind dieselben wie auf der Seite über IOB-Register zu diesem Thema.
Weitere Überlegungen
Die Verwendung von IOB-Registern ist allerdings nicht das Einzige, was sichergestellt werden muss: Auch die räumliche Nähe der Ausgangs-Ports zueinander spielt eine Rolle. Wenn die Ausgangs-Ports weit voneinander entfernt liegen, kann diese physische Distanz den Taktversatz (englisch: clock skew) im FPGA negativ beeinflussen. Auch Unterschiede bei den Leiterbahnlängen (also den Verbindungen auf der Leiterplatte) können sich negativ auswirken. Darüber hinaus sollten die elektrischen Parameter (Spannung, I/O-Standard, Slew Rate, Treiberstrom usw.) für alle Ausgänge gleich sein.
Wenn das FPGA keine IOB-Register besitzt, werden die Timing-Constraints entscheidend. Die Grundlage für source-synchrone Ausgänge ist die Fähigkeit, einen geringen Versatz (Skew) zwischen allen relevanten Ausgangs-Ports sicherzustellen. Meist reicht es aus, die Verzögerung zwischen dem Flip-Flop und dem I/O-Pin zu kontrollieren: Liegt diese Verzögerung nahe am Minimum, das beim jeweiligen FPGA möglich ist, sind die Unterschiede zwischen den Ausgängen für die meisten Zwecke klein genug.
Bidirektionaler I/O
Das Hauptmerkmal source-synchroner Ausgänge besteht darin, dass der zugehörige Takt vom FPGA erzeugt wird. Das ist offensichtlich dann zweckmäßig, wenn alle Datensignale zur externen Komponente hin gerichtet sind. Aber auch wenn Datensignale in beiden Richtungen übertragen werden, kann es sinnvoll sein, sich auf einen vom FPGA erzeugten Takt zu verlassen.
Beachten Sie jedoch: Die Dateneingänge sind mit dem Takt auf der Leiterplatte synchron, nicht mit dem Takt im Inneren des FPGA-Chips. Diese beiden Takte haben natürlich exakt dieselbe Frequenz. Es gibt aber eine zeitliche Differenz, die von der Clock-to-Output-Verzögerung der Ausgangs-Ports abhängt. Diese kann durchaus einige Nanosekunden betragen.
Daher ist es empfehlenswert, auf der Leiterplatte einen Loopback vorzusehen: Verbinden Sie den Taktausgang des FPGAs mit einem Eingangs-Port. Dieser Eingangs-Port kann dann wie ein systemsynchroner Takt (englisch: system synchronous clock) behandelt werden: Die externe Komponente verhält sich so, als käme ihr Takt von einem eigenen Oszillator und nicht vom FPGA. Dies ähnelt einem systemsynchronen Takt, weil sowohl das FPGA als auch die externe Komponente auf dasselbe physische Signal auf der Leiterplatte angewiesen sind.
Möglicherweise können die Dateneingänge auch als source-synchrone Eingänge (englisch: source-synchronous inputs) behandelt werden. Insbesondere bei Verwendung der Phasenverschiebungstechnik ist kein Takt-Loopback erforderlich. Das ist tatsächlich die übliche Methode zur Anbindung von DDR-SDRAM-Speichern.
Die wichtige Schlussfolgerung lautet: Planen Sie das Timing der Eingangssignale sorgfältig, bevor die Leiterplatte gefertigt wird, und erwägen Sie, bei Bedarf einen Takt-Loopback vorzusehen.

