Cette page est la troisième d’une série de pages présentant le transcepteur multi-gigabits (MGT).
Remarque : si vous lisez cette page dans le cadre de la mise en place d’une liaison physique pour Xillyp2p, elle ne vous concerne pas : dans ce cas, toutes les fonctions de codage doivent être désactivées, car le cœur IP (IP core) Xillyp2p implémente tout en interne et présente à l’utilisateur des flux de données applicatives de bout en bout.
Introduction
Le flux de données de la logique applicative n’est presque jamais transmis tel quel sur le canal physique. Une telle transmission provoquerait très probablement un dysfonctionnement du MGT, pour les raisons indiquées précédemment. Dans presque toutes les applications, le MGT ou la logique applicative applique un codage au flux de données afin de garantir le bon fonctionnement du canal physique. Ce codage contribue également à la synchronisation entre l’émetteur et le récepteur.
Il y a toutefois des exceptions : dans cet exemple complet de conception, le MGT est utilisé comme un simple SERDES, sans aucun codage activé. Cela est possible parce que la logique applicative implémente l’embrouilleur (scrambler) et les autres fonctionnalités requises.
Cette page présente les principes de base des techniques de codage les plus utilisées. La liste des protocoles de la page précédente établit le lien entre ces codages et les protocoles utilisés entre FPGA.
Codage 8b/10b
Le codage 8b/10b est utilisé par plusieurs protocoles, par exemple certaines versions de PCIe, Gigabit Ethernet, SATA, DisplayPort et SuperSpeed USB. Tous les MGT de FPGA disposent d’un codeur et d’un décodeur 8b/10b intégrés, même si ce codeur peut également être implémenté dans la logique programmable.
Ce codage transforme chaque octet (8 bits) en un mot de 10 bits. Le but principal de cette transformation est de créer une séquence de bits contenant en moyenne le même nombre de « 0 » et de « 1 ». En d’autres termes, les bits du flux codé sont équilibrés en courant continu (DC-balanced). Le codage garantit en outre qu’il y a suffisamment de transitions entre « 0 » et « 1 » dans le flux, afin que le mécanisme de CDR (Clock Data Recovery) puisse fonctionner correctement.
Notons toutefois que le codage 8b/10b ne randomise pas le flux de données. En particulier, le codage 8b/10b ne suffit pas à lui seul si un égaliseur (equalizer) est utilisé et que cet égaliseur exige que le flux de données soit statistiquement aléatoire.
Pour atteindre l’équilibre en courant continu, certains mots de 8 bits peuvent être codés de deux manières possibles. Par exemple, l’octet 0x20 (00100000, noté D0.1) peut être codé comme 1001111001 ou comme 0110001001. Dans les deux cas, il est décodé en 0x20. Notons que la première possibilité contient quatre bits à « 0 » et six bits à « 1 ». La seconde contient six bits à « 0 » et quatre bits à « 1 ». Toute l’idée du codage 8b/10b est là : le codeur dispose de deux possibilités, l’une avec plus de « 0 » que de « 1 », et l’autre avec la répartition inverse.
Le codeur se sert de cette propriété pour assurer l’équilibre entre les « 0 » et les « 1 » à long terme : il mémorise s’il y a eu jusqu’ici trop de « 0 » ou trop de « 1 » dans le flux. Ce déséquilibre est appelé disparité courante (Running Disparity). Le codeur choisit le mot de 10 bits qui contribue à réduire ce déséquilibre.
Tous les mots de 8 bits n’ont pas deux candidats de 10 bits. Par exemple, l’octet 0x23 (00100011, noté D3.1) est toujours codé en 1100011001. Ce mot codé contient autant de « 0 » que de « 1 » ; il n’influence donc pas la disparité courante.
Ce codage a été publié pour la première fois en 1983 et a été très populaire dans les protocoles introduits jusqu’aux environs de 2010. Il l’est moins dans les protocoles publiés récemment. La raison principale est qu’un embrouilleur fait souvent partie intégrante du protocole. L’équilibre en courant continu du flux est alors garanti par l’embrouilleur, de sorte que le codage 8b/10b n’est pas nécessaire à cette fin. L’embrouilleur garantit aussi que les transitions entre « 0 » et « 1 » se produisent assez souvent. En revanche, le codage 8b/10b ajoute 25 % de bits supplémentaires à transmettre sur le canal physique. Ces bits supplémentaires auraient pu servir à transmettre des données utiles.
Cela dit, certains protocoles qui utilisent un embrouilleur ont aussi recours au 8b/10b. Par exemple, toutes les versions de PCIe exigent un embrouilleur, mais le 8b/10b est également utilisé dans les versions de PCIe antérieures à 3.0. Le codage 8b/10b présente donc manifestement d’autres avantages. Ceci nous amène au sujet suivant : les symboles K.
Symboles K
Le fait qu’un codeur 8b/10b génère 10 bits à partir des 8 bits qu’il code signifie que le mot codé possède 1024 combinaisons possibles, contre 256 pour le mot d’origine. Même en supposant que chaque mot d’origine ait deux mots codés possibles, cela ne couvrirait que 512 combinaisons. Comme indiqué plus haut, certains mots de 8 bits n’ont qu’un seul mot de 10 bits possible, si bien qu’il y a moins de 512 mots de 10 bits utilisés. On en conclut donc qu’au moins 512 combinaisons de mots de 10 bits n’ont aucun mot de 8 bits correspondant.
Le codage 8b/10b permet donc de détecter certaines erreurs binaires sur la liaison physique, en repérant les mots de 10 bits interdits. Les MGT de FPGA disposent de ports de sortie qui signalent à la logique applicative la détection d’un mot de 10 bits illégal. Ce mécanisme de détection d’erreurs n’est toutefois pas très précieux, car il ne détecte pas toutes les erreurs.
La fonction réellement précieuse du codage 8b/10b est le symbole K. Un symbole K est codé et transmis à la place d’un mot de 8 bits. Le décodeur est capable de distinguer un mot de données ordinaire d’un symbole K, et il existe toujours un moyen de signaler à la logique applicative l’arrivée d’un symbole K.
Le codage 8b/10b permet ainsi à l’émetteur d’envoyer des informations supplémentaires sur le canal de données d’une manière qui ne peut pas être confondue avec des données normales. Cette fonctionnalité est souvent utilisée par les protocoles pour aider le récepteur à se synchroniser sur le flux de données de l’émetteur.
La signification des symboles K dépend du protocole. Un symbole K est toutefois utilisé par de nombreux protocoles avec la même signification : le K28.5 est souvent appelé Comma (COM) et sert à synchroniser le flux de données. Nous y reviendrons plus bas.
Lorsque le 8b/10b est activé sur un MGT de FPGA, l’interface avec la logique applicative comporte un fil séparé pour chaque octet de données. Ce fil indique si l’octet est une donnée ordinaire ou un symbole K. En d’autres termes, l’interface de transmission permet de choisir, pour chaque mot transmis, s’il s’agit d’une donnée normale ou d’un symbole K. Cela dit, lorsqu’un mot de données est marqué comme symbole K, le mot de 8 bits est limité à ces seules possibilités :
| Valeur d’octet (hex) | Symbole K |
|---|---|
| 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 |
De même, dans l’interface du récepteur MGT avec la logique applicative, il y a un fil séparé pour chaque octet reçu. Chacun de ces fils indique si l’octet correspondant doit être interprété comme une donnée ordinaire ou comme un symbole K. Le récepteur dispose en outre d’une fonctionnalité spéciale permettant de traiter le K28.5 (symbole Comma, COM) d’une manière particulière. C’est ce symbole que nous allons examiner à présent.
Le symbole Comma (K28.5)
La représentation sur 10 bits du K28.5 est 0011111010 ou 1100000101. Ce mot est particulièrement utile, car cette séquence de bits ne peut apparaître sur le canal physique qu’à la suite de la transmission d’un K28.5. Pour détecter un K28.5, le récepteur n’a pas besoin d’être synchronisé sur l’émetteur : il suffit que les dix derniers bits reçus correspondent à l’un de ces deux mots.
Cela fait du K28.5 un excellent outil pour synchroniser le récepteur. Une fois ce symbole K détecté, les limites des autres mots de 10 bits sont connues.
Les MGT de FPGA sont capables d’aligner automatiquement le flux de données entrant à l’arrivée d’un symbole K28.5. Il est généralement possible aussi de demander que l’alignement se fasse sur une limite plus large. Par exemple, on peut configurer le MGT pour aligner un K28.5 entrant sur le début d’un mot de 32 bits.
Outre l’alignement du récepteur, le symbole K28.5 peut aussi servir à aligner d’autres unités fonctionnelles ayant besoin de synchronisation. Par exemple, un protocole peut demander que l’embrouilleur soit réinitialisé en réponse à l’arrivée de ce symbole K.
En raison de ces possibilités, les protocoles exigent souvent qu’un K28.5 soit transmis périodiquement pour la synchronisation du récepteur. Les protocoles qui établissent une connexion par une poignée de main (handshake) utilisent souvent le K28.5 dans le cadre de l’établissement de la liaison. Quoi qu’il en soit, le symbole K28.5 simplifie souvent la conception du protocole au point de justifier les 25 % de bits supplémentaires transmis sur le canal physique.
Le symbole Skip (K28.0 et K28.1)
Dans la plupart des situations réelles, il existe une différence entre les fréquences d’horloge de l’émetteur et du récepteur. Cela peut poser problème : souvent, l’interface entre le MGT et la logique applicative est synchrone avec l’horloge locale du récepteur. Les données arrivent donc au rythme de l’horloge de l’émetteur, mais sont remises à la logique applicative au rythme de l’horloge du récepteur.
En d’autres termes, les données reçues par un MGT arrivent à une cadence imposée par l’autre côté. C’est pourtant l’horloge locale qui détermine la vitesse à laquelle les données sont consommées.
Si la fréquence d’horloge de l’émetteur est plus élevée, la logique applicative extrait les données du MGT trop lentement. Les données excédentaires finissent par s’accumuler et un débordement (overflow) se produit quelque part dans le MGT. En revanche, si la fréquence de l’émetteur est plus basse, la logique applicative veut extraire les données plus vite qu’elles n’arrivent. C’est là aussi un problème.
Ce problème a une solution simple : ajouter des « symboles Skip ». Par exemple, le protocole SuperSpeed USB définit un « SKP Ordered Set » (ensemble ordonné SKP) comme deux symboles K28.1 consécutifs. Le protocole exige que ces deux symboles K28.1 soient transmis une fois toutes les 354 mots de données ordinaires. Le MGT récepteur est autorisé à éliminer ces symboles K28.1 au lieu de les présenter à la logique applicative. Cela résout le problème des données excédentaires lorsque l’horloge de l’émetteur est plus rapide que celle du récepteur : lorsque le MGT récepteur commence à accumuler des données en raison de l’écart de fréquence, il ignore les symboles K28.1 qui arrivent.
Grâce à ce mécanisme, l’émetteur peut transmettre 356 mots pendant que la logique applicative du récepteur n’en consomme que 354. Avec le calcul 356 / 354 ≈ 1,00565, ce mécanisme peut donc compenser un écart de fréquence pouvant atteindre ~0,565 % entre les deux horloges. Cela dépasse bien entendu ce que la spécification du protocole autorise.
Le MGT du récepteur est également autorisé à ajouter des symboles K28.1 à un « SKP Ordered Set » existant. Cela peut aider lorsque l’horloge de l’émetteur est plus lente. Dans ce cas, la logique applicative du côté récepteur tente d’extraire les données plus vite qu’elles n’arrivent. Le MGT est donc autorisé à combler les emplacements manquants avec des symboles K28.1 : la logique applicative est de toute façon censée ignorer tous les symboles K28.1.
Le protocole PCIe utilise le symbole Skip d’une manière semblable. Le « SKP Ordered Set » de PCIe a toutefois un format différent : il se compose de quatre symboles K : d’abord un K28.5 (Comma), puis trois symboles K28.0. Les principes d’utilisation du symbole Skip n’en restent pas moins les mêmes.
Le protocole USB et le protocole PCIe utilisent tous deux l’abréviation SKP pour désigner ces ensembles ordonnés. Il faut noter que SKP désigne K28.1 dans le protocole SuperSpeed USB, mais K28.0 dans le contexte de PCIe. Cela prête à confusion.
Codage 64b/66b
Comme on l’a déjà mentionné, le codage 8b/10b utilise le canal physique de manière inefficace, et les principaux objectifs de ce codage (l’équilibre en courant continu et la garantie de transitions entre « 0 » et « 1 ») ne sont pas nécessaires lorsqu’un embrouilleur est utilisé. C’est pourquoi les protocoles plus récents ont recours au codage 64b/66b et à des méthodes analogues. Il est toutefois important de comprendre que le 64b/66b n’est pas vraiment une méthode de codage. C’est plutôt une méthode d’organisation du flux de données et des mots de contrôle. Les données ne sont pas transformées dans une représentation différente. Tout ce qui se passe, c’est que les données sont organisées en segments et que des bits supplémentaires sont insérés pour permettre la synchronisation et l’envoi d’informations de contrôle sur le canal.
Notons que les symboles K n’existent que dans le codage 8b/10b ; ils ne sont pas disponibles dans les autres formats de codage.
Le codage 64b/66b est utilisé par plusieurs protocoles, par exemple Ethernet 10G/100G. Il convient de noter que les versions évoluées de PCIe et d’USB reposent sur d’autres méthodes, comme expliqué plus loin.
Le codage 64b/66b divise le flux de données en segments de 64 bits et ajoute deux bits au début de chaque segment. Chaque segment mesure donc 66 bits sur le canal physique. Ces deux bits supplémentaires ne peuvent prendre que deux valeurs : « 01 » ou « 10 ». S’ils valent « 01 », le mot de 64 bits qui suit contient huit octets de données. S’ils valent « 10 », l’octet suivant contient un code qui définit le contenu des 56 bits restants : le nombre de mots de données et le nombre de mots de contrôle.
Les mots de contrôle servent notamment à marquer le début et la fin des trames (paquets), mais aussi à insérer des mots d’inactivité (idle words) pour compenser les différences de fréquence d’horloge (comme les symboles Skip du 8b/10b). Des mots de contrôle spécifiques à un protocole peuvent aussi être définis.
Comme déjà mentionné, si les deux premiers bits sont « 10 », les 64 bits restants sont divisés en deux parties : un mot de code de 8 bits et 56 bits composés d’une combinaison de mots de données et de mots de contrôle. L’organisation des mots de données et de contrôle dans le segment de 56 bits est assez compliquée, principalement parce que chaque mot de contrôle est long de 7 bits. Cette particularité est nécessaire pour permettre d’insérer huit mots de contrôle dans les 56 bits restants.
En outre, les protocoles qui utilisent ce codage ont aussi recours à un embrouilleur afin d’assurer l’équilibre en courant continu et le caractère aléatoire des données. Ce caractère aléatoire n’est pas nécessaire uniquement pour l’égaliseur : le récepteur en a également besoin pour trouver le début des segments de 66 bits dans le flux de données reçu. Pour cela, il examine les deux premiers bits de chaque segment de 66 bits. Si cette paire ne prend que les valeurs « 01 » ou « 10 » de façon répétée, le récepteur est synchronisé. Sinon, il doit essayer une autre position. L’embrouilleur garantit que tous les autres bits sont aléatoires ; si le récepteur est mal aligné, une combinaison « 00 » ou « 11 » apparaîtra rapidement à la place des combinaisons valides.
Dans l’ensemble, le 64b/66b exploite mieux le canal physique sous-jacent, mais un protocole qui utilise cette méthode est plus difficile à implémenter. En particulier, la nécessité de traiter chaque segment différemment (selon ses deux premiers bits et, éventuellement, selon l’octet qui suit) ajoute de la complexité à l’implémentation. Les différents MGT de FPGA offrent différents niveaux d’assistance à cet égard. Certains MGT, notamment, disposent d’un mécanisme intégré qui aligne automatiquement le récepteur sur les segments de 66 bits des données entrantes. La logique applicative reste toutefois responsable de la tâche la plus délicate, qui consiste à extraire le contenu des segments de 66 bits contenant un mélange de mots de données et de mots de contrôle.
Un MGT de FPGA est susceptible de comporter un module intégré de conversion de largeur de mots (gearbox) pour extraire les mots de 64 bits du flux de segments de 66 bits. Les modules de conversion de ce type sont abordés plus en détail dans la page suivante de cette série.
64b/67b, 128b/130b et 128b/132b
Même si le 64b/66b exploite mieux le canal physique, cette méthode est compliquée à mettre en œuvre. C’est probablement la raison pour laquelle les protocoles PCIe et SuperSpeed USB ont pris une autre direction lorsqu’ils ont abandonné le 8b/10b.
Ces deux protocoles ont conservé l’idée de diviser le flux de données en segments. Au lieu de segments de 64 bits, ils se fondent sur des segments de 128 bits.
PCIe 3.0 et versions ultérieures reposent sur le 128b/130b. Comme pour le 64b/66b, chaque segment de 128 bits commence par « 01 » ou « 10 » pour distinguer les données des codes de contrôle. SuperSpeed USB Gen 2 repose sur le 128b/132b. Chaque segment de 128 bits commence par « 0011 » ou « 1100 » à cette même fin. La seule différence est que le protocole USB réserve quatre bits au lieu de deux, pour une meilleure protection contre les erreurs binaires.
Comme pour le 64b/66b, un embrouilleur est appliqué aux 128 bits de chaque segment afin d’assurer l’équilibre en courant continu et la randomisation du flux de données. Mais c’est là que s’arrête la ressemblance avec le 64b/66b : les deux protocoles définissent la signification du contenu de la partie de 128 bits selon leur propre structure. Autrement dit, 128b/130b et 128b/132b ne concernent que la division du flux en segments et le nombre de bits ajoutés à la partie contenant les données. Le reste est propre à chaque protocole.
Le codage 64b/67b fonctionne de manière analogue. La différence est que trois bits sont ajoutés à chaque segment de 64 bits, dans les mêmes buts. Ce codage est utilisé principalement par le protocole Interlaken.
Aucun codage
Il est possible de mettre en œuvre une liaison de communication sans aucune des méthodes de codage mentionnées ci-dessus. Un exemple d’un tel protocole est xillyp2p, qui utilise un mot de synchronisation toutes les 223 bits pour aligner et synchroniser le récepteur sur l’émetteur. Pour ce protocole, le MGT n’est qu’un SERDES. Le principal avantage de cette stratégie est que le protocole ne dépend pas du tout des autres fonctionnalités du MGT. Cela simplifie l’implémentation du protocole sur une large gamme de MGT. Un autre avantage est que l’instanciation du MGT (instantiation) est beaucoup plus simple, comme le montre cet exemple de conception.
L’inconvénient est que des ressources logiques du FPGA sont utilisées pour des tâches qui auraient peut-être pu être effectuées à l’intérieur du MGT.
Cette approche est envisageable lorsque le protocole couvre tous les besoins que le codage peut aider à satisfaire : l’équilibre en courant continu, la randomisation (si nécessaire), la synchronisation et l’alignement des mots, ainsi que la distinction entre les données et les informations de contrôle.
Résumé
Comme indiqué ci-dessus, il existe différentes approches pour coder le flux de données de la logique applicative, et il est aussi possible de n’utiliser aucun codage. Pour la plupart des applications, le codage 8b/10b est le plus simple à utiliser, mais il gaspille une partie du flux de données sur le canal physique. C’est pourquoi les protocoles plus récents ont adopté d’autres méthodes de codage, plus efficaces mais nettement plus difficiles à mettre en œuvre.
Ceci conclut la troisième page de cette série consacrée aux MGT. La page suivante présente certaines parties du PCS, notamment celles qui implémentent les codages évoqués ici.