Leçon 7 : Phase de chargement

Dans ce TP, vous allez compléter le développement de votre processeur S3 en intégrant la phase de chargement. Une première FSM vous permettra d’afficher une instruction d’un programme stocké en mémoire.

L’exécution d’un programme repose sur une boucle infinie qui exécute une séquence d’instructions l’une après l’autre. Pour chaque instruction il faut pouvoir la récupérer dans la mémoire de programme, la décoder puis l’exécuter. La phase de chargement est commune à toutes les instructions elle met en œuvre deux registres particuliers CO et RI.

Connaissances requises

Modèles de Von Neumann, Additionneur, registres, FSM, mémoire ROM.

Objectifs

Dans ce TP, vous allez compléter le développement de votre processeur S3 en intégrant la phase de chargement. Une première FSM vous permettra d’afficher une instruction d’un programme stocké en mémoire.

Le projet

Dans la machine Von Neumann, je vous rappelle que les instructions et les données sont rangées dans la même mémoire. Ici le processeur S3 propose en fait une architecture de type Harvard. Nous allons ranger les instructions et les données dans deux mémoires distinctes. La phase de chargement récupère en mémoire de programme la prochaine instruction à décoder et à exécuter. Cela se fera via un accès à cette mémoire à l’adresse contenue dans le registre CO (Compteur Ordinal). L’instruction est alors rangée dans le registre RI (Registre d’Instruction) et peut être décodée par l’unité de contrôle et commande (votre FSM). Le CO est par la même occasion incrémenté afin de pointer toujours sur la prochaine instruction à exécuter. Lors d’une phase de branchement (JUMP) le CO sera mis à jour directement et éventuellement après un calcul interne sur l’ALU, vous verrez cela dans les leçons suivantes. En conséquence, il nous faut :

  • Une mémoire d’instruction : on choisira une ROM qui sera initialisée case par case avec les instructions machines à exécuter.
  • Un incrémenteur de CO.
  • Un sélecteur d’entrée pour le CO qui range soit la valeur de CO+1, soit la valeur véhiculée sur le bus interne du processeur quand il s’agira d’un branchement.

Le projet TP7 a été créé à la fin de la leçon précédente par une copie de projet TP6. Avant toute chose sélectionnez dans le schéma S3 le fil qui relie Vcc aux CE de Rled, Rsw et R7seg ainsi qu’au connect du CRsw puis supprimez-le ! Vous pouvez aussi supprimer le symbole Vcc qui lui été connecté!

Après chaque modification de S3, ne pas oublier de recréer le

symbole S3 et de mettre à jour ce symbole dans toplevel !!!

C’est vrai pour tout Schematic

L’incrémenteur

Vous allez d’abord créer l’incrémenteur. Je vous propose de créer une nouvelle source schématique inc. Une fois celle-ci créée, une instance du symbole ADD16 de la bibliothèque Arithmetic va vous suffire pour réaliser votre inc. Après avoir consulté Symbol Info, complétez le circuit avec une entrée Din(15:0) connectée à A(15:0) et une sortie Dout(15:0) connectée à S(15:0) avec leur I/O Marker respectifs. Pour réaliser Dout = Din + 1 il suffit de placer la retenue à 1 et d’ajouter x0000 à la valeur Din. Placez une constante x0000 de longueur 16 sur l’entrée B(15:0), forcez la retenue CI à 1 par un Vcc. Les autres sorties de ADD16 peuvent rester non connectées. Vous pouvez créer le symbole.

Figure 81 Incrémenteur 16 bits

Rangement dans CO

La valeur du CO peut être produite soit par votre incrémenteur pour passer d’une instruction à la suivante, soit depuis le bus de données lorsque l’on veut forcer la valeur du CO pour un branchement ou rupture de séquence. Vous devez donc placer un multiplexeur 2 entrées une sortie sur les 16 fils. Il n’y a pas de composant de la sorte en bibliothèque. Vous allez créer le votre. Ajoutez une nouvelle source schématique nommée mux2x16. Placez au centre deux bus D0(15:0) et D1(15:0) entre les deux placez un fil S0, enfin placez autour un bus en U nommé O(15:0). Il vous reste à instancier 8 M2_1 de la bibliothèque Mux à droite des trois bus, 8 autres M2_1 en affichage miroir à gauche (copier/coller) en les décalant légèrement vers le haut (sinon les Bus Tap ne pourront se connecter sur le bus). Connectez les bus aux ports correspondants des M2_1 en commençant par les fils x(15) via des Bus Tap. Beaucoup de fils mais ça reste assez rapide à réaliser. Enfin placez les I/O Marker. Vous pouvez ensuite créer le symbole correspondant. Voici le schéma pour vous guider.

Figure 82 Multiplexeur 2x1 pour mots de 16 bits

Il n’était pas possible d’utiliser votre connecteur16 créé pour la leçon précédente car l’hypothèse initiale n’est pas respectée ici. Instanciez un symbole inc et un mux2x16 sur la gauche du registre CO. Pour la clarté du schéma faites un miroir sur inc. Ensuite reliez l’entrée de inc avec la sortie de CO, la sortie de inc avec l’entrée D0 du mux2x16 le bus de données bus_data avec l’entrée D1 du mux2x16. Deux commandes différentes déclencheront le rangement d’une valeur sur le registre CO : une commande range la valeur incrémentée, la seconde range la valeur présente sur le bus. Une et une seule commande peut être active à un instant donné. La première commande B2CO (Bus to CO) pilote mux2x16 : quand elle est active c’est D1 et donc la valeur du bus de données qui passe, sinon c’est D0 et donc la valeur de CO+1. Placez un fil sur le port S0 du mux2x16 et nommez le B2CO. Les deux commandes B2CO et COinc déclenche le chargement du registre CO. Placez un OR avec en entrée B2CO et un fil nommé COinc. La sortie du OR doit être connectée en entrée du CE de ce registre CO. Je vous conseille de nommer vos instances incCO et selectCO afin de faciliter la simulation.

Figure 83 Mise à jour du CO

La mémoire de programme

Vous allez construire une mémoire qui contiendra toutes les instructions de votre programme. Cette mémoire reçoit une adresse depuis CO et renvoie la donnée rangée à cette adresse. Il faudra la charger dans le registre RI. ISE facilite la création d’une telle mémoire. Vous allez créer une ROM par l’ajout d’une nouvelle source dans votre projet. Sélectionnez cette fois lors de la création IP (CORE...), en nommant le symbole insmem.

Figure 84 Création de la mémoire de programme

ISE ouvre alors une fenêtre qui vous permet de créer des composants automatiquement pour des fonctions prédéfinies et paramétrables. Vous allez choisir Basic Elements> Memory Elements> Distributed Memory Generator. Cliquez sur Next et Finish.

Figure 85 Générateur d'IP mémoire

Le processeur S3 manipule des mots de 16 bits autant pour les données que pour les instructions. Vous allez créer une Rom de 256 mots de 16 bits en cliquant sur Generate. 256 sera la taille maximale d’un programme pour vos TPs alors que le CO pourrait adresser une mémoire de 64 K mots. Vous pourriez agrandir cette mémoire pour un autre usage plus tard. Pour l’instant cette ROM ne contient pas d’instruction nous reviendrons par la suite pour initialiser cette ROM depuis un fichier. Le symbole insmem est automatiquement crée par ISE dans une bibliothèque IPcore_dir, vous pouvez donc instancier ce symbole dans votre schéma S3 à gauche du registre RI.

Figure 86 Un ROM de 256 mots de 16 bits

Le composant Insmem possède un bus de 8 fils en entrée (256 emplacements) et 16 fils en sortie (mots de 16 bits). Ce composant est assez simple, il renvoie en sortie le contenue de la case mémoire pour l’adresse positionnée en entrée. Vous allez lui envoyer la valeur du CO pour récupérer la prochaine instruction à exécuter et la ranger dans RI. Pour cela je vous propose de renommer la sortie du registre CO en COBus(15:0), puis via un Bus Tap les 8 bits de poids faible COBus(7:0) sont connectés à l’entrée a(7:0) de insmem . Enfin la sortie spo(15:0) et reliée à l’entrée de RI. Vous pouvez pour la clarté du schéma réduire la taille du symbole insmem. Il suffit de sélectionner le symbole et par un clic droit>Symbol>Edit Symbol, vous avez accès à la représentation graphique du symbole. Réduisez sa hauteur et sauvez les modifications. En revenant dans le schéma S3, ISE vous demandera de mettre à jour le symbole insmem puisqu’il a été modifié. Faites-le. Il vous reste à piloter le chargement du registre RI, pour l’instant ajoutez simplement un fil RIload sur le CE de ce registre.

Figure 87 Connexion mémoire d'instructions

Initialisation de la ROM

Maintenant vous allez ranger quelques mots de 16 bits dans cette ROM. Pour cela vous créez une nouvelle source dans votre projet de type User Document.

Figure 88 Création du programme en binaire

Vous allez initialiser ce fichier prog.coe avec le contenu suivant:

La première commande spécifie le nombre de bits par mot, la seconde les valeurs sur 16 bits en hexadécimal les unes derrière les autres avec un mot par ligne, un point-virgule derrière chaque commande.

Dans le mode design cliquez sur insmem pour ouvrir le gestionnaire d’IP_core. En appuyant sur next deux fois, vous pouvez associer le fichier que vous venez de créer et aussi le visualiser. Après Generate, les quatre premières adresses de cette mémoire sont alors initialisées.

Figure 89 Rangement du programme dans la mémoire de programme

FSM et contrôle

Votre processeur S3 est prêt pour la phase de chargement. Il ne vous reste plus qu’à déclencher les signaux de chargement et incrémentation des registres CO et RI mais aussi le signal de sélection du multiplexeur en amont du CO. Pour cela vous allez utiliser une FSM !

Pour visualiser la fonction de chargement sur la carte, je vous propose d’afficher la première instruction qui se trouve en mémoire insmem à l’adresse x0000. Vous devez donc exécuter une fois la phase de chargement : chargement du registre RI et incrément du registre CO. Ensuite, au top d’horloge suivant, il vous faut transférer le contenu du registre RI vers le registre R7seg pour affichage. Pour réaliser ce chargement, ajoutez un signal B2R7seg sur l’entrée CE du registre R7seg ainsi qu’un signal RI2B sur l'entrée connect du connecteur16 associé au registre RI. Ces deux signaux permettront de réaliser le transfert de registre tel qu’il a été réalisé dans la leçon précédente.

Figure 90 Contrôle R7seg

Figure 91 Contrôle RI

Passons à la FSM ! Vous allez reprendre la FSM définie lors de la leçon 5. Par Project>Add Copy of Source, ajoutez le fichier fsm.vhd du TP5. Les trois process seront conservés. Par contre il faudra changer les ports de la FSM ainsi que l’automate. Ici il suffit de deux états chargement CHg et transfert TRf. Les transitions déclenchent les signaux indiqués.

Figure 92 Automate de l'UCC

Les modifications à apporter sur le code de fsm.vhd sont les suivantes.

    1. Changez les ports d’entrée et sortie. Ici il y a 5 sorties qui déclenche les actions sur les registres CO, RI et R7seg. Puis déclarez les signaux internes pour chacune des sorties xxx_i. Enfin le type énumératif doit être mis à jour, il contient deux valeurs chargement et transfert.
    1. Le process Next_output doit lui aussi être modifié. Après initialisation des signaux internes xxx_i, il faut pour chaque état de la FSM définir les sorties actives.
    1. Pour le process Next_node il suffit de faire passer du premier état au second. Transfert boucle sur lui-même.
    1. Enfin pour le dernier process Synchro il suffit de positionner les signaux internes sur les ports de sortie de la FSM à chaque top d’horloge.

Vous pouvez maintenant créer le symbole associé à fsm. Une fois le symbole disponible, placez une instanciation en dessous du registre RI. L’entrée clk peut de suite être reliée au fil clk de votre schéma. Pour les quatre sorties, ISE vous permet de dessiner deux fils distincts alors qu’il s’agit en fait d’un seul fil. Il suffit que les deux fils aient le même nom. ISE regroupe les fils par nommage. Cette façon de procéder permet de construire des fils de connexion non visibles et donc sans surcharge du schéma. Vous allez placer 4 fils courts en sortie de la fsm et les nommer COinc, RIload, B2R7seg et RI2B (respectez bien sûr les noms des ports). Une erreur sur un nom est ce sont deux fils différents générés par ISE !!

Figure 93 Connexion de la FSM

Vous pouvez ensuite compiler et exécuter, vous pouvez aussi simuler le comportement avec Isim en récupérant, s’il n’est pas présent, par un Project>Add Copy... le code toplevel_tb du TP6. En mode simulation vérifiez que la valeur du CO a bien été incrémentée et que les registres RI et R7seg sont correctement chargés. Il suffit de faire glisser dans la fenêtre de simulation les sorties q(15:0) pour chacun de ces registres. Une fois vérifié, faites un copie du projet vers TP8 pour la suite.

Figure 94 Simulation de la phase de chargement

A vous de jouer

Question 1 : En ajoutant deux états à la suite de votre automate chargement2 et transfert2, vous devriez être en mesure d’afficher la seconde valeur. Voici le résultat de simulation. La première valeur passe par le registre R7seg mais pas suffisamment longtemps pour être affichée.

Figure 95 Simulation de 2 phases de chargement

Question 2 : On peut même faire çà en 3 cycles au lieu de 4 !

Figure 96 Un fonctionnement pipe line!

Réponses