Skip to content

Niveau 7 · Chapitre 7.8

Chronogrammes de bus, poignées de main et arbitrage

Comment un transfert sur un bus se règle à la nanoseconde : lire un chronogramme, une lecture synchrone avec états d’attente calculée pas à pas, la latence CAS de la DRAM en cycles et en nanosecondes, la poignée de main asynchrone complète, l’arbitrage en guirlande sur un circuit vivant, et les cycles en rafale, verrouillés et d’interruption.

Le chapitre sur le chemin de données a présenté le bus système : lignes d’adresse, de données et de contrôle, cycles de bus, états d’attente, maîtres et arbitrage. Ce chapitre descend d’un niveau, vers ce qui se passe sur ces fils nanoseconde par nanoseconde. Deux questions le traversent : quand la valeur d’un fil est-elle valide, et qui a le droit de piloter ce fil ?

Lire un chronogramme

Les fiches techniques décrivent les bus par des chronogrammes (timing diagrams) : le temps s’écoule de gauche à droite, et chaque signal a sa rangée.

  • Un fil isolé, comme l’horloge ou une ligne de contrôle, est dessiné haut ou bas. Ses fronts sont dessinés en biais, parce qu’aucun signal ne change en un temps nul.
  • Un groupe de fils, comme le bus d’adresse ou de données, est dessiné par deux lignes parallèles quand sa valeur est valide, qui se croisent là où la valeur change. Les hachures signifient « sans importance, ou non piloté ».
  • Les signaux de contrôle sont activés (ils font leur travail) ou désactivés, quelle que soit la tension correspondante. Un nom surmonté d’une barre ou suivi d’un #, comme MREQ# ou RD#, est actif à l’état bas.

Autour de chaque front, le chronogramme indique des paramètres de temps avec une valeur minimale ou maximale. C’est un contrat entre puces : le CPU garantit par exemple que l’adresse sera valide au plus 1 ns après un front d’horloge, et la mémoire promet que ses données seront valides un certain temps après avoir vu l’adresse. Le récepteur obéit aux mêmes règles de temps de prépositionnement (setup) et de maintien (hold) qu’une bascule : les données doivent être stables un moment avant le front d’échantillonnage et le rester un moment après.

Une lecture synchrone, pas à pas

Sur un bus synchrone, tout se passe par rapport à une horloge de bus. Prenons un bus cadencé à 200 MHz, où chaque cycle de bus dure donc 5 ns, et un CPU dont la fiche technique indique :

ParamètreValeurSignification
T_AD≤ 1 nsadresse valide après le front montant qui ouvre T1
T_ML≥ 0,5 nsadresse stable avant l’activation de MREQ#
T_DS≥ 0,5 nsdonnées stables avant le front qui les échantillonne (setup)
lecture minimale2 cyclesdonnées échantillonnées au front montant qui termine T2, sauf si WAIT# est activé

Sans état d’attente, la mémoire dispose au plus de 2 × 5 − 1 − 0,5 = 8,5 ns entre le moment où l’adresse devient valide et celui où les données doivent être sur le bus. Chaque état d’attente (wait state) ajoute un cycle de 5 ns. Une mémoire qui a besoin de t ns demande donc le plus petit nombre d’états d’attente k tel que 8,5 + 5k ≥ t :

Temps d’accès de la mémoireÉtats d’attenteDurée de la lecture
8 ns02 cycles, 10 ns
12 ns13 cycles, 15 ns
15 ns24 cycles, 20 ns

Voici le cas à 12 ns, cycle par cycle :

SignalT1 (0–5 ns)T2 (5–10 ns)T3 (10–15 ns)à 15 ns
CLKmonte à 0monte à 5monte à 10monte : front d’échantillonnage
ADDRESSvalide à 1 ns au plus tardvalidevalidelibérée
MREQ#, RD#activés à 2,5 nsactivésactivésdésactivés
WAIT#-activé par la mémoiredésactivé-
DATAnon pilotéesnon pilotéesvalides à 13 ns au plus tardéchantillonnées

Le CPU regarde WAIT# à la fin de T2, le voit activé, et insère un cycle. Les données de la mémoire sont valides à 1 + 12 = 13 ns, 2 ns avant le front d’échantillonnage à 15 ns, ce qui couvre largement les 0,5 ns de prépositionnement.

Deux leçons en découlent. D’abord, un bus synchrone arrondit tout au cycle entier supérieur : une mémoire qui a besoin de 8,6 ns coûte autant qu’une mémoire qui en demande 13,4. Ensuite, l’écart entre MREQ# et l’adresse (T_ML) compte : MREQ# pilote en général les sélections de puce, et le décodeur d’adresse qui les produit doit voir une adresse stable d’abord, sinon deux puces peuvent être sélectionnées en même temps pendant un instant.

Les états d’attente aujourd’hui : la latence CAS

Les bus partagés classiques, où de nombreuses puces pendaient à de longs fils, tournaient entre 5 et 133 MHz. Des liaisons point à point courtes vont bien plus vite : une interface mémoire DDR5-4800 est cadencée à 2,4 GHz. Le principe du compte en cycles entiers reste le même, et les états d’attente aussi.

Les interfaces DRAM modernes sont synchrones, et leurs états d’attente ont un nom : la latence CAS (CL), le nombre de cycles d’horloge entre une commande READ et la première donnée. Les classes de vitesse standard du JEDEC donnent :

MémoireHorlogeCycleLatence CASEn nanosecondes
DDR3-1600 (classe K)800 MHz1,25 ns11 cycles13,75 ns
DDR4-3200 (classe AA)1600 MHz0,625 ns22 cycles13,75 ns
DDR5-4800 (classe B)2400 MHz0,417 ns40 cycles16,7 ns

L’horloge a doublé puis triplé, et le nombre de cycles d’attente a grandi avec elle : le temps dont les cellules DRAM ont besoin n’a presque pas bougé. Ce que les interfaces plus rapides ont apporté, c’est de la bande passante (plus de données par nanoseconde une fois le flux lancé), pas une attente plus courte.

Vu d’un programme, le trajet complet est encore plus long. En suivant des pointeurs dans un tableau mélangé au hasard sur l’Apple M2 Ultra de ce chapitre, chaque chargement a pris environ 0,92 ns quand le tableau faisait 16 Kio, bien à l’intérieur du cache L1 (environ 3 cycles aux 3,24 GHz auxquels tournait le cœur), et 120 à 133 ns quand il couvrait de 64 Mio à 1 Gio et que presque chaque chargement allait jusqu’à la DRAM (deux séries de mesures). Cela fait environ 400 cycles du cœur : la latence CAS n’en est qu’une partie, le reste venant des caches traversés en vain, de la traduction d’adresse, des files d’attente du contrôleur mémoire et du réseau interne de la puce. Pour un cœur de CPU, la mémoire principale est un périphérique qui réclame des centaines d’états d’attente.

Bus asynchrones et poignée de main complète

Un bus synchrone est simple, mais il doit être réglé sur son périphérique le plus lent, et il ne peut pas profiter d’un périphérique plus rapide sans changer d’horloge. Un bus asynchrone n’a pas d’horloge. Chaque étape est déclenchée par la précédente, dans une poignée de main complète (full handshake) entre le maître et l’esclave. Pour une lecture :

ÉtapeMaîtreEsclave
1place l’adresse sur le bus, active MREQ et RD, puis active MSYN (« maître prêt »)
2voit MSYN, lit sa mémoire, place les données sur le bus, active SSYN (« esclave prêt »)
3voit SSYN, mémorise les données, désactive MSYN et libère l’adresse
4voit MSYN désactivé, désactive SSYN et libère les données

Chaque événement est causé par le précédent, jamais par un coup d’horloge : le transfert dure exactement le temps dont cette paire de périphériques a besoin, et un périphérique rapide n’attend jamais au rythme d’un lent. Comme chaque signal monte puis redescend, on parle aussi de poignée de main à quatre phases.

La plupart des bus sont restés synchrones parce qu’ils sont plus faciles à concevoir et à vérifier. Mais l’idée de poignée de main est partout :

  • le 68000 de Motorola, le processeur du premier Macintosh, utilisait un bus asynchrone : il activait un signal d’adresse valide et attendait que la mémoire réponde par DTACK (data transfer acknowledge) ;
  • sur le bus I²C, encore présent sur toutes les cartes mères pour parler aux petites puces, un périphérique lent peut maintenir la ligne d’horloge à l’état bas, c’est l’étirement d’horloge (clock stretching), ce qui greffe une poignée de main sur un bus cadencé ;
  • à l’intérieur des puces, l’interconnexion AXI d’ARM transporte chaque adresse et chaque donnée avec une paire VALID/READY : l’émetteur active VALID, le récepteur active READY, et le transfert a lieu au front d’horloge où les deux sont hauts. C’est une poignée de main échantillonnée par une horloge, le meilleur des deux mondes ;
  • PCI Express remplace la poignée de main par des crédits : un récepteur annonce la place libre dans ses tampons, et l’émetteur s’arrête quand les crédits sont épuisés (chapitre sur PCI Express).

L’arbitrage : qui pilote le bus

Un bus partagé ne peut avoir qu’un seul pilote à la fois. Quand plusieurs maîtres (le CPU, un contrôleur de disque en DMA, une carte réseau) le veulent en même temps, un arbitre décide. Le schéma centralisé le plus simple est la guirlande (daisy chain). Chaque périphérique peut tirer une ligne de requête partagée. L’arbitre répond sur une unique ligne d’attribution (grant), câblée à travers les périphériques en série : un périphérique qui ne demande rien passe l’attribution au suivant, et celui qui demande la garde.

Logic · Arbitrage en guirlande avec trois périphériques

À essayer : Cliquez sur un interrupteur d’entrée du circuit (ou sur son bouton au-dessus) pour le basculer. Les portes et la table de vérité suivent.

auto
0
gate delays
stable after 0
stable
state
4
critical path
gate delays, worst case
8
gates
arbiterdevice 1device 2device 3REQ1REQ2REQ3OR gate: output 11GRANTAND gate: output 00GNT1NOT gate: output 1AND gate: output 1AND gate: output 11GNT2NOT gate: output 0AND gate: output 0AND gate: output 00GNT3
1 0 inputs changed, output switches next delayclick a switch to toggle it
REQ1REQ2REQ3GRANTGNT1GNT2GNT3
0000000
0011001
0101010
0111010
1001100
1011100
1101100
1111100

One grant line, wired through the devices in series. A device that is requesting keeps the grant (GNT); one that isn't passes it on. So the device closest to the arbiter always wins: turn on REQ2 and REQ3, then REQ1. Each device adds a gate delay to the grant's trip, which is why long daisy chains are slow.

Unit-delay model: every gate takes one step to react. With auto off, toggle switches and press step to watch the change travel gate by gate.

Les périphériques 2 et 3 demandent tous les deux, et le 2, plus proche de l’arbitre, a l’attribution (GNT2). Ensuite :

  1. Coupez REQ2 : l’attribution descend d’un périphérique, et GNT3 s’allume. En partant de zéro, REQ3 seul met 4 délais de porte à être servi, contre 2 pour REQ1 : chaque périphérique de la chaîne ajoute du retard.
  2. Rallumez REQ2, puis REQ1. C’est maintenant le périphérique 1 qui gagne. Mais regardez de près avec auto désactivé : pendant deux délais de porte, GNT1 et GNT2 sont allumés en même temps, parce que GNT1 monte avant que le signal « passe au suivant » vers le périphérique 2 soit retombé.

Ce chevauchement explique pourquoi les vrais arbitres ne déplacent jamais l’attribution au milieu d’un transfert. Le périphérique qui gagne active une troisième ligne, BUSY (ou un acquittement), tant qu’il utilise le bus, et l’attribution ne bouge qu’une fois BUSY relâché. C’est aussi pourquoi l’arbitrage se fait en général pendant un transfert pour décider du suivant, afin de ne perdre aucun cycle de bus.

Les priorités figées de la guirlande ont un revers : un périphérique proche de l’arbitre qui demande sans arrêt peut affamer ceux qui sont derrière lui pour toujours. Les vrais systèmes ajoutent plusieurs lignes de requête et d’attribution de priorités différentes, ou rendent l’arbitre tournant (round-robin), en donnant le bus à chaque demandeur à tour de rôle. Le bus PCI donnait à chaque emplacement ses propres broches de requête et d’attribution vers un arbitre central dont la spécification laissait l’algorithme libre, justement pour qu’il puisse être équitable.

L’arbitrage décentralisé

L’arbitrage peut aussi se faire sans arbitre. Dans l’un de ces schémas, chaque périphérique lit la ligne d’arbitrage venant de son voisin et ne la transmet que s’il ne veut pas le bus lui-même, comme une guirlande dont la tête serait branchée en permanence sur « attribué ».

Une astuce plus élégante utilise des lignes à drain ouvert (ou collecteur ouvert), que n’importe quel périphérique peut tirer à 0 et que personne ne pilote à 1 ; une résistance s’en charge. La ligne vaut alors le AND de ce qu’envoient tous les périphériques, et deux d’entre eux peuvent émettre en même temps sans dommage. Sur le bus I²C et sur le bus CAN des voitures, les maîtres concurrents envoient les en-têtes de leurs messages bit par bit tout en écoutant : un périphérique qui envoie un 1 mais relit un 0 sait qu’un autre, plus prioritaire, est en train d’émettre, et se retire sans bruit. Le gagnant ne remarque même pas qu’il y a eu une compétition, et son message passe intact.

Les autres sortes de cycles de bus

Les transferts en bloc. Charger toute une ligne de cache mot par mot répéterait la phase d’adresse à chaque fois. À la place, le maître envoie une adresse et l’esclave renvoie des mots consécutifs sur des cycles consécutifs : une rafale (burst). La mémoire DDR ne fonctionne que comme cela : une lecture DDR4 renvoie une rafale de 8 transferts de 64 bits, et une lecture DDR5 une rafale de 16 transferts sur un sous-canal de 32 bits. Les deux font 64 octets, une ligne de cache sur la plupart des processeurs, livrée par une seule commande READ.

Le contrôleur mémoire recouvre aussi les commandes destinées à des bancs différents : pendant qu’un banc est encore en train d’ouvrir une ligne (ACTIVATE), un autre peut envoyer sa rafale, et un troisième refermer sa ligne (PRECHARGE). En DDR3, par exemple, quatre accès peuvent se recouvrir de cette façon. Comme tout est synchrone sur l’interface, le contrôleur sait à quel cycle chaque réponse reviendra et ordonnance les commandes comme un pipeline.

Les cycles verrouillés. Deux CPU qui incrémentent le même compteur ne doivent pas lire tous les deux l’ancienne valeur avant que l’un d’eux écrive. Les anciens bus avaient un cycle lecture-modification-écriture (read-modify-write) qui gardait le bus verrouillé entre la lecture et l’écriture ; le préfixe lock du 8086 activait une broche LOCK# exactement pour cela. L’instruction existe toujours :

; x86-64: __atomic_fetch_add(&counter, 1, __ATOMIC_SEQ_CST)
    lock inc QWORD PTR [rip+counter]

; ARM64 (v8.1 and later): the same, as one atomic instruction
    mov     w8, #1
    adrp    x9, counter
    add     x9, x9, :lo12:counter
    ldaddal x8, x8, [x9]

Aujourd’hui, le verrou n’atteint presque jamais un bus. Le cœur prend la ligne de cache en propriété exclusive grâce au protocole de cohérence des caches, fait la lecture et l’écriture dans son cache, et retarde simplement ses réponses aux demandes des autres cœurs pour cette ligne jusqu’à ce qu’il ait fini. Seule une opération atomique à cheval sur deux lignes de cache se rabat encore sur le verrouillage de tout le système mémoire, ce qui perturbe tellement la machine que les noyaux Linux récents savent détecter ces verrous fendus (split locks) et avertir, ou ralentir, le programme qui les provoque.

Les cycles d’interruption. Sur les PC classiques, le CPU acquittait une interruption par un cycle de bus spécial pendant lequel le contrôleur d’interruptions 8259A plaçait un numéro de vecteur sur le bus de données. Les périphériques PCI Express envoient plutôt une écriture mémoire ordinaire à une adresse spéciale, comme l’explique le chapitre sur les interruptions : l’interruption est devenue une transaction comme une autre sur le bus.

À retenir

  • Les chronogrammes donnent une rangée à chaque signal et à chaque front un temps minimal ou maximal garanti. Les règles de prépositionnement et de maintien disent quand une donnée peut être échantillonnée.
  • Sur un bus synchrone, un périphérique lent demande des états d’attente, par cycles entiers. Sur un bus à 200 MHz avec une lecture minimale de 2 cycles, une mémoire de 12 ns demande un état d’attente.
  • Les états d’attente de la DRAM, c’est sa latence CAS : 11 cycles en DDR3-1600, 22 en DDR4-3200, 40 en DDR5-4800, soit de 14 à 17 ns environ à chaque fois. Un chargement qui rate tous les caches du M2 Ultra a pris de 120 à 133 ns.
  • Un bus asynchrone remplace l’horloge par une poignée de main complète (MSYN/SSYN, ou DTACK) ; VALID/READY, l’étirement d’horloge et les crédits prolongent l’idée.
  • Une guirlande attribue le bus au demandeur le plus proche de l’arbitre, avec un délai de porte par périphérique. Lignes BUSY, niveaux de priorité, arbitrage tournant et arbitrage bit à bit sur lignes à drain ouvert (I²C, CAN) corrigent ses défauts.
  • Au-delà des simples lectures et écritures, les bus font des rafales (64 octets par lecture DDR4 ou DDR5), des cycles verrouillés de lecture-modification-écriture (désormais réalisés dans le cache) et des cycles d’interruption (désormais des écritures mémoire).

Dans ce niveau

  1. 7.1Portes et algèbre de Boole
  2. 7.2Additionneurs, ALU et drapeaux
  3. 7.3Multiplexeurs, décodeurs et bus
  4. 7.4Verrous, bascules et horloge
  5. 7.5Registres et matrices mémoire
  6. 7.6Puces SRAM, DRAM, ROM et flash
  7. 7.7Puces de CPU, broches et boîtiers
  8. 7.8Chronogrammes de bus, poignées de main et arbitrage
  9. 7.9Bus réels : PCI, PCI Express et USB
  10. 7.10Circuits d’E/S et décodage d’adresses