Le chapitre précédent a montré comment on cadence et on partage un bus. Celui-ci s’intéresse aux vrais bus qui relient les périphériques à un PC : ISA, PCI, PCI Express et USB. C’est aussi l’histoire d’un grand changement : des bus parallèles larges partagés par de nombreux périphériques aux liaisons série étroites qui en relient chacune exactement deux, et transportent des paquets plutôt que des signaux.
ISA et PCI : l’ère du parallèle
Le bus ISA du PC/AT d’IBM tournait à 8,33 MHz et transférait 2 octets par cycle : 16,7 Mo/s au mieux. Il était trop lent pour le graphisme dès le début des années 1990, et Intel a conçu son remplaçant, PCI (Peripheral Component Interconnect). Le bus PCI d’origine transférait 32 bits par cycle à 33 MHz, 133 Mo/s, et les versions suivantes ont doublé la largeur et l’horloge, jusqu’à environ 530 Mo/s.
PCI est un bus synchrone classique, et on y retrouve l’essentiel du chapitre précédent :
- adresse et données multiplexées : les mêmes 32 lignes AD portent l’adresse au premier cycle et les données ensuite. Une lecture demande un cycle de retournement (turnaround) entre les deux, pour que le maître cesse de piloter les lignes avant que la cible commence ;
- le maître lance une transaction en activant FRAME#. Il signale qu’il est prêt avec IRDY# ; la cible revendique l’adresse avec DEVSEL# et signale qu’elle est prête avec TRDY#. Chaque côté insère des états d’attente en gardant simplement son signal READY désactivé : une poignée de main sur un bus cadencé ;
- l’arbitrage est centralisé : chaque emplacement a ses propres lignes REQ# et GNT# vers un arbitre dans le chipset ;
- chaque périphérique a un espace de configuration de 256 octets, lu par des cycles de configuration spéciaux, qui indique au système ce qu’est le périphérique et de quelles ressources il a besoin. Il a rendu possible le plug-and-play, et c’est la partie de PCI qui a survécu.
PCI a longtemps été le principal bus de périphériques des PC ; PCI Express l’a remplacé pour tout ce qui est rapide dans les années 2000. Aujourd’hui, le PCI parallèle et son dérivé graphique AGP ont disparu des ordinateurs neufs, remplacés par PCI Express.
PCI Express : des lignes, pas un bus
Le problème, quand on accélère un bus parallèle, c’est le décalage (skew) : les bits d’un mot, qui voyagent sur des fils différents, n’arrivent pas exactement en même temps, et à haute fréquence l’écart devient une grosse fraction d’un cycle d’horloge. Les fils partagés sont aussi longs, avec de nombreux connecteurs en chemin, qui réfléchissent chacun une partie du signal.
PCI Express (PCIe) règle les deux problèmes en renonçant au bus partagé :
- chaque périphérique a une liaison point à point dédiée vers un port d’un commutateur (switch) ou du complexe racine (root complex, dans le CPU ou le chipset). Pour brancher plus de périphériques qu’il n’y a de ports, on ajoute un commutateur, qui a une liaison montante et plusieurs descendantes. La topologie est un arbre, comme un réseau Ethernet commuté ;
- une liaison est faite de lignes (lanes). Chaque ligne a deux paires différentielles, une par sens. Une paire différentielle transporte chaque bit comme la différence entre deux fils pilotés en sens opposés, ce qui annule l’essentiel du bruit capté en route. Les deux fils de la paire portent le signal ; aucun n’est une masse ;
- une liaison a 1, 2, 4, 8 ou 16 lignes (×1 à ×16 ; ×12 et ×32 ont aussi été définis mais ne servent pratiquement pas). Les octets successifs d’un paquet sont répartis sur les lignes, et chaque ligne est reçue et resynchronisée séparément : le décalage entre lignes est corrigé par le récepteur au lieu de limiter l’horloge ;
- il n’y a pas d’horloge de bus. L’émetteur intègre son horloge dans le flux de données et le récepteur la récupère à partir des transitions. La plupart des systèmes distribuent tout de même une horloge de référence commune de 100 MHz aux périphériques, dont les deux extrémités tirent leur débit binaire.
Encodage et générations
Pour que le récepteur récupère l’horloge, les données doivent avoir assez de transitions : une longue suite de bits identiques est une ligne plate. L’encodage 8b/10b, utilisé par PCIe 1.0 et 2.0, transforme chaque octet en un symbole de 10 bits choisi dans une table qui garantit des transitions fréquentes et autant de 1 que de 0 sur la durée. Il coûte 20 % du débit brut : 2,5 GT/s (gigatransferts, bits bruts par seconde et par ligne) portent 2 Gb/s de données. PCIe 3.0 est passé au 128b/130b : 128 bits de données brouillées plus un en-tête de 2 bits, seulement 1,5 % de surcoût. PCIe 6.0 est allé plus loin, en envoyant deux bits par symbole avec quatre niveaux de tension (PAM4) et en regroupant les données en flits de taille fixe protégés par une correction d’erreurs directe.
| Version | Année | Par ligne | Encodage | Par ligne, chaque sens | ×16, chaque sens |
|---|---|---|---|---|---|
| 1.0 | 2003 | 2,5 GT/s | 8b/10b | 250 Mo/s | 4 Go/s |
| 2.0 | 2007 | 5 GT/s | 8b/10b | 500 Mo/s | 8 Go/s |
| 3.0 | 2010 | 8 GT/s | 128b/130b | 985 Mo/s | 15,8 Go/s |
| 4.0 | 2017 | 16 GT/s | 128b/130b | 1,97 Go/s | 31,5 Go/s |
| 5.0 | 2019 | 32 GT/s | 128b/130b | 3,94 Go/s | 63 Go/s |
| 6.0 | 2022 | 64 GT/s | PAM4, flits | environ 8 Go/s | environ 128 Go/s |
| 7.0 | 2025 | 128 GT/s | PAM4, flits | environ 16 Go/s | environ 256 Go/s |
Les chiffres de 6.0 et 7.0 s’entendent avant les quelques pour cent que les flits consacrent au contrôle d’erreurs. Chaque étape depuis la 3.0 a doublé le débit par ligne. Les liaisons de première génération tournaient à 2,5 GT/s ; les cartes graphiques et les SSD actuels utilisent 16 ou 32 GT/s, et PCIe 6.0 arrive dans les serveurs.
Des paquets au lieu de signaux
Sur un bus PCI, une lecture est un motif de signaux de contrôle. Sur PCIe, c’est un échange de paquets, construits par une pile de couches à l’intérieur de chaque puce :
- la couche transaction crée des paquets de transaction (TLP, transaction layer packets) : un en-tête de 12 ou 16 octets (type, longueur, identifiant du demandeur, adresse) et une charge utile facultative, jusqu’à la taille maximale de charge de la liaison (de 128 à 4096 octets ; 256 est courant) ;
- la couche liaison de données ajoute un numéro de séquence et un CRC de 32 bits. Le récepteur acquitte les paquets corrects et redemande les mauvais (ACK/NAK) : les erreurs sur la ligne sont corrigées par retransmission. Elle envoie aussi des crédits de contrôle de flux : l’émetteur ne peut envoyer que le nombre de paquets pour lequel le récepteur a annoncé de la place dans ses tampons ;
- la couche physique ajoute le tramage et fait l’encodage décrit plus haut.
Une lecture est une transaction scindée (split transaction) : un TLP de requête de lecture mémoire part sans données, et le périphérique répond plus tard par un ou plusieurs TLP de complétion qui les portent. Entre-temps, la liaison reste libre pour d’autres échanges. Il existe aussi des requêtes de configuration, qui atteignent le même espace de configuration qu’en PCI, et des messages, qui remplacent les signaux annexes. Une interruption d’un périphérique PCIe n’est même pas un message : c’est un TLP d’écriture mémoire ordinaire vers une adresse que surveille le contrôleur d’interruptions (MSI).
PCI Express sur une vraie machine
Le Mac Studio sur lequel ce chapitre a été écrit n’a pas d’emplacement d’extension, mais ses puces d’E/S sont quand même reliées par PCIe. macOS les liste dans l’I/O Registry :
$ ioreg -r -c IOPCIDevice -l | grep -E '"(IOName|model|compatible|IOPCIExpressLinkStatus|IOPCIExpressLinkCapabilities)"'
| "IOName" = "pci-bridge"
| "IOPCIExpressLinkCapabilities" = 7567380
| "compatible" = <"apcie-bridge">
| "IOPCIExpressLinkStatus" = 12306
| | "IOPCIExpressLinkCapabilities" = 4651026
| | "IOName" = "pci14e4,4434"
| | "IOPCIExpressLinkStatus" = 4114
| | "compatible" = <"wlan-pcie,bcm4387","wlan-pcie,bcm">
…
| "IOName" = "ethernet"
| "IOPCIExpressLinkCapabilities" = 4680772
| "compatible" = <"pci106b,223","pci1d6a,4c0","pciclass,020000","lan-10gb">
| "IOPCIExpressLinkStatus" = 4116
| "model" = "Apple AQC113"
…
Chaque périphérique se trouve derrière un port racine dédié (apcie-bridge, le pont PCIe d’Apple dans le M2 Ultra) : une liaison par périphérique, pas de bus partagé. Les nombres sont des copies des registres PCIe Link Capabilities et Link Status. Les bits 3–0 donnent la vitesse (1 = 2,5 GT/s, 2 = 5, 3 = 8, 4 = 16) et les bits 9–4 la largeur. Une fois décodés :
| Périphérique | Fabricant:modèle | Capable de | Fonctionne à |
|---|---|---|---|
| Wi-Fi et Bluetooth (Broadcom BCM4387) | 14e4:4434 | 5 GT/s ×1 | 5 GT/s ×1 (état 4114 = 0x1012) |
| Ethernet 10 Gb (Aquantia AQC113) | 1d6a:04c0 | 16 GT/s ×4 | 16 GT/s ×1 (état 4116 = 0x1014) |
| Contrôleur USB (ASMedia ASM3142) | 1b21:2142 | 8 GT/s ×2 | l’état se lit 0xFFFF |
| Lecteur de cartes SD (Genesys Logic) | 17a0:9755 | 5 GT/s ×1 | l’état se lit 0xFFFF |
La puce Ethernet pourrait utiliser quatre lignes, mais le port du M2 Ultra ne lui en donne qu’une : à 16 GT/s, une ligne transporte 1,97 Go/s dans chaque sens, plus que les 1,25 Go/s de l’Ethernet 10 Gb. Les deux derniers registres d’état, et ceux de leurs ports racines, se lisent tout à 1, la valeur que renvoie une lecture PCI quand personne ne répond : ces liaisons étaient très probablement en veille, sans carte SD insérée et, comme le montre la liste USB plus bas, sans rien sur le contrôleur ASMedia.
Une machine virtuelle Linux sur le même Mac voit un autre bus PCI, virtuel, et Linux expose l’espace de configuration de chaque périphérique sous forme de fichier :
$ cat /sys/bus/pci/devices/0000:00:01.0/{vendor,device,class}
0x1af4
0x1041
0x020000
$ head -c 64 /sys/bus/pci/devices/0000:00:01.0/config | od -A x -t x1
000000 f4 1a 41 10 06 00 10 00 01 00 00 02 00 40 00 00
000010 04 00 00 80 02 00 00 00 00 01 00 50 00 00 00 00
000020 00 00 00 00 00 00 00 00 00 00 00 00 f4 1a 41 00
000030 00 00 00 00 40 00 00 00 00 00 00 00 0e 01 00 00
000040
Les quatre premiers octets sont l’identifiant du fabricant (vendor ID) 0x1af4 et l’identifiant du modèle (device ID) 0x1041, en petit-boutiste : une carte réseau virtio. Les octets 0x09 à 0x0b, 00 00 02, forment le code de classe 0x020000, là encore en petit-boutiste : contrôleur réseau, Ethernet. Tout périphérique PCI ou PCIe au monde commence son espace de configuration ainsi, et c’est ce qui permet à un système d’exploitation de savoir ce qui est branché avant de charger le moindre pilote. Les octets 0x10 à 0x1b sont les registres d’adresse de base (BAR) du périphérique, les décodeurs d’adresse programmables que démonte le chapitre sur les E/S. (L’outil lspci, qui affiche tout cela avec les noms, n’est pas installé dans le conteneur ; les fichiers de /sys sont ce qu’il lit.)
L’USB : un seul câble pour tout le reste
PCI Express sert aux puces d’une carte. Pour les périphériques externes, l’USB (Universal Serial Bus) a remplacé les ports série, parallèle, clavier et souris des années 1990 par une seule sorte de câble. Ses choix de conception tiennent toujours :
- la topologie est un arbre : un contrôleur hôte avec un concentrateur racine (root hub), puis des concentrateurs et des périphériques, jusqu’à 127 périphériques avec des adresses de 7 bits attribuées par l’hôte au branchement ;
- l’hôte contrôle tout : un périphérique n’émet jamais sans que l’hôte le lui demande. Même les transferts « d’interruption » des claviers et des souris sont en fait l’hôte qui interroge (polling) le périphérique à intervalle fixe ;
- il y a quatre types de transferts : contrôle (configuration), bloc (bulk : disques, imprimantes ; retransmis en cas d’erreur), interruption (petits, périodiques, interrogés) et isochrone (audio, vidéo : bande passante garantie, jamais retransmis) ;
- l’hôte organise le trafic en trames de 1 ms en pleine vitesse, divisées en huit micro-trames de 125 µs en haute vitesse et au-delà.
Chaque périphérique se décrit par des descripteurs (identifiants de fabricant et de produit, version d’USB, tailles de paquets, besoins en courant) que l’hôte lit au branchement, pour que le système d’exploitation choisisse automatiquement un pilote.
Les débits ont été multipliés par plus de 50 000 :
| Vitesse | Débit | Introduite par | Signalisation |
|---|---|---|---|
| Low Speed | 1,5 Mb/s | USB 1.0 (1996) | une paire en semi-duplex, NRZI avec bourrage de bits |
| Full Speed | 12 Mb/s | USB 1.0 (1996) | idem |
| High Speed | 480 Mb/s | USB 2.0 (2000) | idem |
| SuperSpeed | 5 Gb/s | USB 3.0 (2008), aujourd’hui « USB 3.2 Gen 1 » | deux paires de plus, une par sens, 8b/10b |
| SuperSpeed+ | 10 Gb/s | USB 3.1 (2013), aujourd’hui « USB 3.2 Gen 2 » | 128b/132b |
| SuperSpeed+ ×2 | 20 Gb/s | USB 3.2 (2017), « Gen 2×2 » | deux lignes par sens, USB-C seulement |
| USB4 | 20 ou 40 Gb/s | USB4 (2019) | deux lignes par sens, USB-C seulement |
| USB4 version 2 | 80 Gb/s | USB4 v2 (2022) | signalisation PAM3 |
L’USB 1.0, de 1996, définissait déjà le Low Speed (1,5 Mb/s) et le Full Speed (12 Mb/s) ; l’USB 1.1 a suivi en 1998. Beaucoup de détails souvent cités sur l’USB appartiennent à l’USB 1.x et 2.0 : le paquet de données de 64 octets au maximum est la limite du Full Speed (les paquets bulk du High Speed portent 512 octets et ceux du SuperSpeed 1024), et le câble à quatre fils est le câble USB 2.
L’USB 1.x utilisait deux interfaces de contrôleur hôte concurrentes, UHCI et OHCI, et l’USB 2.0 a ajouté EHCI. Depuis l’USB 3.0, une seule interface standard, xHCI, gère toutes les vitesses. L’arbre USB de ce Mac montre tout cela :
$ system_profiler SPUSBHostDataType
USB 3.1 Bus:
Driver: AppleT8112USBXHCI
Unnamed Device:
Link Speed: 480 Mb/s
USB Vendor ID: 0x0451
RODE AI-1:
Link Speed: 12 Mb/s
Power Allocated: 2.5 W (500 mA)
Unnamed Device:
Link Speed: 480 Mb/s
USB Controls:
Manufacturer: LG Electronics Inc.
Link Speed: 12 Mb/s
…
USB 3.1 Bus:
Driver: AppleT8112USBXHCI
USB Receiver:
Manufacturer: Logitech
Link Speed: 12 Mb/s
USB 3.0 Bus:
PCI Vendor ID: 0x1b21
PCI Device ID: 0x2142
Driver: AppleEmbeddedUSBXHCIASMedia3142
(Réduit aux lignes intéressantes. Sur cette version de macOS, l’ancien rapport SPUSBDataType n’affiche rien ; l’arbre se trouve sous SPUSBHostDataType.) Les « Unnamed Device » à 480 Mb/s sont des concentrateurs, avec l’identifiant de fabricant 0x0451 de Texas Instruments. Une interface audio, le canal de contrôle d’un écran et un récepteur sans fil Logitech parlent tous encore à 12 Mb/s, le Full Speed de 1996, largement assez pour des échantillons audio, des frappes de touches et des mouvements de souris. Les 2,5 W attribués à l’interface audio sont la limite de l’USB 2 : 500 mA sous 5 V. Et le dernier bus est le contrôleur ASMedia du tableau PCIe plus haut : un périphérique PCIe dont le travail est d’être un hôte USB, sans rien de branché pour l’instant.
La VM Linux sur la même machine a deux contrôleurs hôtes virtuels, un par génération de signalisation :
$ cat /sys/bus/usb/devices/usb1/{speed,version} /sys/bus/usb/devices/usb2/{speed,version}
480
2.00
10000
3.10
USB-C, USB4 et Thunderbolt
L’USB-C est un connecteur, pas un protocole : une prise réversible à 24 broches. Peuvent y passer l’USB 2 sur une paire de fils dédiée, l’USB 3.x ou l’USB4 sur jusqu’à quatre paires rapides, la vidéo DisplayPort en mode alternatif, et Power Delivery, une négociation sur une ligne de configuration séparée qui fait monter la tension du bus de 5 V jusqu’à 20 V (ou 48 V dans la plage étendue) pour un maximum de 240 W. Qu’un câble et un port donnés supportent 480 Mb/s ou 80 Gb/s, 15 W ou 240 W, cela ne se voit pas sur la prise.
L’USB4 est bâti sur Thunderbolt 3, qu’Intel a confié à l’USB Implementers Forum en 2019. Son idée principale est le tunnel : une liaison USB4 transporte en même temps des paquets de plusieurs protocoles : USB 3, DisplayPort et PCI Express. Un SSD externe ou un boîtier graphique sur un port Thunderbolt est un périphérique PCIe dont les lignes passent simplement par un câble. Thunderbolt 4 (2020) est une certification de l’USB4 à 40 Gb/s avec tunnel PCIe obligatoire, et Thunderbolt 5 (2023) fonctionne à 80 Gb/s, jusqu’à 120 Gb/s dans un sens pour les écrans.
$ system_profiler SPThunderboltDataType
Thunderbolt/USB4:
Thunderbolt/USB4 Bus 5:
Vendor Name: Apple Inc.
Device Name: Mac Studio
Port:
Status: No device connected
Speed: Up to 40 Gb/s
Receptacle: 6
…
Le Mac Studio M2 Ultra a six bus de ce type, un par port USB-C (prises 1 à 6), chacun donné pour 40 Gb/s au plus et capable de faire passer du PCIe vers ce qu’on y branche. La frontière entre bus interne et câble externe, si nette à l’époque d’ISA et de PCI, a presque disparu.
À retenir
- ISA et PCI étaient des bus parallèles, synchrones et partagés : lignes d’adresse et de données multiplexées, poignées de main FRAME#/IRDY#/TRDY#, arbitrage REQ#/GNT# par emplacement. L’espace de configuration de PCI est la partie qui survit.
- PCI Express remplace le bus par des lignes point à point en paires différentielles, commutées comme un réseau, avec l’horloge intégrée aux données. L’encodage est passé du 8b/10b (20 % de surcoût) au 128b/130b (1,5 %) puis aux flits PAM4 ; chaque génération depuis la 3.0 a doublé le débit, jusqu’à 128 GT/s par ligne pour PCIe 7.0.
- PCIe transporte des paquets : des TLP avec en-tête et charge utile, protégés par un numéro de séquence, un CRC et la retransmission, cadencés par des crédits. Les lectures sont des transactions scindées, les interruptions des écritures mémoire.
- L’USB est un arbre de concentrateurs et de périphériques interrogés par l’hôte, avec des transferts de contrôle, en bloc, d’interruption et isochrones, de 1,5 Mb/s en 1996 à 80 Gb/s avec l’USB4 v2. Sur ce Mac, souris et audio tournent encore à 12 Mb/s.
- L’USB-C est un connecteur qui peut porter l’USB 2, l’USB 3.x, l’USB4, DisplayPort, Thunderbolt et jusqu’à 240 W. USB4 et Thunderbolt font passer PCI Express dans le câble.