Aller au contenu

Fonctionnement d'un ordinateur/Les exceptions précises et branchements

Un livre de Wikilivres.

Un point important est que les branchements sont identifiés à l'étage de décodage, ce qui aide grandement à les gérer. Si l'étape de décodage décode un branchement, elle sait qu'elle a potentiellement chargé des instructions à tort. Je dis potentiellement, car tout dépend de si le branchement est pris ou non. Et l'unité de décodage ne peut pas toujours le déterminer.

Les branchements inconditionnels sont dans un cas favorable : ils sont toujours pris. L'étage de décodage sait donc que les instructions suivantes ont été chargées à tord. Précisément N instructions, avec N le nombre d'étages entre le chargement et le décodage (inclus). Dans ce cas, les N instructions suivantes sont tout simplement annulés, elles sont remplacées par des NOPs. Notons qu'il ne s'agit pas de bulles de pipeline. Une bulle de pipeline retarde une instruction, elle la bloque dans l'unité de décodage. Ici, les instructions sont annulées. De plus, le processeur restaure le program counter à sa valeur adéquate naturellement, en exécutant le branchement.

L'implémentation demande juste un simple compteur et quelques circuits annexes. Évidemment, on perd un peu en performances comparé à un cas idéal, mais n'a pas le choix. Nous verrons dans quelques chapitres que des techniques de prédiction de branchement permettent de résoudre ce problème, mais laissons cela de côté pour le moment.

Notons que ne pas exécuter les instructions fonctionne car le branchement a été détecté avant l'étage de décodage. Aucun registre architectural n'a été modifié, il n'y a pas eu d'accès à la mémoire, l'état du processeur n'a pas changé. Il suffit de ne pas émettre/exécuter les instructions chargées à tort pour régler le problème. La seule subtilité est de déterminer l'adresse de destination. Si le branchement est un branchement direct, l'adresse est inclue dans l'instruction. Mais dans le cas d'un branchement relatif, les choses sont plus compliquées et il faut ajouter quelques cycles de retard en plus pour calculer l'adresse de destination dans l'ALU.

D'autres branchements sont toujours pris : les appels de fonctions, les interruptions logicielles. Ils sont traités comme les branchements inconditionnels. Par contre, les branchements conditionnels peuvent être pris ou non-pris. Et on doit tenir compte de deux cas : est-ce que le branchement est pris ou non. Si le branchement n'est pas pris, aucun problème : les instructions n'ont pas été chargées à tord. Par contre, ce n'est pas le cas pour les branchements pris.

Pour les branchements conditionnels, la technique précédente ne fonctionne pas. On ne sait pas si le branchement est pris ou non à l'étage de décodage, il faut exécuter le branchement pour ça. Et le temps que le résultat du branchement soit connu, des instructions chargées à tord auront le temps d'atteindre l'unité d'émission, voire les unités de calcul. Elles auront l'opportunité de s'exécuter, de calculer leur résultat, voire de modifier des registres.

Une solution utilisée sur le pipeline RISC classique est de calculer les branchements pendant l'étape de décodage, dans une ALU spécialisée qui travaille en parallèle de l'unité de décodage. Le défaut de cette technique est que l'ALU en question doit lire les registres. Pour rappel, sur ce pipeline, l'étape de décodage effectue la lecture des opérandes dans les registres, en parallèle de l'unité de décodage. Mais ce qu'on n'a pas dit dans le chapitre précédent, c'est qu'elle effectue aussi le calcul des branchements dans une mini-ALU séparée ! Ce faisant, le résultat du branchement est connu dès la fin de l'étape de décodage.