Voici les réponses aux différentes questions
Voici les réponses aux différentes questions
La première réponse est très détaillée. Les autre réponses seront plus succinctes.
Pour effectuer un calcul, l’automate doit disposer de trois informations :
Plus que ça, il doit en disposer en même temps. Mais elles sont stockées en RAM, et ne peuvent être lues que l’une après l’autre. Il faudra donc prévoir un moyen de stockage de ces trois informations à l’intérieur du processeur pour pouvoir effectuer le calcul.
Vu l’organisation de la mémoire, il semble logique de lire ces trois informations de la façon la plus simple possible, c’est à dire :
ce qui correspond à un parcours linéaire de la mémoire.
De plus, le stockage du résultat s’effectue dans la RAM à l’adresse suivant celle de l’opérande 2. On peut donc doter l’automate d’un compteur qu’on appellera compteur d’adresse ou PC (Program Counter), qui donnera l’adresse de la RAM à laquelle on est en train d’accéder (que ce soit en lecture ou en écriture). Ce compteur sera incrémenté à chaque coup d’horloge, et pilotera directement le bus d’adresse de la RAM.
Vu ce qui vient d’être dit, l’automate a un fonctionnement linéaire - l’ordre des actions effectuées est toujours le même :
On peut donc le concevoir comme un automate à quatre états, dont le fonctionnement est circulaire : état 1 → état 2 → état 3 → état 4 → état 1 → état 2 → …
Remarque : on peut se dire que ce n’est pas la peine de stocker cet opérande, car on dispose dès à présent de toutes les données pour effectuer le calcul : l’instruction dans un registre, l’opérande dans un autre registre, et le deuxième opérande sur le bus Q[7:0]. Mais il faudrait alors stocker le résultat dans un registre 8 bits, car on ne fait son stockage en RAM qu’au prochain cycle…Alors qu’ici, le calcul et le stockage seront faits en bloc au prochain cycle (donc pas besoin de stocker le résultat dans un registre). Au total, dans les deux approches, le nombre de registres est le même, et ce ne sont que des considérations de chemin critique qui permettront de déterminer la meilleure des deux méthodes…
On obtient donc l’architecture suivante pour notre processeur :
L'automate (CTRL) est présenté en figure 1.4 et son graphe d’états en figure 1.5.

L'automate a quatre états, parcourus de façon linéaire, sans condition sur les transitions.
Il dispose de 4 sorties, chacune d’entre elles à l’état haut dans un seul état de l'automate. Un codage "one-hot", consistant à matérialiser chaque état par un registre est donc très approprié.
L’implémentation en registre a déjà été vue (registres les uns à la suite des autres), et ne sera pas détaillée ici. Les sorties des registres donnent directement les sorties de l'automate…

Plusieurs possibilités, leur nombre est limité seulement par votre imagination. Voici quelques exemples :
Chaque opération ne nécessite plus qu’un seul opérande :
Le contenu de la RAM se présentera donc maintenant ainsi :
| adresse | type du mot stocké | exemple | effet |
| 0 | instruction | load | |
| 1 | donnée | 3 | l’accumulateur contient maintenant 3 |
| 2 | instruction | + | |
| 3 | donnée | 4 | l’accumulateur contient maintenant 7 |
| 4 | instruction | - | |
| 5 | donnée | 1 | l’accumulateur contient maintenant 6 |
| 6 | instruction | store | |
| 7 | donnée | X | après l’exécution du programme cet emplacement en RAM contiendra “6” |
On remarque donc qu’une adresse sur deux contient une instruction, une sur deux contient une donnée (soit opérande, soit stockage du contenu de l’accumulateur)…
Comme précédemment, les adresses de la RAM sont parcourues de façon linéaire. On garde donc le compteur d’adresse incrémenté à chaque cycle d’horloge.
Pour effectuer les calculs, le processeur n’a plus besoin de connaître que deux informations : l’instruction et l’opérande. On garde donc le registre d’instruction (8 bits) qui stocke l’instruction à effectuer pendant qu’on va chercher l’opérande en RAM.
Par contre, auparavant on parcourait 4 emplacements en RAM pour chaque instructions, d’où une machine à états à 4 cycles. Maintenant on ne parcourt plus que 2 emplacements en RAM, donc une machine à état à 2 cycles devrait convenir…
A chaque instruction, le processeur effectuera ceci :
Pour une opération "normale" :
Pour un "load" :
Pour un "store" :
Chaque instruction est donc traitée de façon très similaire :
Lors du second cycle, l’accumulateur peut subir trois traitements différents :
En entrée de l’accumulateur on mettra donc un multiplexeur qui présentera soit le résultat de l’opération en cours (si on exécute une opération standard), soit le contenu de la RAM (si on exécute un load). De plus, dans ces deux cas, le signal enable de l’accumulateur sera mis à l’état haut (pour autoriser sa modification) dans l’état 2 (quand on accède à la partie donnée de la RAM) Dans le cas d’un store, on laisse l’enable de l’accumulateur à l’état bas pour ne pas le modifier.
En d’autre termes, le signal de validation du chargement de l’accumulateur a pour équation en pseudo-langage :
LOAD_ACC = (Instruction <> STORE) ET (Etat = état 2)
Le pilotage du multiplexeur en entrée de l’accumulateur aura pour équation quelque chose du genre :
Ce qui se simplifie en :
La sortie de l’accumulateur est branchée simultanément
Enfin la génération du signal d’écriture en RAM est simple : il est mis à l’état haut quand l’instruction est un STORE, et qu’on est dans l’état 2. Le contenu de l’accumulateur est présenté sur l’entrée de la RAM (cf. ci dessus), l’adresse courante est sur le bus d’adresse de la RAM, la RAM est donc mise à jour avec la bonne valeur…
Nous disposons donc les éléments suivants :
Remarque : Les signaux générés par l'automate ne dépendent pas seulement de l’état courant de l'automate, mais aussi de la nature de l’instruction à exécuter. On nomme ce genre d'automate "machine de Mealy")
L’architecture globale est celle représentée sur la figure 1.6, et son graphe d’états en figure 1.7


avec :
Pour une opération :
Pour deux opérations chaînées :
Pour trois opérations chaînées :
Bref, pour n opérations :
On a donc tout intérêt à enchaîner les calculs. Ce qui est très souvent le cas en pratique…
L’automate doit maintenant pour chaque instruction
On a donc une machine qui possède un état de plus (celui où on va lire en RAM l’opérande proprement dit).
Maintenant, on n’accède plus à la RAM de façon linéaire. Dans l’exemple de programme donné, les adresses présentées à la RAM seront celles-ci :
Les adresses de code sont globalement linéaires (0, 1, 2, 3, …), celles des données ne le sont pas (elles sont arbitraires). Il faut donc présenter sur le bus d’adresse RAM
donc : multiplexeur…
De plus, le compteur d’adresse doit être piloté par un signal INCR_PC : il n’est incrémenté que si INCR_PC est à l’état haut.
Le registre d’adresse est chargé au cycle numéro 2. Son contenu n’est utile qu’au cycle numéro 3. Il n’est donc pas nécessaire de le piloter avec un enable…Il peut rester tout le temps actif : son contenu sera indéterminé pendant les cycles 1 et 2, mais ce n’est pas grave, il n’est pas utilisé pendant ces cycles là…
L’architecture globale est donc celle représentée sur la figure 1.8, et son graphe d’états en figure 1.9.


C’est, ici encore, une machine de Mealy, et ses équations sont :
La génération de C et Z est combinatoire et peut être effectuée par l’ALU.
Il suffit juste de rajouter deux registres 1 bits pour stocker ces deux signaux, pilotés par le même enable que l’accumulateur (LOAD_ACC, qu’on appellera maintenant LOAD_AZC). On considérera donc que Z et C font partie de l’accumulateur (qui devient donc un registre sur 10 bits : 8 de donnée, 1 pour Z, un pour C).
Remarque : le fonctionnement de Z et C ici n’est pas tout à fait standard !..
Il suffit de faire entrer C sur la retenue entrante de l’addition ou de la soustraction…
Pour implémenter les sauts, il suffit de se donner la possibilité de remplacer le contenu de PC par la valeur lue en RAM.
PC devient donc un peu plus complexe. C’est globalement un compteur, mais :
Ceci peut être implémenté comme indiqué en la figure 1.10.

Pour simplifier les schémas, nous nommerons PC l'ensemble du bloc de la figure 1.10.
Il faut maintenant générer le signal LOAD_PC. Ce signal sera aussi généré par la machine à états CTRL. Le PC doit être remplacé lorsqu’on exécute un saut, et que le condition du saut est vérifiée. La nouvelle valeur est présente sur le bus de sortie de la RAM pendant le cycle 2.
On aura donc une équation du style :
L’architecture globale est donc celle représentée sur la figure 1.11, avec un automate CTRL à peine modifié (même graphe d’état) représenté figure 1.12.


L’instruction NOP ne fait rien. Elle n’a pas besoin d’opérande, et pourrait donc être stockée sur un seul octet (au lieu de deux pour les autres).
Mais cela compliquerait la gestion de l'automate pour générer les signaux LOAD_PC et INCR_PC. De plus, cela pourrait poser d’autres problèmes (cf. les optimisations).
On peut donc accepter de perdre un octet de mémoire, et ne rien changer à l’organisation de la mémoire. L’instruction NOP sera accompagnée d’un opérande qui ne servira a rien... Une instruction sera toujours exécutée en trois cycles. La seule modification de la machine à état sera l’équation suivante :
LOAD_ACC = (I[7:0] <> (STORE ou saut ou NOP)) ET (Etat = Ex)
Ces opérations sont combinatoires et seront donc implémentées dans l’ALU.
Remarque : comme le NOP, elles ne nécessitent pas d’opérande. De même, pour garder une cohérence (nous optimiserons ça plus tard), on garde un codage des instructions sur deux octets. Pour ROR et ROL, le deuxième octet n’a pas de signification...
On ajoute un registre 1 bit, piloté par un signal d’enable appelé LOAD_BZ.
LOAD_BZ sera généré par la machine à état, selon l’équation suivante : LOAD_BZ = (I[7:0] == OUT) et (état = EX)…
L’architecture globale est donc celle représentée sur la figure 1.13, avecun automate CTRL représenté figure 1.14.


Les équation sont laissées en exercice au lecteur !..
Remarque : le signal SEL_ACC ne sort pas de CTRL sur le schéma : il peut être inclus, avec le multiplexeur qu’il pilote, dans l’ALU...
Les réponses sont à trouver par le lecteur...