Il est temps de mettre en œuvre quelques programmes en langage machine S3 afin de bénéficier de tous les développements qui vous ont amené ici. La programmation d’un processeur en langage machine demande une bonne compréhension de son architecture. C’est vous qui avez créé ce processeur S3. Vous en connaissez tous les rouages. Il vous reste à associer une suite d’instructions supportées par le processeur S3 pour en faire un programme exécutable.
Votre processeur S3 est réalisé à 95%. Il vous reste à placer une mémoire de données, ce que vous ferez dans la dernière leçon. Il est temps de mettre en œuvre quelques programmes en langage machine S3 afin de bénéficier de tous les développements qui vous ont amené ici. La programmation d’un processeur en langage machine demande une bonne compréhension de son architecture. C’est vous qui avez créé ce processeur S3. Vous en connaissez tous les rouages. Il vous reste à associer une suite d’instructions supportées par le processeur S3 pour en faire un programme exécutable.
Eléments de programmation. Pour exécuter un programme S3 sur la carte ou le simuler sous ISE vous devez :
Par construction chaque phase de chargement d’une instruction déclenche l’incrémentation du CO afin de le faire pointer vers la prochaine instruction à exécuter, c’est à dire la suivante dans le modèle Von Neumann. La rupture de séquence est obtenue seulement par le chargement explicite d’une autre adresse dans le CO. Pour cela vous disposez de 6 instructions dans le processeur S3.
Avant tout il faut comprendre le fonctionnement pipeline du processeur. Lorsque l’instruction qui modifie la valeur du CO s’exécute, le pipeline a déjà chargé l’instruction suivante et commence à la décoder. La prise en compte du déroutement du programme ne sera effective qu’avec un retard de un cycle donc d’une instruction. On parle de branchement retardé.
Dans cet exemple l’instruction NEXT sera toujours exécutée, le saut étant effective au cycle suivant.
Je vous propose de tester cette caractéristique sur votre carte et par simulation. Il suffit de tester ce programme.
La simulation avec affichage des q(15:0) des registres CO, RI et R7seg vous donnera ceci. Vous observez la prise en compte effective du MVI 02 R7seg avant la rupture de séquence. L’exécution affichera x0002 sur l’afficheur et non pas x0001. La valeur X0003 ne sera jamais affichée.
Figure 125 Simulation branchement retardé
Ce n’est pas toujours possible de trouver une dernière instruction à placer après la mise à jour du CO. Au pire vous pourrez toujours placer un NOP. Vous aurez dans ce cas un cycle de perdu lors du branchement au pire des cas.
Les instructions de transfert de registres conditionnées ne testent que la valeur du registre Rdest égale ou non à x0000.
Les booléens sont une codification de l'information, en général définie pour le langage que vous utilisez. Pour le processeur S3, si vous décidez que VRAI = x0000 et FAUX = xFFFF et les autres valeurs restant indéfinies, les opérateurs de votre ALU vous permettent directement de réaliser des AND, OR ou INV. Les résultats produits dans Rdest servent alors à déclencher ou non des branchements.
Pour un langage comme le shell, on peut décider de choisir la codification suivante où les valeurs booléennes sont : VRAI= x0000 et FAUX toutes les autres valeurs (En C c'est l'inverse!). Dans ce cas voici les codes pour tester les prédicats suivants : A, NOT A, A and B, A NAND B et un code qui réalise B := NOT A. Les formules de De Morgan seront bien utiles…[1] Le code if A=B est lui utile pour tous les types de données. On considère dans ces exemples que l’adresse de branchement est rangée dans R3, A dans R1 et B dans R2. Vous pourriez faire la même chose avec MIZ, MINZ et un adressage immédiat.
Je vous propose d’écrire le programme suivant manipulant des booléens avec cette codification et un OR.
Entrer R1
Entrer R2
si (R1 ou R2) alors
Rdest := x0001
sinon
Rdest := x0002
fsi
Le programme affiche la valeur x0001 si l’une au moins des deux valeurs saisies est égale à x00 et x0002 sinon. Appliquons la formule de De Morgan A OR B est égal à NAND ( Not A , Not B ). Vous pouvez analyser et tester le programme suivant (pour la simulation remplacer les PAUSE par des NOP).
Le branchement relatif
Les instructions de rupture de séquence forcent la valeur du CO à une nouvelle adresse. Parfois il est souhaitable d’effectuer un saut relatif à la valeur du CO. Par exemple on peut vouloir reculer de 3 instructions ou encore sauter au-dessus des 5 suivantes. Il faut dans ce cas recalculer la valeur du CO par rapport à sa valeur actuelle. Cette technique de rupture de séquence vous évitera d’avoir à calculer et recalculer les adresses de branchement chaque fois que la portion de code change de place dans la mémoire d’instructions.
Pour simuler ce comportement il faut inclure les instructions qui recalculeront la valeur du CO. Cette façon de procédé a bien sûr un coût par rapport à l’adressage direct. Il faut bien se souvenir que le CO pointe vers l’instruction suivante. Voici un code générique que vous pourrez réutiliser par la suite.
Voici un code avec retour en arrière.
:
La simulation avec les registres CO, RI et R7seg que vous devriez obtenir.
Figure 126 La boucle infinie avec branchement relatif
On peut faire la même chose pour un saut en avant.
Figure 127 Saut en avant
La simulation pour ce programme vous permet d’observer le saut en avant sur l’adresse x0008. R7seg ne reçoit pas la valeur x04.
Je vous propose de construire un programme qui utilise un IF THEN ELSE. Vous allez concevoir un programme qui affiche la liste
3 4 7 8 11 12 15 … ou 3 4 7 8 B C F 10 … en hexadécimal
N := 1
Loop :
IF N pair THEN
dest := 2N
ElSE
dest := 2N + 1
ENDIF
Afficher dest
Pause
N := N+ 1
GOTO Loop
Voici le programme assembleur qui pourrait être produit par un compilateur depuis la description avec un IF THEN ELSE. Ici le branchement retardé a bien été utilisé puisque des instructions ont trouvé leur place derrière la rupture de séquence. Ce code est moins efficace que celui que vous avez écrit en séance de TD, mais il pourrait être produit automatiquement à partir d'un langage de plus haut niveau. Testez les deux programmes!!!
Vous pouvez exécuter le programme sur la carte. Vous pouvez aussi le simuler sur Isim afin de suivre l’évolution du CO des registres Rsrc1, Rsrc2, Rdest et R1. Pour la simulation il est préférable de remplacer le PAUSE par un NOP, ça vous évitera d’attendre la pression du bouton btn0.
Vous allez tester ce programme qui affiche le Iième élément de la suite de fibonacci. I est un nombre compris entre 0 et 255 saisi sur les switches, néanmoins sur 16 bits on n'ira pas très loin. Le programme dans un pseudo langage serait :
Loop:
N := 0
R1 := 0
R2 : = 1
-- Positionner les switches
Pause
Tantque N<> Rsw faire
N := N + 1
Dest := R1 + R2
R1 := R2
R2 := Dest
FTQ
Afficher R1
Goto loop
Tester le programme sur la carte. C’est un bon test pour votre processeur S3 ! Testez aussi le programme obtenu en TD.
Ensuite pour le simuler il faudrait mieux remplacer le PAUSE par un NOP et n’oubliez pas de positionner une valeur initiale sur les switches dans toplevel_tb.
A vous de jouer
Question 1 :
Pour la suite 3 4 7 8 11 12 15, on peut remarquer que l'on ajoute alternativement +1 et +3. Ecrivez ce code avec une boucle qui produit un élément de la série à la fois
Question 2
Produisez un autre code qui déroule la boucle et produit deux éléments à chaque itération! Ce code a été proposé en TD.
[1] Attention votre ALU implémente un AND sur 16 bits : x0010 and x1101 vous produira x0000 alors que les valeurs "booléennes" sont indéfinies. Vous pouvez utiliser ce AND tel que seulement avec la codification choisie.