< Fonctionnement d'un ordinateur

Il est maintenant temps de voir l'unité de contrôle. Pour rappel, celle-ci s'occupe du chargement des instructions et de leur interprétation. Elle contient l'unité de chargement, qui charge l'instruction depuis la mémoire, et le séquenceur, qui commande le chemin de données.

L’étape de chargement

Au démarrage d'un programme, le program counter est initialisé à l'adresse de sa première instruction. Cette adresse n'est pas toujours l'adresse 0 : les premières adresses peuvent être réservées pour la pile ou le vecteur d'interruptions. Le program counter est mis à jour à la fin de chaque instruction pour le faire pointer sur l'adresse suivante. Dans la grosse majorité des cas, cette adresse est calculée par l'unité de calcul ou par un circuit dédié : le compteur ordinal.

Il faut noter que l'instruction chargée est parfois stockée dans un registre, pour mettre celle-ci a disposition du séquenceur. Ce registre est appelé le registre d'instruction. Cela arrive sur les processeurs ne disposant que d'une seule mémoire. Sans cela, pas d'accès mémoire aux données : le bus mémoire serait occupé en permanence par l'instruction chargée, et ne pourrait pas servir à charger ou écrire de données. Le bus de données serait donc inaccessible, rendant toute lecture ou écriture impossible. Les processeurs basés sur une architecture Harvard arrivent cependant à se passer de ce registre, vu que le bus des instructions est séparé du bus dédié aux données.

Registre d'instruction.

L'étape de chargement (ou fetch) est toujours décomposée en trois étapes :

  • l'envoi du contenu du program counter sur le bus d'adresse ;
  • la lecture de l'instruction sur le bus de données ;
  • la mise à jour du program counter (parfois faite en parallèle de la seconde étape).
Étape de chargement.

La mise à jour du program counter sans branchement

Sur certains processeurs assez rares, chaque instruction précise l'adresse de la suivante, qui est incorporée dans l'instruction.

Sur la majorité des processeurs, on profite du fait que les instructions sont placées dans l'ordre d’exécution dans la RAM. En faisant ainsi, on peut calculer l'adresse de la prochaine instruction en ajoutant la longueur de l'instruction au contenu du 'program counter. L'adresse de l'instruction en cours est connue dans le program counter, reste à connaitre la longueur cette instruction. Lorsque les instructions ont toutes la même taille, ce calcul est simple : un simple additionneur suffit. Mais certains processeurs ont des instructions de taille variable, ce qui complique le calcul. Il y a plusieurs solutions à ce problème.

La plus simple consiste à indiquer la longueur de l'instruction dans une partie de l'opcode ou de la représentation en binaire de l'instruction.

Une autre solution consiste à charger l'instruction byte par byte, par morceaux de taille fixe. Ceux-ci sont alors accumulés les uns à la suite des autres dans le registre d'instruction, jusqu'à ce que le séquenceur détecte l'obtention d'une instruction complète. Le seul défaut de cette approche, c'est qu'il faut détecter quand une instruction complète à été chargée : un nouveau circuit est requis. Une solution similaire permet de se passer d'un registre d'instruction, en transformant le séquenceur en circuit séquentiel. Les bytes sont chargés à chaque cycle, faisant passer le séquenceur d'un état interne à un autre à chaque mot mémoire. Tant qu'il n'a pas reçu tous les mots mémoire de l'instruction, chaque mot mémoire non terminal le fera passer d'un état interne d'attente à un autre. S'il tombe sur le dernier mot mémoire d'une instruction, il rentre dans un état de décodage.

Et enfin, il existe une dernière solution, qui est celle qui est utilisée dans les processeurs haute performance de nos PC : charger un bloc de mots mémoire qu'on découpe en instructions, en déduisant leurs longueurs au fur et à mesure. Généralement, la taille de ce bloc est conçue pour être de la même longueur que l'instruction la plus longue du processeur. Ainsi, on est sûr de charger obligatoirement au moins une instruction complète, et peut-être même plusieurs. Dit autrement, les instructions doivent être alignées en mémoire (relisez le chapitre sur l'alignement et le boutisme si besoin). Cette solution pose quelques problèmes avec des instructions à cheval entre deux blocs. Il se peut qu'on n'ait pas une instruction complète lorsque l'on arrive à la fin du bloc, mais seulement un morceau.

Instructions non alignées.

Dans ce cas, on doit décaler le morceau de bloc pour le mettre au bon endroit (au début du registre d'instruction), et charger le prochain bloc juste à côté. On a donc besoin d'un circuit qui décale tous les bits du registre d'instruction, couplé à un circuit qui décide où placer dans le registre d'instruction ce qui a été chargé, avec quelque circuits autour pour configurer les deux circuits précédents.

Décaleur d’instruction.

L'unité de chargement avec des branchements

Lors d'un branchement, l'adresse de destination du branchement est copiée dans le program counter. Il faut alors court-circuiter l'adresse calculée par le compteur ordinal si le branchement s’exécute. Pour les branchements directs, l'adresse de destination est fournie par le séquenceur. Pour les branchements indirects, il suffit de relier le program counter au bus interne au processeur, et de lire le registre voulu.

Unité de chargement qui gère les branchements directs.

Pour prendre en compte les branchements relatifs, on a encore deux solutions : réutiliser l'ALU pour calculer l'adresse, ou rajouter un circuit qui fait le calcul.

Unité de chargement qui gère les branchements relatifs.

Le séquenceur

Pour rappel, le chemin de données est rempli de composants à configurer d'une certaine manière pour exécuter une instruction. Pour configurer le chemin de données, il va envoyer ce qu'il faut sur l'entrée de sélection de l'unité de calcul, les entrées du banc de registres, ou les circuits du bus du processeur. On appelle ces bits des signaux de commande. Lorsque les circuits du chemin de données reçoivent un de ces signaux de commande, elles sont conçues pour effectuer une action précise et déterminée. Les instructions sont décomposées en plusieurs étapes, appelées micro-instructions, chacune configurant le chemin de donnée d'une manière bien précise.

Pour chaque instruction, il faut déduire quelles sont les micro-opérations à exécuter et dans quel ordre. C'est le rôle de l'unité de décodage d'instruction, une portion du séquenceur qui « décode » l'instruction. Le séquenceur traduit une instruction en suite de micro-opérations et émet les signaux de commande pour chaque micro-opération.

Unité de décodage d'instruction

Les séquenceurs câblés

Il existe des processeurs dans lesquels chaque instruction est décodée par un circuit combinatoire ou séquentiel : on parle de séquenceur câblé. Plus le nombre d'instructions à câbler est important, plus le séquenceur utilise de portes logique pour sa conception. Autant dire que les processeurs CISC n'utilisent pas trop ce genre de séquenceurs et préfèrent utiliser des séquenceurs différents. Par contre, les séquenceurs câblés sont souvent utilisés sur les processeurs RISC, qui ont peu d'instructions, pour lesquels la complexité du séquenceur et le nombre de portes est assez faible et supportable.

Sur certains processeurs assez rares, toute instruction s’exécute en une seule micro-opération (chargement inclus) et donc en un seul cycle d'horloge. Un accès mémoire prend autant de temps qu'une addition, ou qu'une multiplication, etc. Le séquenceur se résume alors à un simple circuit combinatoire. La durée d'un cycle d'horloge est calée sur l'instruction la plus lente, diminuant fortement les performances.

Mais sur la majorité des processeurs, les instructions s’exécutent en plusieurs micro-opérations. Pour enchaîner les micro-opérations, le séquenceur doit savoir à quelle micro-opération il en est, et mémoriser cette information dans une mémoire interne. En conséquence, ces séquenceurs câblés sont des circuits séquentiels. Ces séquenceurs doivent éviter de changer d'instruction à chaque cycle : le processeur doit autoriser ou interdire les modifications du program counter tant qu'il est en train de traiter une instruction.

Commande de la mise à jour du program counter.

Les séquenceurs microcodés

Pour limiter la complexité du séquenceur, on peut ruser afin de réduire la complexité du circuit. Au lieu de déterminer à l’exécution la suite de micro-opérations à exécuter, on va la pré-calculer dans une mémoire ROM (pour chaque instruction). Cela donne des séquenceurs microcodés. Un séquenceur microcodé contient donc une mémoire ROM, le control store. Celui-ci stocke, pour chaque instruction microcodée, la suite de micro-opérations équivalente. Le contenu du control store s'appelle le microcode. Parfois, le control store est une EEPROM , ce qui permet de modifier le microcode pour corriger des bugs ou ajouter des instructions.

Pour retrouver la suite de micro-opérations correspondante, le séquenceur considère l'opcode de l'instruction microcodée comme une adresse : le control store est conçu pour que cette adresse pointe directement sur la suite de micro-opérations correspondante. La micro-opération est parfois recopiée dans un registre, le registre de micro-opération, qui est aux micro-opérations ce que le registre d'instruction est aux instructions machine : il sert à stocker une micro-opération pour que le séquenceur puisse décoder celle-ci.

Control store.

Les microcodes horizontal et vertical

Il existe plusieurs sous-types de séquenceurs microcodés, qui se distinguent par la façon dont sont stockées les micro-opérations.

Avec le microcode horizontal, chaque instruction du microcode encode directement les signaux de commande à envoyer aux unités de calcul.

Avec un microcode vertical, il faut traduire les micro-opérations en signaux de commande à l'aide d'un séquenceur câblé. Un séquenceur microcodé utilisant un microcode vertical est divisé en deux parties : un microséquenceur, et une unité de décodage câblée pour décoder les micro-opérations en signaux de commandes. Son avantage est le faible nombre de bits utilisé pour chaque micro-opération : il n'est pas rare que les instructions d'un microcode horizontal fassent plus d'une centaine de bits !

L’enchaînement des micro-instructions

Dans tous les cas, le processeur doit trouver un moyen de dérouler les micro-instructions les unes après les autres, ce qui est la même chose qu'avec des instructions machines. Le micro-code est donc couplé à un circuit qui de l’exécution des micro-opérations les unes après les autres, dans l'ordre. Ce circuit est l'équivalent du circuit de chargement, mais pour les micro-opérations. Un séquenceur microcodé peut même gérer des micro-instructions de branchement, qui précisent la prochaine micro-instruction à exécuter : on peut faire des boucles de micro-opérations, par exemple.

Dans la majorité des cas, le séquenceur contient un équivalent du program counter pour le microcode : le registre d’adresse de micro-opération, couplé à un microcompteur ordinal.

Microcode avec un microséquenceur.

On peut modifier ce microcompteur ordinal de façon à permettre les branchements entre micro-opérations, d'une manière identique à celle vue pour l'unité de chargement.

Branchements avec microcode horizontal avec microséquenceur.

Dans des cas beaucoup plus rares, chaque micro-instruction contient l'adresse de la micro-instruction suivante.

Microcode sans microséquenceur.

Pour gérer les micro-branchements, il faut rajouter la destination d'un éventuel branchement. Cette adresse est rajoutée pour toutes les instructions, vu que toutes les micro-opérations ont la même taille. Elle n'est simplement pas prise en compte si la micro-opération n'est pas un micro-branchement.

Branchements avec microcode horizontal sans microséquenceur.

Les séquenceurs hybrides

Les séquenceurs hybrides sont un compromis entre séquenceurs câblés et microcodés : une partie des instructions est décodée par une partie câblée, et l'autre par une partie microcodée. Cela évite de câbler une partie du séquenceur qui prendrait beaucoup de portes pour décoder des instructions complexes, généralement rarement utilisées, tout en gardant un décodage rapide pour les instructions simples, souvent utilisées.

Cet article est issu de Wikibooks. Le texte est sous licence Creative Commons - Attribution - Partage dans les Mêmes. Des conditions supplémentaires peuvent s'appliquer aux fichiers multimédias.