Leçon 8 : Instruction MOV

Vous allez mettre en place la première instruction de votre processeur S3. Seuls les accès aux registres en entrée et en sortie seront sollicités. Vous allez devoir mettre en place votre FSM qui assure non seulement le chargement de votre instruction à exécuter, mais aussi le déclenchement des commandes qui permettent la réalisation de cette instruction pour tous les transferts de registres possibles. La construction de votre FSM telle que nous l’avons introduite au TP5, assure un fonctionnement pipe-line en deux étages. Vous l’avez sans doute remarqué dans la question 2 de la leçon précédente. Le premier étage décode la prochaine instruction à exécuter, alors que le second étage exécute l’instruction en cours d’exécution. Ce pipe-line permet d’avoir deux instructions en traitement en même temps dans deux états d’avancement différents.

Le transfert de données d’un registre vers un autre provoque une duplication de l’information dans le registre destination. Pour votre processeur S3 cette instruction est indispensable. Le fonctionnement de S3 est si simple qu’il faut toujours générer les instructions de transfert de registre avant de pouvoir déclencher un calcul ou un accès mémoire. Le transfert de registres tel qu’il a été testé dans la leçon précédente peut être généralisé pour tous les registres. Il faut alors proposer une instruction qui déclenche un de ces transferts : c’est l’instruction MOV qui va le réaliser !

Connaissances requises

Registre, bus, automates, mode d’adressage

Objectif

Vous allez mettre en place la première instruction de votre processeur S3. Seuls les accès aux registres en entrée et en sortie seront sollicités. Vous allez devoir mettre en place votre FSM qui assure non seulement le chargement de votre instruction à exécuter, mais aussi le déclenchement des commandes qui permettent la réalisation de cette instruction pour tous les transferts de registres possibles. La construction de votre FSM telle que nous l’avons introduite au TP5, assure un fonctionnement pipe-line en deux étages. Vous l’avez sans doute remarqué dans la question 2 de la leçon précédente. Le premier étage décode la prochaine instruction à exécuter, alors que le second étage exécute l’instruction en cours d’exécution. Ce pipe-line permet d’avoir deux instructions en traitement en même temps dans deux états d’avancement différents.

Le projet

Après avoir choisi une codification de l’instruction MOV, vous allez décoder l’instruction dans votre FSM. Si cette instruction est un MOV, vous devez alors ouvrir le bon registre source sur le bus de données ainsi que le bon registre destination en écriture depuis ce même bus. Seuls certains registres acceptent des écritures depuis le bus. Par contre tous les registres peuvent s’ouvrir vers le bus, si aucun ne s’ouvre, la constante x0000 est alors véhiculée sur le bus et éventuellement recopiée dans le registre destination. Cela équivaut à un reset du registre.

Les connexions au bus

Ouvrez le TP8 que vous avez copié à la fin de la leçon précédente. Pour commencer, sélectionnez tous les GND que vous aviez placés sur les entrées des connecteur16 et supprimez-les. Sur chaque entrée ainsi libérée, placez un fil et nommez les dans l’ordre du haut vers le bas et sans erreur (Nom_du_registre to Bus) : R12B, R22B, R32B, R42B, R52B, Rled2B, Rsw2B, R7seg2B, Rsrc12B, Rsrc22B, Rdest2B, Ram2B, Rdm2B, CO2B. RI2B est déjà créé. Sur les registres, il faut ajoutez un fil sur les CE non encore connectés. Voici les noms à placer sur ces fils et dans le même ordre : B2R1, B2R2, B2R3, B2R4, B2R5, B2Rled, Rswload, B2Rsrc1, B2Rsrc2, Rdestload, B2Ram, Rdmload. Les CE de CO RI et R7seg sont déjà connectés. Voici une partie des connexions que vous devriez obtenir.

Figure 97 Les contrôles bus vers registre et registre vers bus

L’instruction MOV

Les instructions du processeur S3 sont donc codées sur 16 bits. Les 4 premiers bits seront utilisés pour coder le code opération. Il reste 3 champs de 4 bits pour les opérandes ou également pour spécialiser un code opération.

L’instruction MOV aura comme code opération b0000. Le second champ n’est pas utilisé, le troisième champ code l’adresse du registre source, le quatrième champ code l’adresse du registre destination. Le codage des registres se fera dans l’ordre de placement sur le schéma :

Par exemple l’instruction b0000_0000_0011_1100 soit x003C correspond à MOV R3 Ram. Les registres Rsw, RI et Rdest ne peuvent être la destination d’un MOV. Ils ne sont pas connectés au bus de données en entrée. Pour le registre Rsw, placez sur le port CE un Vcc (=1) pour forcer le chargement à chaque top d’horloge. Ce registre procure une copie des switches à chaque top d’horloge.

C’est votre FSM qui va décoder la prochaine instruction à exécuter. Par conséquent la prochaine instruction à exécuter devient une entrée de la FSM. En sortie la FSM doit produire le numéro du registre à transférer sur le bus et le numéro du registre à charger depuis le bus. Le numéro b0000 permet de ne rien déclencher, c’est pour cela que le processeur S3 ne possède que 15 registres. Pour passer du numéro produit par la FSM aux fils de sélection que vous venez d’ajouter, vous utiliserez deux décodeurs 4 x 16 qui activent le fil dont le numéro est placé en entrée : b0101 activerait le fil 5 soit R52B en source ou B2R5 en destination.

Modification de votre FSM

Pour commencer il faut modifier les ports de la FSM. Ouvrez le fichier fsm.vhd. Vous allez d’abord faire un nettoyage.

    1. Supprimez dans entity les ports out B2CO, B2R7seg et RI2B, ne gardez que le port clk et les ports COinc et RIload.
    2. Supprimez les 3 signaux internes B2CO_i, B2R7seg_i et RI2B_i.
    3. Supprimez les valeurs du type State_type ne gardez que chargement.
    4. Dans Next_output, supprimez les initialisations des 2 signaux internes B2R7seg_i et RI2B_i ainsi que le contenue du case.
    5. Dans Next_node supprimez le contenu du case.
    6. Dans Synchro supprimez la mise à jour des 2 ports de sortie B2R7seg et RI2B.

Vous êtes prêt pour la construction de la nouvelle FSM. Commencez par ajouter les ports dans l’entity. Il faut un port en entrée pour recevoir l’instruction et deux ports de sortie pour la sélection des registres en source et destination du MOV. Je vous propose de les nommer instr(15:0), source(3:0) et dest(3:0).

Déclarez les 2 signaux internes pour les 2 nouveaux ports de sortie, source et dest.

Vous ne devez avoir qu’un seul élément dans la déclaration de type énumératif. Il reste chargement. Dans le process Next_output, vous devez initialisez vos deux signaux internes source_i et dest_i à b0000. Ensuite il ne reste plus qu’un seul état dans votre FSM. Il faut déclencher l‘incrément de CO et le rangement de l’instruction courante dans RI. De plus si l’instruction est un MOV il faut ranger le numéro de la source obtenu depuis le premier opérande de l’instruction et le numéro de la destination depuis le second opérande de l’instruction. Le transfert de registre sera effectif en même temps que la mémorisation de l’incrément du CO et le rangement de l’instruction dans RI. Pour l’instant le rangement dans RI ne sert pas à grand-chose et vous pourriez ne pas le charger. Comme le signal d’entrée instr est dans un prédicat de if il faut l’ajouter dans la liste de sensibilité.

Concernant le process Next_node, il suffit de mettre à jour le case. Ici l’automate boucle sur le seul et unique nœud chargement. Vous pourriez purement et simplement supprimer le case.. Gardez-le, vous vous en servirez par la suite…

Pour le process Synchro, il suffit de mettre à jour les nouveaux ports depuis les nouveaux signaux internes.

Vous êtes prêt pour générer le symbole associé à cette FSM. Une fois généré, il faut ensuite venir le mettre à jour dans S3, il remplacera le symbole créé lors du TP précèdent. ISE devrait vous le demander d’office. Vérifiez que clk, COinc et RIload sont toujours connectés. Connectez l’entrée instr(15:0) au bus sortant de insmem sur le port spo(15:0). Ajoutez deux bus horizontaux sur les ports source et dest et nommez les source(3:0) et dest(3:0). Il faut maintenant décoder les numéros véhiculés par sources et dest afin d’activer le fil correspondant qui est connecté soit aux connect des connecteur16 et soit aux CE des registres. Bien sûr il faut respecter la codification choisie précédemment. ISE propose un décodeur D4_16E qui va vous réaliser ce décodage.

Placer un premier D4_16E sous la FSM après l’avoir fait pivoter de 90°. Ajouter 16 petits fils sur les sorties. A ce moment faites un copier-coller pour en créer un second D4_16E que vous placerez à sa droite. Avec 4 Bus Tap vous devez connecter dest(3:0) sur les 4 entrées A3 A2 A1 A0 en respectant les poids des fils. Faites la même chose pour le second avec source(3:0).

Il ne vous reste plus qu’à nommer les sorties de vos deux D4_16E. Aucune erreur n’est permise. Aidez-vous du schéma suivant pour suivre l’ordre de nos registres R12B, R22B … sur les sorties 1, 2 … du décodeur source, B2R1, B2R2 …. sur les sorties 1, 2 … du décodeur dest. Pour terminer placez un Vcc sur les deux entrées E des décodeurs afin de les rendre actifs.

Figure 98 FSM connectée au RI et ses deux décodeurs

Figure 99 Zoom sur le décodeur destination

Figure 100 Zoom sur le décodeur source

Votre processeur S3 est prêt pour exécuter son premier programme.

Le premier programme va récupérer la valeur saisie sur les switches, celle-ci est automatiquement copiée dans le registre Rsw. Pour tester quelques transferts de registres vous allez la recopier dans le registre R3, puis R3 est recopié dans R4 enfin R4 est recopié dans R7seg pour affichage. Si la source d’un MOV n’est pas sélectionnée (code b0000) de par notre hypothèse sur les connecteurs, la valeur véhiculée sur le bus de donnée est x0000. MOV 0 R5 copie la valeur x0000 dans le registre R5.

Il suffit de mettre ce programme dans votre mémoire d’instruction insmem. Pour cela vous devez éditer le fichier prog.coe et copier les 4 premières instructions hexa suivantes. Il faudra toujours placer une première instruction b0000 0000 0000 0000 en début de programme. La raison de cette contrainte est liée à la simplicité du processeur S3 : il n’y a pas de signal de reset qui initialise le processeur. Par la suite on appellera cette instruction NOP : elle ne fait aucun transfert et ne déclenche aucune opération. Vous pouvez aussi laisser une instruction autre que MOV à la fin du programme. Normalement votre case ne la prendra pas en compte.

Une fois le fichier mis à jour et sauvé, il faut ouvrir l’IP_Core insmem et venir mettre à jour le fichier d’initialisation sur le troisième écran de saisie. Faites un show pour être certain de rentrer le bon fichier. Enfin il faut regénérer le composant par Generate. Une fois cette tâche ISE terminée, venez mettre à jour le schéma S3 par un clic sur le schéma, des symboles ont dû changer, recréez le composant S3 et mettez-le à jour dans toplevel.

Vous pouvez simuler toplevel en utilisant toplevel_tb tel que. Choisissez les ports q(15:0) des registres que vous voulez observer (RI, CO, R3, R4, R7seg dans l’ordre sur la fenêtre de simulation). La valeur x12 est toujours initialisée pour les switches dans toplevel_tb.

Figure 101 Simulation de votre premier programme

Lancez la génération finale et testez le programme sur la carte. Faites une copie du projet et nommez le TP9.

Un assembleur en deux minutes

Effectivement copier des codes hexadécimaux dans un fichier, c’est fastidieux et source d’erreur. Le jeu d’instructions du processeur S3 est assez simple pour créer un assembleur lui aussi très simple avec la commande sed. Cette commande linux est aussi disponible sous windows. Il vous suffit d’installer la dernière version. Voici celle que j’ai utilisée lors de la rédaction de ces TPs.

http://sourceforge.net/projects/gnuwin32/files/sed/4.2.1/sed-4.2.1-setup.exe/download

Ensuite il vous suffit de créer un fichier S3asm.bat qui contient toutes vos commandes sed. Les S/xxx/yyy/ produisent des substitutions de toutes les chaines xxx par une chaine yyy.

Dans une fenêtre dos lancez alors la commande sur un fichier texte contenant le code assembleur de votre programme. Modifiez votre path si besoin est.

commande SED

sed -f S3asm.bat mon_fichier.S3 >mon_fichier.coe

Le format de mon_fichier.S3 ne doit utiliser que les mots clefs de votre fichier S3asm.bat, ou des hexadécimaux tout cela entre un begin et end. Vous pouvez remarquer que la première instruction x0000 est générée automatiquement par la traduction du begin. Inutile de le réécrire dans votre code assembleur. Tous les mots clefs sont en majuscule, mais la première commande de S3asm.bat convertit toutes les minuscules en majuscules, les deux sont donc équivalents. La seconde commande sed supprime les lignes commençant par --, ce sont des lignes commentaire.Voici le code mon_fichier.s3 de votre premier programme S3.

A vous de jouer

Question 1 : Modifier le programme pour afficher également la valeur sur les Led (Rled est le registre 6).

Question 2 : Pourquoi le programme tourne à l’infini et non pas une seule fois? Que fait votre CO ???

Réponses