Diese Seite ist der dritte Beitrag einer Artikelserie, die den Multi-Gigabit-Transceiver (MGT) vorstellt.
Hinweis: Wenn Sie diese Seite lesen, weil Sie eine physikalische Verbindung für Xillyp2p einrichten, ist diese Seite für Sie nicht relevant: In diesem Fall sollten alle Kodierungsfunktionen deaktiviert sein, da der Xillyp2p-IP-Core (IP core) alles intern implementiert und dem Anwender die Anwendungsdaten als Ende-zu-Ende-Datenströme präsentiert.
Einführung
Der Datenstrom der Anwendungslogik wird fast nie unverändert auf dem physikalischen Kanal übertragen. Das würde höchstwahrscheinlich zu einer Fehlfunktion des MGTs führen, und zwar aus den zuvor genannten Gründen. In fast allen Anwendungen wendet der MGT oder die Anwendungslogik eine Kodierung auf den Datenstrom an, damit der physikalische Kanal ordnungsgemäß arbeiten kann. Diese Kodierung unterstützt außerdem die Synchronisation zwischen Sender und Empfänger.
Es gibt jedoch Ausnahmen: In diesem vollständigen Beispiel-Design wird der MGT als einfacher SERDES verwendet, ohne dass eine Kodierung aktiviert ist. Das ist möglich, weil die Anwendungslogik den Verwürfler (Scrambler) und die anderen erforderlichen Funktionen implementiert.
Diese Seite behandelt die Grundlagen der gebräuchlichsten Kodierungsverfahren. Die Liste der Protokolle auf der vorherigen Seite stellt die Verbindung zwischen diesen Kodierungen und den zwischen FPGAs verwendeten Protokollen her.
8b/10b-Kodierung
Die 8b/10b-Kodierung wird von mehreren Protokollen verwendet, beispielsweise von einigen Versionen von PCIe, Gigabit-Ethernet, SATA, DisplayPort und SuperSpeed-USB. Alle FPGA-MGTs besitzen einen eingebauten 8b/10b-Kodierer und einen ebensolchen Dekodierer, obwohl dieser Kodierer auch in der Logikstruktur des FPGAs implementiert werden könnte.
Diese Kodierung wandelt jedes Byte (8 Bit) in ein Wort aus 10 Bit um. Der Hauptzweck dieser Umsetzung ist es, eine Bitfolge zu erzeugen, die im Mittel gleich viele Nullen und Einsen enthält. Mit anderen Worten: Die Bits im kodierten Datenstrom sind gleichspannungsfrei (DC-balanced). Ein weiterer Vorteil ist, dass die Kodierung dafür sorgt, dass im Datenstrom ausreichend viele Übergänge zwischen „0“ und „1“ vorkommen, damit der CDR-Mechanismus (Clock Data Recovery) ordnungsgemäß arbeiten kann.
Beachten Sie jedoch, dass die 8b/10b-Kodierung den Datenstrom nicht randomisiert. Insbesondere reicht die 8b/10b-Kodierung allein nicht aus, wenn ein Entzerrer (Equalizer) verwendet wird und dieser Entzerrer verlangt, dass der Datenstrom statistisch zufällig ist.
Um das Ziel der Gleichspannungsfreiheit zu erreichen, können manche 8-Bit-Wörter in zwei mögliche Kandidaten kodiert werden. Beispielsweise kann das 8-Bit-Wort 0x20 (00100000, als D0.1 bezeichnet) entweder als 1001111001 oder als 0110001001 kodiert werden. Beide Alternativen werden zurück zu 0x20 dekodiert. Beachten Sie, dass die erste Alternative vier „0“-Bits und sechs „1“-Bits enthält. Die zweite Alternative enthält sechs „0“-Bits und vier „1“-Bits. Das ist die ganze Idee hinter der 8b/10b-Kodierung: Der Kodierer hat zwei Alternativen – eine mit mehr „0“ als „1“, und bei der zweiten genau umgekehrt.
Der Kodierer nutzt diese Eigenschaft, um langfristig das Gleichgewicht zwischen „0“ und „1“ sicherzustellen: Er merkt sich, ob in dem bisherigen Datenstrom zu viele „0“ oder zu viele „1“ aufgetreten sind. Dieses Ungleichgewicht wird als Running Disparity bezeichnet. Der Kodierer wählt das 10-Bit-Wort, das dazu beiträgt, dieses Ungleichgewicht zu verringern.
Nicht alle 8-Bit-Wörter haben zwei 10-Bit-Kandidaten. Beispielsweise wird das 8-Bit-Wort 0x23 (00100011, als D3.1 bezeichnet) immer zu 1100011001 kodiert. Dieses kodierte Wort enthält gleich viele „0“ und „1“, beeinflusst also die Running Disparity nicht.
Diese Kodierung wurde erstmals 1983 veröffentlicht und war in Protokollen, die bis etwa zum Jahr 2010 eingeführt wurden, sehr verbreitet. In neueren Protokollen ist sie weniger verbreitet. Der Hauptgrund ist, dass ein Verwürfler (Scrambler) oft ebenfalls Bestandteil des Protokolls ist. Die Gleichspannungsfreiheit des Datenstroms wird dann durch den Verwürfler sichergestellt, sodass die 8b/10b-Kodierung zu diesem Zweck nicht benötigt wird. Der Verwürfler sorgt auch dafür, dass Übergänge zwischen „0“ und „1“ häufig genug vorkommen. Andererseits fügt die 8b/10b-Kodierung 25 Prozent mehr Bits für die Übertragung auf dem physikalischen Kanal hinzu. Diese zusätzlichen Bits hätten für die Übertragung von Nutzdaten verwendet werden können.
Allerdings verwenden einige erfolgreiche Protokolle, die einen Verwürfler einsetzen, zusätzlich die 8b/10b-Kodierung. Beispielsweise verlangen alle PCIe-Versionen einen Verwürfler, aber in PCIe-Versionen vor 3.0 wird auch die 8b/10b-Kodierung verwendet. Die 8b/10b-Kodierung hat also offenbar noch andere Vorteile. Damit kommen wir zum nächsten Thema: den K-Symbolen.
K-Symbole
Die Tatsache, dass ein 8b/10b-Kodierer aus jedem 8-Bit-Wort, das er kodiert, 10 Bit erzeugt, bedeutet, dass das kodierte Wort 1024 mögliche Kombinationen hat, verglichen mit den 256 Möglichkeiten des ursprünglichen Worts. Selbst wenn man annähme, dass jedes ursprüngliche Wort zwei mögliche kodierte Wörter hätte, käme man auf 512 Möglichkeiten. Wie bereits erwähnt, haben manche 8-Bit-Wörter nur einen einzigen 10-Bit-Kandidaten für die Umsetzung, sodass es weniger als 512 Möglichkeiten für die 10-Bit-Wörter gibt. Daraus folgt, dass mindestens 512 der möglichen 10-Bit-Wörter keinem 8-Bit-Wort entsprechen.
Dadurch kann die 8b/10b-Kodierung Bitfehler auf der physikalischen Verbindung erkennen, indem sie unzulässige 10-Bit-Wörter erkennt. FPGA-MGTs besitzen Ausgangsports, mit denen die Anwendungslogik informiert wird, wenn ein unzulässiges 10-Bit-Wort erkannt wurde. Dieser Fehlererkennungsmechanismus ist allerdings nicht besonders wertvoll, da er nicht alle Fehler erkennt.
Der wirklich wertvolle Aspekt der 8b/10b-Kodierung sind die K-Symbole. Ein K-Symbol wird anstelle eines 8-Bit-Worts kodiert und übertragen. Der Dekodierer kann zwischen einem regulären Datenwort und einem K-Symbol unterscheiden, und es gibt immer eine Möglichkeit, die Anwendungslogik zu benachrichtigen, wenn ein K-Symbol eintrifft.
Somit ermöglicht die 8b/10b-Kodierung dem Sender, auf dem Datenkanal zusätzliche Informationen zu senden, die nicht mit regulären Daten verwechselt werden können. Diese Möglichkeit wird von Protokollen häufig genutzt, um dem Empfänger die Synchronisation mit dem Datenstrom des Senders zu erleichtern.
Die Bedeutung der K-Symbole hängt vom Protokoll ab. Es gibt jedoch ein K-Symbol, das in vielen Protokollen mit derselben Bedeutung verwendet wird: Das K28.5 wird oft als Comma (COM) bezeichnet und dient der Synchronisierung des Datenstroms. Mehr dazu weiter unten.
Wenn die 8b/10b-Kodierung an einem FPGA-MGT aktiviert ist, besitzt die Schnittstelle zur Anwendungslogik für jedes Datenbyte eine eigene Leitung. Diese Leitung zeigt an, ob es sich um ein reguläres Datenbyte oder um ein K-Symbol handelt. Mit anderen Worten: Die Schnittstelle zum Senden von Daten erlaubt es, für jedes gesendete Wort zu wählen, ob es ein reguläres Datum oder ein K-Symbol ist. Allerdings ist das 8-Bit-Datenwort, wenn es als K-Symbol markiert wird, auf genau diese Optionen beschränkt:
| Byte-Wert (hex) | K-Symbol |
|---|---|
| 1C | K28.0 |
| 3C | K28.1 |
| 5C | K28.2 |
| 7C | K28.3 |
| 9C | K28.4 |
| BC | K28.5 |
| DC | K28.6 |
| FC | K28.7 |
| F7 | K23.7 |
| FB | K27.7 |
| FD | K29.7 |
| FE | K30.7 |
Entsprechend gilt für den MGT-Empfänger: In der Schnittstelle zur Anwendungslogik gibt es für jedes empfangene Byte eine eigene Leitung. Der Wert jeder dieser Leitungen gibt an, ob das zugehörige Byte als normales Datenbyte oder als K-Symbol zu interpretieren ist. Der Empfänger besitzt außerdem eine spezielle Funktionalität, um K28.5 (Comma-Symbol, COM) in besonderer Weise zu behandeln. Dieses K-Symbol wird im Folgenden besprochen.
Das Comma-Symbol (K28.5)
Die 10-Bit-Darstellung von K28.5 ist 0011111010 oder 1100000101. Dieses Wort ist besonders nützlich, weil diese Bitfolge auf dem physikalischen Kanal nur als Ergebnis der Übertragung von K28.5 auftreten kann. Der Empfänger muss zum Erkennen eines K28.5 nicht mit dem Sender synchronisiert sein: Es genügt, dass die letzten 10 empfangenen Bits mit einem dieser beiden Wörter übereinstimmen.
Das macht K28.5 zu einem hervorragenden Werkzeug für die Synchronisierung des Empfängers. Sobald dieses K-Symbol erkannt wurde, sind die Grenzen der übrigen 10-Bit-Wörter bekannt.
FPGA-MGTs besitzen die Fähigkeit, den ankommenden Datenstrom automatisch auf das Eintreffen eines K28.5-Symbols auszurichten. Meist ist es auch möglich, die Ausrichtung an einer größeren Grenze vorzunehmen. Beispielsweise kann der MGT so konfiguriert werden, dass er ein ankommendes K28.5 am Anfang eines 32-Bit-Worts ausrichtet.
Abgesehen von der Ausrichtung des Empfängers kann das K28.5-Symbol auch dazu verwendet werden, andere funktionale Einheiten auszurichten, die eine Synchronisation benötigen. Beispielsweise kann das Protokoll verlangen, dass der Verwürfler (Scrambler) beim Eintreffen dieses K-Symbols zurückgesetzt wird.
Wegen dieser Möglichkeiten verlangen Protokolle oft, dass regelmäßig ein K28.5 gesendet wird, um den Empfänger zu synchronisieren. Protokolle, die eine Verbindung per Handshake aufbauen, verwenden K28.5 häufig als Teil des Verbindungsaufbaus. Wie auch immer: Das K28.5-Symbol vereinfacht das Design des Protokolls oft so weit, dass die zusätzlich übertragenen 25 Prozent Bits auf dem physikalischen Kanal dadurch gerechtfertigt sind.
Das Skip-Symbol (K28.0 und K28.1)
In den meisten praktischen Situationen gibt es einen Unterschied zwischen den Taktfrequenzen von Sender und Empfänger. Das kann ein Problem verursachen: Oft ist die Schnittstelle zwischen dem MGT und der Anwendungslogik synchron zum eigenen lokalen Takt des Empfängers. Die Daten kommen also gemäß dem Takt des Senders an, werden aber gemäß dem Takt des Empfängers an die Anwendungslogik übergeben.
Mit anderen Worten: Die Daten, die ein MGT empfängt, treffen in einem Tempo ein, das von der Gegenseite vorgegeben wird. Der lokale Takt gibt jedoch vor, wie schnell die Daten verbraucht werden.
Wenn die Taktfrequenz des Senders höher ist, holt sich die Anwendungslogik die Daten zu langsam vom MGT. Die überschüssigen Daten sammeln sich schließlich an, und irgendwo im MGT kommt es zu einem Überlauf (Overflow). Ist die Taktfrequenz des Senders dagegen niedriger, möchte die Anwendungslogik die Daten schneller holen, als sie ankommen. Auch das ist ein Problem.
Eine einfache Lösung für dieses Problem ist das Hinzufügen von Skip-Symbolen. Das SuperSpeed-USB-Protokoll definiert beispielsweise ein „SKP Ordered Set“ als zwei aufeinanderfolgende K28.1-Symbole. Das Protokoll verlangt, dass diese beiden K28.1-Symbole einmal pro 354 reguläre Datenwörter gesendet werden. Dem Empfänger-MGT ist es erlaubt, diese K28.1-Symbole zu verwerfen, anstatt sie der Anwendungslogik zu präsentieren. Das löst das Problem der überschüssigen Daten, wenn der Takt des Senders schneller ist als der Takt des Empfängers: Wenn das Empfänger-MGT aufgrund der Taktfrequenzunterschiede beginnt, Daten anzusammeln, überspringt es die ankommenden K28.1-Symbole.
Mit diesem Mechanismus kann der Sender in demselben Zeitraum 356 Wörter senden, in dem die Anwendungslogik des Empfängers nur 354 Wörter abholt. Mit der Rechnung 356 / 354 ≈ 1,00565 folgt, dass dieser Mechanismus einen Frequenzunterschied von bis zu etwa 0,565 Prozent zwischen den beiden Takten ausgleichen kann. Das ist natürlich mehr, als die Spezifikation des Protokolls zulässt.
Der Empfänger-MGT darf außerdem K28.1-Symbole zu einem vorhandenen „SKP Ordered Set“ hinzufügen. Das kann helfen, wenn der Takt des Senders langsamer ist. In diesem Fall versucht die Anwendungslogik auf der Empfängerseite, Daten schneller zu holen, als sie eintreffen. Der MGT darf die fehlenden Datenslots daher mit K28.1-Symbolen auffüllen: Von der Anwendungslogik wird ohnehin erwartet, dass sie alle K28.1-Symbole ignoriert.
Das PCIe-Protokoll verwendet das Skip-Symbol auf ähnliche Weise. Das Format des SKP Ordered Set bei PCIe ist jedoch anders: Es besteht aus vier K-Symbolen – zuerst einem K28.5 (Comma) und dann drei K28.0-Symbolen. Die Prinzipien der Verwendung des Skip-Symbols sind dennoch dieselben.
Sowohl das USB-Protokoll als auch das PCIe-Protokoll verwenden die Abkürzung SKP im Zusammenhang mit den Ordered Sets. Beachten Sie, dass damit im SuperSpeed-USB-Protokoll K28.1 gemeint ist, bei PCIe jedoch K28.0. Das lässt Raum für Verwechslungen.
64b/66b-Kodierung
Wie bereits erwähnt, nutzt die 8b/10b-Kodierung den physikalischen Kanal ineffizient. Die Hauptzwecke dieser Kodierung – Gleichspannungsfreiheit und das Sicherstellen von Übergängen zwischen „0“ und „1“ – sind nicht erforderlich, wenn ein Verwürfler (Scrambler) verwendet wird. Aus diesem Grund setzen neuere Protokolle auf die 64b/66b-Kodierung und ähnliche Verfahren. Es ist jedoch wichtig zu beachten, dass 64b/66b eigentlich keine Kodierungsmethode ist. Vielmehr handelt es sich um eine Methode, den Datenstrom und die Steuerwörter zu organisieren. Die Daten werden nicht in eine andere Darstellung umgewandelt. Es passiert lediglich, dass die Daten in Segmente aufgeteilt und zusätzliche Bits eingefügt werden, um die Synchronisation und das Senden von Steuerinformationen über den Kanal zu ermöglichen.
Beachten Sie, dass K-Symbole ausschließlich Bestandteil der 8b/10b-Kodierung sind und in keinem der anderen Kodierformate zur Verfügung stehen.
Die 64b/66b-Kodierung wird von mehreren Protokollen verwendet, beispielsweise von 10G/100G-Ethernet. Erwähnenswert ist, dass die fortgeschrittenen Versionen von PCIe und USB auf anderen Verfahren basieren, wie weiter unten erläutert wird.
Die 64b/66b-Kodierung teilt den Datenstrom in 64-Bit-Segmente und fügt am Anfang jedes solchen Segments zwei Bits hinzu. Jedes Segment ist also auf dem physikalischen Kanal 66 Bit lang. Diese zwei zusätzlichen Bits haben einen von zwei möglichen Werten: „01“ oder „10“. Wenn diese beiden Bits „01“ sind, enthält das nachfolgende 64-Bit-Wort acht Datenbytes. Sind diese Bits „10“, enthält das nächste Byte einen Code, der festlegt, was die restlichen 56 Bits enthalten: wie viele Datenwörter und wie viele Steuerwörter.
Die Steuerwörter dienen insbesondere dazu, den Anfang und das Ende von Frames (Paketen) anzuzeigen, aber auch dazu, Idle-Wörter einzufügen, um Unterschiede in der Taktfrequenz auszugleichen (ähnlich den Skip-Symbolen der 8b/10b-Kodierung). Es können auch Steuerwörter definiert werden, die für ein bestimmtes Protokoll spezifisch sind.
Wie bereits erwähnt, werden die restlichen 64 Bits – wenn die ersten beiden Bits „10“ sind – in zwei Teile aufgeteilt: ein 8-Bit-Codewort und 56 Bits, die aus einer Kombination von Daten- und Steuerwörtern bestehen. Die Organisation der Daten- und Steuerwörter innerhalb des 56-Bit-Segments ist recht kompliziert, vor allem weil jedes Steuerwort 7 Bit lang ist. Diese Besonderheit ist notwendig, um acht Steuerwörter in die verbleibenden 56 Bits einfügen zu können.
Darüber hinaus verwenden Protokolle, die diese Kodierung nutzen, auch einen Verwürfler (Scrambler) für die Daten, um die Gleichspannungsfreiheit und die Zufälligkeit der Daten sicherzustellen. Diese Zufälligkeit wird nicht nur wegen des Entzerrers (Equalizer) benötigt: Der Empfänger braucht sie auch, um den Anfang der 66-Bit-Segmente im ankommenden Datenstrom zu finden. Dazu werden die ersten beiden Bits jedes 66-Bit-Segments untersucht. Wenn dieses Bitpaar wiederholt nur die Werte „01“ oder „10“ annimmt, ist der Empfänger synchronisiert. Andernfalls muss er eine andere Position ausprobieren. Der Verwürfler sorgt dafür, dass die übrigen Bits zufällig sind. Wenn der Empfänger also falsch ausgerichtet ist, erscheint bald ein „00“ oder „11“ anstelle der zulässigen Kombinationen.
Alles in allem nutzt 64b/66b den zugrunde liegenden physikalischen Kanal besser, aber ein Protokoll, das diese Methode verwendet, ist schwieriger zu implementieren. Insbesondere die Notwendigkeit, jedes Segment unterschiedlich zu behandeln (abhängig von den ersten beiden Bits und möglicherweise auch von den acht darauf folgenden Bits), erhöht die Komplexität der Implementierung. Verschiedene FPGA-MGTs bieten hier unterschiedliche Grade der Unterstützung. Einige MGTs besitzen beispielsweise einen eingebauten Mechanismus, der den Empfänger automatisch auf die 66-Bit-Segmente des ankommenden Datenstroms ausrichtet. Die anspruchsvollere Aufgabe, 66-Bit-Segmente zu entpacken, die eine Kombination aus Daten- und Steuerwörtern enthalten, bleibt jedoch der Anwendungslogik überlassen.
Ein FPGA-MGT verfügt wahrscheinlich über eine eingebaute Gearbox, um aus dem Strom der 66-Bit-Segmente 64-Bit-Wörter zu extrahieren. Gearboxen werden auf der nächsten Seite dieser Serie ausführlicher besprochen.
64b/67b, 128b/130b und 128b/132b
Auch wenn 64b/66b den physikalischen Kanal besser ausnutzt, ist diese Methode kompliziert zu implementieren. Das ist wahrscheinlich der Grund, warum sowohl PCIe als auch SuperSpeed USB einen anderen Weg eingeschlagen haben, als sie sich von 8b/10b entfernten.
Beide Protokolle blieben bei der Idee, den Datenstrom in Segmente aufzuteilen. Anstelle von 64-Bit-Segmenten basieren diese Protokolle jedoch auf 128 Bits.
PCIe 3.0 und höher basiert auf 128b/130b. Ähnlich wie bei der 64b/66b-Kodierung beginnt jedes 128-Bit-Segment dieses Protokolls entweder mit „01“ oder „10“, um zwischen Daten- und Steuercodes zu unterscheiden. SuperSpeed USB Gen 2 basiert auf 128b/132b. Jedes seiner 128-Bit-Segmente beginnt zu demselben Zweck entweder mit „0011“ oder „1100“. Der einzige Unterschied besteht darin, dass das USB-Protokoll vier Bits statt zwei vorsieht, um einen besseren Schutz gegen Bitfehler zu bieten.
Ähnlich wie bei der 64b/66b-Kodierung wird auch auf dem 128-Bit-Teil jedes Segments ein Verwürfler (Scrambler) eingesetzt, um die Gleichspannungsfreiheit und die Randomisierung des Datenstroms sicherzustellen. Aber hier endet die Ähnlichkeit mit 64b/66b: Beide Protokolle definieren die Bedeutung des Inhalts des 128-Bit-Teils gemäß ihrer eigenen Protokollstruktur. 128b/130b und 128b/132b stehen also nur für die Aufteilung des Datenstroms in Segmente und dafür, wie viele Bits zu dem Teil hinzugefügt werden, der die Daten enthält. Der Rest ist für jedes Protokoll spezifisch.
Die 64b/67b-Kodierung funktioniert auf ähnliche Weise. Der Unterschied besteht darin, dass jedem Segment von 64 Bit zu denselben Zwecken drei Bits hinzugefügt werden. Diese Kodierung wird hauptsächlich vom Interlaken-Protokoll verwendet.
Keine Kodierung
Es ist möglich, eine Kommunikationsverbindung ohne eines der oben genannten Kodierungsverfahren zu implementieren. Ein Beispiel für ein solches Protokoll ist xillyp2p, das alle 223 Bits ein Synchronisationswort verwendet, um den Empfänger auf den Sender auszurichten und zu synchronisieren. Für dieses Protokoll ist der MGT nur ein SERDES. Der Hauptvorteil dieser Strategie besteht darin, dass das Protokoll überhaupt nicht von den anderen Funktionen des MGTs abhängt. Das vereinfacht die Implementierung des Protokolls auf einer breiten Palette von MGTs. Ein weiterer Vorteil ist, dass die Instanziierung (Instantiation) des MGTs viel einfacher ist, wie in diesem Beispiel-Design gezeigt wird.
Der Nachteil ist, dass FPGA-Logikressourcen für eine Aufgabe verwendet werden, die möglicherweise im MGT selbst hätte erledigt werden können.
Dieser Ansatz ist geeignet, wenn das Protokoll alle Anforderungen abdeckt, bei denen die Kodierung helfen kann: Gleichspannungsfreiheit, Randomisierung (falls erforderlich), Synchronisation und Wortausrichtung sowie die Unterscheidung zwischen Daten- und Steuerinformationen.
Zusammenfassung
Wie oben gezeigt, gibt es verschiedene Ansätze, den Datenstrom der Anwendungslogik zu kodieren, und es ist auch möglich, überhaupt keine Kodierung zu verwenden. Für die meisten Anwendungen ist die 8b/10b-Kodierung am einfachsten zu handhaben, aber diese Kodierung ist im Hinblick auf den Datenstrom auf dem physikalischen Kanal verschwenderisch. Deshalb haben neuere Protokolle andere Kodierungsverfahren übernommen, die effizienter, aber erheblich schwieriger anzuwenden sind.
Damit ist die dritte Seite in dieser Serie über MGTs abgeschlossen. Die nächste Seite stellt einige Teile des PCS vor, unter anderem die Teile, die die hier erwähnten Kodierungen implementieren.