Am2900 et Manuel d’utilisation du simulateur Emu2900 (Version 0.2, 029-Octobre-2008) Par Mohamed Boussamma [email protected] Département GEL-GIF Faculté de sciences et génie Université Laval 1 1-Introduction : La famille des circuits intégrés Am2900 à été conçue par AMD (Advanced Micro Devices) en 1975, à cette époque AMD à mis sur le marché plusieurs modules basés sur la technique du ‘Bit Slice’, parmi les circuits intégrés, on cite les suivants : Am2901 (ALU 4 bits), Am2904 (Control de statut et des shifts), Am2910 (séquenceur CCU 12 bits). Ces circuits intégrés tout ensemble constituent un système minimum complet. Il existe cependant beaucoup d’extensions comme le Am2914 (contrôleur d’interruption) par exemple. Une bonne technologie ?’ Ce que l’on sait, c’est que cela est à partir du PDP-10, basé sur les circuits intégrés AM2900, que Bill Gates et Paul Allen ont lancé la révolution de l’informatique que nous connaissons ! Pour la culture générale : http://www.dailymotion.com/videos/relevance/search/cinglés+de%20l'informatique/1 http://youtube.com/results?search_query=pirates+of+silicon+valley La famille Am2900 est un bon moyen d’apprentissage pour l’introduction au domaine des microprocesseurs microprogrammés, et son apprentissage ne demandera pas beaucoup de temps. Afin de faciliter votre apprentissage, le simulateur Emu2900 à été développé pour le cours GIF-17456, ce simulateur reprend le fonctionnement exact d’une version légèrement modifiée de l’ALU 2901 (8 bits au lieu de 4), du CCU Am2910, de l’Am2904 complémentée par une mémoire programme, un Registre d’instruction (IR) et une mémoire Mapping PROM. Le simulateur fonctionne sous Windows XP, mais le test sur Vista n’a pas encore été effectué, le code du simulateur est sous licence GPL (http://www.gnu.org/licenses/gpl.html) et le code source vous sera fournis sur demande, il suffit juste de me contacter. 2 2-Architecture du système : L’architecture de la version modifiée du système est présentée dans la figure ci-dessous Figure 1- Architecture génerale du système 3 Lorsque l’on fait exécuter un programme, chacun des modules du simulateur entrent en fonction. Au départ, on doit effectuer un reset général du système, qui permet d’initialiser tous les signaux à zéro, et d’aller à la routine FETCHINSTR dans le microprogramme. C’est à chaque montée d’horloge, que le pipeline envoie de nouveaux signaux de contrôle aux différents modules pour l’instruction suivante. Ces signaux se retrouvent à l’entrée du pipeline, et sont remplacés par de nouvelles valeurs suite à la montée d’horloge. Ces valeurs proviennent en réalité de la micromémoire, et représentent les différentes valeurs de la série de bits qui forment une microinstruction. À chaque adresse de la micromémoire, on retrouve une microinstruction. Les microinstructions non programmées contiennent donc une série de bits qui ont tous la valeur zéro. Programmer une microinstuction correspond donc à déterminer la valeur de ces différents bits. Comme il l’a été mentionné précédemment, ce sont la valeur de ces différents bits qui contrôlent les différents modules du simulateur. Chaque microinstruction contient donc 71 signaux de contrôles. Ces signaux de contrôles sont divisés en instructions, dépendamment du module qu’ils contrôlent. Chaque instruction est divisée en champs, dépendamment de quelle section du module elle contrôle. Cette division améliore la programmation de ces signaux. Le pipeline permet donc d’afficher les signaux de contrôle pendant un cycle d’horloge. Cela assure donc la stabilité du système. C’est donc pendant ce cycle d’horloge que le microséquenseur AM2910 détermine l’adresse de la prochaine microinstruction et que le AM2901 (l’Alu), effectue les différentes opérations déterminées par les signaux de contrôle sortant du pipeline. Toutes les opérations du microséquenseur AM2910, du AM2901 et de la macromémoire doivent dont s’effectuer en un cycle d’horloge. Car à la prochaine montée d’horloge, ce sont les signaux de la prochaine microinstruction qui seront affichés à la sortie du pipeline. Normalement, l’accès à la macromémoire se fait en plus d’un cycle d’horloge, mais pour faciliter la simulation, cet accès se fera en un coup d’horloge. C’est pourquoi certains modules réagiront à la descente d’horloge. Une instruction machine est composée de plusieurs microinstructions, et ces instructions se retrouvent dans la macromémoire, avec les données nécessaires à l’exécution du programme. Un programme contient plusieurs instructions machines. Une table de correspondance permet de déterminer la première microinstruction d’une instruction machine. Dans ce qui suit on va expliquer le fonctionnement de chaque partie du système. 2-1- La macromémoire : La macromemoire est la mémoire principale que le système utilise pour exécuter les instructions en code machine, cette mémoire peut stocker jusqu'à 32 données de 8 bits (32x8). La macromémoire est connectée au MAR, au MBR ainsi que le D-BUS. Les opérations de lecture de la mémoire se fait sans aucun délai, mais l’écriture se fait à la descente de l’horloge. Ceci est expliqué plus tard. La lecture/écriture de mémoire est contrôlé par deux bits de contrôle RDWR (00 : aucune opération, 01 : écrire la mémoire, 10 : lire la mémoire) 4 2-2- Le MAR: Le MAR (Memory Address Register) est directement connecté aux lignes de sélection d’adresse de la macromémoire, le MAR est un Latch qui mémorise l’adresse à la montée de l’horloge, cela veut dire que le MAR sera rempli par la nouvelle donnée avant que la donnée dans le MBR sera écrite dans l’adresse indiquée par le MAR. Vu que la macromémoire est composée de 32 cases, seulement 5 bits du MAR sont utilisés pour adresser cette dernière, donc les 3 bits de poids le plus haut sont sans importance. X X X A4 A3 A2 A1 A0 Figure-2- Le registre MAR L’accès au MAR est effectué à partir de du Bus principal (D_BUS) quand le bit d’activation (load) est à 1 sinon aucune valeur n’est inscrite, ce bit peut être codé dans le champ OFFOF de la micromémoire (b1). 2-2- Le MBR: Le MBR (Memory Buffer Register) est un registre qui sert d’interface avec la mémoire, le MBR contient une entrées, une sortie et un bus bidirectionnel (entre le MBR et la macromémoire), l’entrée provient du Bus principal (dans le cas ou on veut écrire dans la macromémoire), le bus bidirectionnel est connecté à la macromémoire et la sortie est connectée vers le bus principal et isolée par un buffer tri-state. Pour écrire dans le MBR à partir du bus principal, on met le bit load à 1 (b0 du champ OFFOF), si on veut écrire dans le MBR à partir de la macromémoire on met les bits RDWR à 10, et si on veut mettre la donnée du MBR dans le bus principal on met le champ ONTO à 001, Il est aussi possible de mettre directement la donnée de la macromémoire dans le bus en jouant sur OFFOF et ONTO. 2-2- Le Registre d’instructions IR: Le registre IR est un latch de 16 bits divisé en IR_MSB et IR_LSB, qui mémorise l’instruction à exécuter qui provient de la macromémoire. IR_MSB : l’entrée est connectée avec le D_BUS et contrôlé par b2 du champ OFFOF, la sortie est connectée vers le MappingProm. Ce registre sert principalement à mémoriser l’opcode de l’instruction qui sera convertie en adresse de début dans la micromémoire par l’intermédiaire du MappingProm. 5 IR_LSB : l’entrée est connectée avec le D_BUS et contrôlé par b3 du champ OFFOF, la sortie est connectée à la DUAL PORT RAM pour selectionner les adresses des registres à utiliser.. Généralement les opérations d’écriture du registre IR est effectué par la routine FETCHINSTR qui est une routine de base pour le fonctionnement du microprocesseur (explications plus tard). 2-2- Microséquenceur AM2900: Figure 2- CCU AM2910 Le microséquenceur joue le rôle du contrôleur principal du microcontrôleur, c’est ce dernier qui détermine les macro-instructions à exécuter et gère des différentes fonctionnalités pour permettre d’exécuter des routines complexes (les boucles, les conditions, les 6 branchements…), la figure ci-haut montre les différentes parties du CCU qu’on expliquera plus loin. 2-2-1- le CCU Logic: Le CCU Logic est la partie intelligente du CCU, c’est cette dernière qui contrôle les différents composants de l’AM2910 tel que le compteur, le pointeur de Pile…, deux choses à retenir : le CCU contrôle un MUX 4/1, une ligne provient du pipeline qui fournir un jeu de 14 instructions pour le CCU (NAS [3 :0]) 2-2-2- le MUX: Le MUX d’adresse sélectionne la prochaine microinstruction dont les signaux de contrôle s’afficheront à la sortie du pipeline à la montée d’horloge. Il peut sélectionner 4 sources d’adresses, et est donc contrôlé par deux bits de sélections qui proviennent du module CCU LOGIC. Il est à remarquer qu’en réalité le MUX affiche à la sortie 5 sources possibles, ceci est possible grâce à un jeu de contrôle assuré par le CCU LOGIC (MappingProm/BranchAdress). 2-2-2- L’Incrementer: L’incrémenter est un composant logique asynchrone, il a pour rôle d’incrémenter l’adresse d’instruction courante fournie par la sortie du MUX et la garder dans microPC afin de garder l’avancement du microprogramme. 2-2-2- UPC register: L’UPC register est un latch synchrone qui mémorise la micro-instruction courante incrémenté de 1, donc au prochain coup d’horloge et si on sélectionne UPC comme entrée du MUX, on a un saut de +1 dans l’adresse micromémoire. 2-2-3- STACK ET TOS POINTER: Lorsque l’on veut effectuer des boucles ou faire un saut conditionnel à une sous-routine, il faut donc sauvegarder la valeur de l’adresse de départ ou de l’adresse de retour sur la pile. Plusieurs instructions du CCU LOGIC permettent d’empiler et de dépiler une adresse sur la pile. LE TOS POINTER incrémente et décrémente sa valeur de sortie à la descente de clock. Cela permet donc d’incrémenter l’adresse pointant sur la pile avant la prochaine montée d’horloge. La STACK, par contre, mémorise à la montée d’horloge, donc seulement à la prochaine montée d ‘horloge suivant l’instruction d’empilage. C’est ce qui permet d’incrémenter le pointeur de pile d’abord, et d’empiler la valeur de la prochaine adresse au prochain coup d’horloge. Quand on décrémente une valeur, le TOS pointeur décrémente seulement à la descente d’horloge de l’instruction. Puisque la valeur que l’on dépile doit être lue dans le MUX d’adresse jusqu’à la prochaine montée d’horloge, la sortie de la pile ne sera donc 7 rafraîchie qu’à la prochaine montée d’horloge. C’est ce qui permet de dépiler la valeur, puis de décrémenter le pointeur de pile tout en laissant cette valeur dépilée à l’entrée du MUX jusqu’à la prochaine montée d’horloge. Ces deux modules sont contrôlés par les signaux de sorties du module CCU LOGIC. 2-2-4- Counter et Zero Test : Le Counter est un registre qui peut être utile dans les boucles, on peut le charger par une constante provenant du pipeline et commencer à le décrémenter chaque coup d’adresse, la sortie du Counter est monitoré par le drapeau ZeroTest, ce drapeau s’active quand la sortie du compteur est nulle, ZeroTest nous aide alors de déterminer si on a atteint le nombre de répétitions désiré. Le mode d’emploi sera expliqué plus tard. 2-2-5- Le REGISTER : Le REGISTER aide principalement à mémoriser les adresses de branchement pour les opérations conditionnelles, ce registre enregistre le Branch_Adress dans le cas des instructions LDCT, JRP et JSRP (explications plus tard). 2-3- l’ALU AM2901: Figure 3- ALU AM2901 L’ALU est la deuxième partie indispensable pour le fonctionnement du microcontrôleur, c’est ce module qui s’occupe des opérations arithmétiques et logiques, il communique avec 8 le reste du système par l’intermédiaire du bus principal et il est contrôlé par des bits provenant de la sortie du pipeline de la micro-mémoire, donc pour chaque microinstruction, une partie des bits de la micromémoire est consacrée au contrôle de l’ALU. 2-3-1 ALU LOGIC: ALU Logic est un module déjà programmé, il est contrôlé par 3 bits de contrôle provenant de la micromémoire, ces 3 bits fournissent un jeu de 8 instructions pour Controller le flux des données dans l’ALU (expliqué plus tard). 2-3-1 DUAL PORT RAM: Les 16 registres internes de l’ALU se retrouvent dans ce module et permettent de garder en mémoire des données nécessaires aux différentes opérations de l’ALU. Les contenus de deux registres peuvent être sélectionnés, et sont accessibles en lecture et se retrouvent à la sortie de cette mémoire. Les deux registres nécessaires à chaque microinstruction peuvent être fixes ou dynamiques. S’ils sont fixes, les deux numéros de registres sont déterminés dans les microinstructions par des bits de contrôles. S’ils sont dynamiques, pour certaines microinstructions d’une instruction, il suffit de le spécifier à l’aide des bits de contrôle réservés à cet effet. Dans le cas ou l’adresse est dynamique, elle sera donc spécifiée dans la section de l’opérande de l’instruction, c’est-à-dire dans les LSB du registre IR. Les opérations de calcul de l’ALU s’exécutent à la montée d’horloge, et le résultat peut être rechargé en mémoire, dans le contenu du registre spécifié par la deuxième adresse à la descente d’horloge. Cependant, le contenu des deux registres apparaissant à la sortie n’est rafraîchi qu’aux montées d’horloges, afin de ne pas déstabiliser les modules de l’alu qui réagissent de manière asynchrone. 2-3-2 ALU DATA SOURCE SELECTOR: Ce module est semblable à un MUX, qui a pour rôle de choisir les deux données à être traités par le 8-Function-ALU, les entrés possibles proviennent soit du DUAL_PORT_RAM soit du Q-Register, du D_BUS ou nulles. 2-3-3 8-FUNCTION-ALU: C’est le module qui réalise les opérations logiques et arithmétiques, ses entrées sont les données choisies par l’ALU DATA SOURCE SELECTOR et sa sortie peut aller dans le BUS de sortie, rechargée dans la DUAL PORT RAM ou le Q-REGISTER. Elle est contrôlée par 3 bits de contrôle provenant de la micromémoire, donc peut exécuter 8 opérations différentes. Des drapeaux de statut sont aussi envoyés vers l’AM2904 à chaque opération, ces flags sont SIGN, OVR, COUT et ZERO. Une entrée supplémentaire est le CARRY_IN qui permet d’ajouter un 1 à l’opération courante. 2-3-4 Y OUTPUT DATA SELECTOR: 9 Ce module joue le rôle d’un accumulateur, et charge en mémoire la sortie du module 8 FUNCTION ALU, ou le contenu de l’adresse du premier registre sélectionné dans le module DUAL PORT RAM. La valeur est sauvegardée à la descente d‘horloge dans le registre, afin que le résultat d’une opération arithmétique soit disponible. La sortie du registre est connectée au bus principal, et il suffit d’activer son buffer 3 états afin que sa valeur se retrouve sur le bus. Cette valeur peut donc être le résultat obtenu suite à l’opération arithmétique exécutée sur des données sélectionnées, ou tout simplement le contenu d’un registre spécifique sur lequel on ne veut pas effectuer d’opérations arithmétique. Le bit qui contrôle la sélection de cette valeur se retrouve à la sortie du module ALU LOGIC, qui est luimême contrôlé par 9 bits provenant des microinstructions. 2-3-5 RAMSHIFT: Ce module est un registre à décalage asynchrone. C’est la valeur de sortie du module 8 FUNCTION ALU qui est connecté à l’entrée. Le décalage peut s’effectuer vers la droite ou vers la gauche, et ne décale qu’un bit. Le résultat de l’opération arithmétique peut donc être divisé ou multiplié par deux, avant d’être rechargé dans le contenu du registre spécifié par la deuxième adresse, dans la DUAL PORT RAM. Des bits de contrôle provenant du module ALU LOGIC déterminent s’il y a ou non un décalage, et sélectionnent le sens de ce décalage. Trois autres bits de contrôle provenant directement des microinstructions sélectionnent ce qui entre dans le registre à décalage. 2-3-6 Q-REGISTER: Ce module constitue un autre registre de l’ALU, et permet de sauvegarder des données décalées provenant de lui-même, ou des données provenant du résultat des opérations arithmétiques. La sortie de ce registre est disponible à l’entrée du module ALU DATA SOURCE SELECTOR, et peut donc être sélectionné pour effectuer des opérations arithmétiques. Ce registre sauvegarde les données sur la descente d’horloge, et la valeur de sa sortie n’est rafraîchie qu’aux montée d’horloges, afin d’assurer la stabilité du système. Les bits de contrôle sélectionnant et chargeant la valeur d’entrée sont déterminés par les bits de sortie du module ALU LOGIC. 2-3-7 Q-SHIFT: Ce module fonctionne exactement comme le module RAMSHIFT, et permet de décaler les données qui entrent dans le registre Q. 2-4- L’Unité de contrôle AM2904: 2-4-1 MICRO-MACRO Flags: Ce module permet de sauvegarder la valeur des flags de l’ALU à la descente d’horloge, après l’exécution d’une l’opération arithmétique. Les valeurs de ces flags seront utilisées pour tester des conditions nécessaires de branchements utiles au module CCU LOGIC. 2-4-2 Conditionnal MUX: 10 Ce module sélectionne le flag devenant la condition de branchement pour les instructions du module CCU LOGIC. Il est contrôlé par trois bit provenant directement des microinstructions. 2-4-3 POLARITY: Ce module détermine la polarité du flag choisi. Cela permet donc d’effectuer l’opération NOT. 3-Le SIMULATEUR : En pratique, l’utilisation d’un tel système se divise en deux parties, la programmation et l’exécution, le simulateur ne fera rien si on ne lui fournit pas les fichiers programmes (qui sont le microprogramme, le microprogramme et le MappingProm). Ainsi, avant de lancer le simulateur on doit écrire ceux-ci. Dans les cas du MappingPROM et de la macromémoire on écrit des fichiers textes, mais afin de faciliter l’écriture du fichier microprogramme, on utilisera un petit compilateur qui convertira le fichier texte en un format compréhensible par le simulateur (type texte, mais formaté d’une façon différente). Un dossier zippé est en téléchargement sur le site web du cours, ce dossier contient les deux exécutables : Emu2900.exe, microcompile.exe, ainsi que quelques exemples de programmes et un petit tutoriel. 3-1 Écriture d’un programme: Voici l’explication des champs qui servira de base de développement du programme : AM2910: NAS et BA Nom Description Instruction NAS CONT La prochaine microinstruction à être exécutée sera la suivante dans la micromémoire. 1 JMAP Saut inconditionnel à la prochaine instruction indiquée à la sortie du Mapping Prom. 2 CJP *LDCT JRP CJS Saut conditionnel à l’adresse spécifiée sur le pipeline (Champ B_A). Si CC (not) est à 0, un saut vers la valeur de B_A sinon la prochaine microinstruction sera executée. Charge le REGISTER et le COUNTER, avec la valeur spécifiée sur le pipeline (B_A). Cette valeur peut être utilisée pour charger une adresse, ou une valeur à décrémenter ultérieurement. Saut conditionnel à l’adresse du registre compteur (CC(not)=1) ou du pipeline (CC(not)=0). Le MUX sélectionne donc B_A ou la sortie de REGISTER Saut conditionnel à une sous routine si CC(not) = 0. La valeur de l’adresse de retour est empilée sur la pile, et le MUX sélectionne B_A. Si CC (not) =1, la prochaine microinstruction sera executée. 11 3 5 6 7 JSRP CRTN RPCT PUSH RFCT LOOP CJPP TWB Saut conditionnel à une sous routine. Si CC (not)=0 le saut s’effectue à partir de (B_A) provenant de la microinstruction. Si la condition CC (not)=1, le saut s’effectue à partir de REGISTER Retour conditionnel à une sous-routine. Si la condition CC (not) =0, le MUX sélectionne la sortie de la pile, et la valeur de la pile est dépilée. Si CC(not)=1, la prochaine microinstruction sera exécutée Répète une boucle dont le départ est sur le pipeline (B_A), si le compteur n’est pas égal à zéro, et décrémente le compteur. Si le compteur est égal à zéro, la prochaine microinstruction sera exécutée. La prochaine adresse va sur la pile et charge le compteur conditionnellement. Si CC (not) =0, le compteur est chargé avec la valeur de B_A. Si CC=1, aucune valeur n’est chargée sur la pile. Dans les deux cas, la prochaine microinstruction sera exécutée. Répète une boucle dont le départ est sur la pile, si le compteur n’est pas égal à zéro et décrémente le compteur, la sortie de la pile est la prochaine adresse. Si le compteur est égal à zéro, la prochaine microinstruction sera exécutée et la valeur sur la pile est dépilée. Teste la fin d’une boucle. Similaire à RFTC, à l’exception que la condition à tester n’est pas le zéro du compteur, mais CC (not). Si le test est réussi, on continue. Sinon, on répète la boucle dont le départ est sur la pile. Saut conditionnel via le pipeline, et récupère la pile (POP). Si CC (not) = 0, Le MUX sélectionne donc B_A. Si CC=1, microinstruction suivante dans la micromémoire qui est la prochaine instruction. Cette instruction peut être utilisée pour sortir d’une boucle conditionnellement, ou pour sortir d’une sous-routine en annulant l’adresse de retour. Saut à trois voies. Si la CC (not) =0 et le compteur =0, on continue et on dépile. Si CC (not)=0 et le compteur n’égal pas 0, on continue, on récupère la pile et on décrémente le compteur. Si CC (not)=1 et que le compteur=0, on va à l’adresse sur le pipeline et on dépile. Si CC (not)=1 et que le compteur n’égal pas zéro, on va à l’adresse sur la pile,et on décrémente le compteur. 8 9 10 11 12 13 14 15 Tableau -1 Instructions NAS AM2901 : AA, AB, USIERA, USIERB, NOP, CARRY, ALUSRC, A LUFN, ALUDEST - AA [3 :0], USIERA : Ce champ permet de spécifier quels registres du module DUAL PORT RAM affichera son contenu à la sortie A_OUT[7 :0]. Valeur Description USIERA=0 La sortie A_OUT est le contenu de l’adresse spécifiée par le signal AA USIERA=1 La sortie A_OUT est le contenu de l’adresse spécifiée par la première opérande du registre IR. (IR_LSB_OUT[7:4]) Tableau -2 Champ adresse AA 12 - BB [3 :0], USIERB : Ce champ permet de spécifier quels registres du module DUAL PORT RAM affichera son contenu à la sortie B_OUT[7 :0]. Valeur Description USIERB=0 La sortie B_OUT est le contenu de l’adresse spécifiée par le signal BB USIERB=1 La sortie B_OUT est le contenu de l’adresse spécifiée par la première opérande du registre IR. (IR_LSB_OUT[3:0]) Tableau -3 Champ adresse BB - ALUSRC, NOP : Ce champs permet de spécifier quelles valeurs s’afficheront au sorties R[7 :0] et S[7 :0] du module ALU DATA SOURCE SELECTOR. Si NOP=1, aucune opération ne se produit, seulement des zéro apparaissent aux sorties R[7 :0] et S[7 :0] du module ALU DATA SOURCE SELECTOR. Pour ALUSRC : ALUSRC R S 0 D ZERO 1 A B 2 ZERO Q 3 ZERO B 4 ZERO A 5 D A 6 D Q 7 A Q Tableau -4 Champ ALUSRC - ALUFN : Valeur Opération 0 R+S 1 S-R 13 2 R-S 3 R || S 4 R && S 5 (Not) R && S 6 R OU exclusif S 7 NON R OU exclusif S Tableau -5 Champ ALUFN - ALUDEST I[8 :6] : Tableau -6 Champ ALUDEST - Carry : Ce champ permet d’incorporer un Carry dans certaines opérations arithmétique du module 8 FUNCTION ALU. Pour mettre le carry à un, il suffit de mettre le signal CARRY à l’état 1. Tableau -7 Champ CARRY - ONTO : 14 Valeur Opération 0 ALU_OE 1 MBR_OE 2 MICRO_OE 3 MACRO_OE 4 CONST_OE 5 IR_MSB_OE 6 IR_LSB_OE 7 pas d'opération Tableau -8 Champ ONTO - OFFOF: Vu qu'on peut écrire sur plusieurs parties du processeur, le codage de est sur 4 bits [IR_LSB_LD, IR_MSB_LD, MAR_LD, MBR_LD]. Par exemple : si OFFOF est 7 ou 0111 cela veux dire qu'on écrit dans IR_MSB, MAR, MBR AM2904 : BCS, POL, CCEN, FLAGSRC - BCS: Ce champ détermine le flag utilisé pour commander le branchement dans le module CCU LOGIC. Les valeurs que peut prendre signal CC_OUT sont indiquées dans le tableau suivant. Il est à noter que la condition CC_OUT est la condition de branchement, et prend la valeur inversée du flag de sortie. Tableau -9 Champ BCS - POL: Ce champ détermine la polarité du signal CC_OUT. On peut réaliser des opérations NOP. Pour inverser CC_OUT, le signal POL doit être mis à un. 15 - CCEN : Ce champ force la condition de branchement dans le module CCU LOGIC, si le signal CCEN est mis à l’état 1. Si CCEN est à l’état 0, le branchement est commandé par le signal CC_OUT. - FLAGSRC: Valeur Opération 0 ALU_TO_MICRO 1 ALU_TO_MACRO 2 MICRO_TO_MACRO 3 MACRO_TO_MICRO 4 MACRO_SWITCH_MICRO 5 Aucune opération Tableau -10 Champ FLAGSRC ALUCONST : CONST MEMORY : RDWR (0 : aucune opération, 1: écriture, 2: lecture) RAMSHIFTMUX : - RIN : Ce champ détermine ce qui entre (in0) ou (in7) dans les entrées RAM0 ou RAM7 du module RAM_SHIFT, dépendamment de la fonction qui a été choisi dans le champ Alu_dest de l’instruction AMD2901. Tableau -11 Champ RIN QSHIFTMUX : - QIN: Ce champ détermine ce qui entre (in0) ou (in7) dans les entrées Q0 ou Q7 du . moduleQ_SHIFT, dépendamment de la fonction qui a été choisi dans le champ Alu_dest de l’instruction AMD2901 16 Tableau -12 Champ QIN 3-2 Syntaxe : La notation doit être en hexadécimale et tout le code doit être en majuscule, les espaces sont permis et chaque point virgule correspond à une fin d’instruction, un mot qui finit par deux point est considéré comme un label et ignoré dans la compilation, un double tiret (--) met toute la ligne en commentaires. Exemple de code (1er style) : -- Ceci est un commentaire #ORG 00 AM2910: NAS=0; BA=0; AM2901: AA=2; AB=1; …… … --Fin du programme Exemple de code (2eme style) : -- Ceci est un commentaire #ORG 00 NAS=0; BA=0; AA=2; AB=1; …… 3-3 Compilation : Afin de compiler votre code, vous devez lancer le programme microcompile.exe et charger le fichier à compiler, la boîte de dialogue est montrée si dessous : 17 Figure-1 – compilateur du microprogramme Après avoir chargé le programme, choisissez le nom de sauvegarde et cliquer sur générer, le code machine sera généré et sauvegardé dans le même répertoire que l’exécutable Pour les fichiers mappingPROM et macro mémoire, vous écrivez directement le code compréhensible par le simulateur : MappingPROM : le MappingProm est constitué de 32 cases mémoires (0 -31), la forme est la suivante : --Fichier mappingPROM.txt ONE: 0 #1A; TWO: 1 #15; THREE: 0A #FF; … -- ONE, TWO et THREE sont des labels et seront ignorés dans le programme --Fin du code Si le fichier ne contient aucune instruction, toutes les cases mémoire seront remplies de zéros. 18 Macromémoire: Elle se programme de la même façon que le mappingPROM. --Fichier macromemoire.txt ONE: 0 #1A; TWO: 1 #15; THREE: 1B #00; -- ONE, TWO et THREE sont des labels et seront ignorés dans le programme --Fin du code 3-4 Lancement du simulateur : La fenêtre principale du simulateur est la suivante : 19 Contenu des registres (DualPort RAM) Indicateurs des Flags Indicateurs d’opérations Contenu de la pile Contenu du MappingPROM Zone des registres Contenu de la macromémoire Zone de chargement chargement Zone d’exécution 20 Contenu de la micromémoire Zone de chargement : Permet le chargement des différents programmes. Zone d’exécution : le bouton Run permet l’exécution pas à pas, Raz fait un reset total au système. Contenu de la micromémoire : chaque adresse et son contenu détaillé en format hexadécimal et binaire, pour voir les détails des champs appuyez sur « détails » Contenu des registres (DualPort RAM) : C’est les registres de l’ALU, à remarquer que l’adresse 00h correspond au PC Indicateurs des Flags : Out contient les flags de l’opération qui vient d’être exécutée, micro et macro contiennent l’état des flags déjà enregistrés. Indicateurs d’opérations(ALU) : Contient les données R et S pour la prochaine opération, contient aussi l’indicateur de la prochaine opération à exécuter Indicateurs d’opérations(CCU) : Contient la dernière opération exécutée dans le CCU, la condition de branchement avant l’exécution de la dernière opération, l’adresse de la prochaine instruction qui sera exécutée et l’état des registres du CCU. Operation : indique la prochaine microinstruction à exécuter. Condition : condition CC rentrante dans le CCU Next Adress : l’adresse de saut suivante dans la micromemoire. UPC : l’adresse micromemoire courante incrémenté de 1 4-Mot de la fin : Ce document ne représente qu’un guide d’utilisation du simulateur, aucun exemple n’y est inclus, des exemples et des explications pratiques sont en téléchargement sur le site web du cours. Le simulateur est sous licence GPL, tout le code source ainsi que le projet complet est fourni sur demande en me contactant sur mon adresse email : [email protected] Section programmeurs C++ (Optionnel) : Le simulateur à été programmé sous Visual C++ 8, l’interface graphique est développée en MFC avec l’aide énorme de www.codeproject.com avec tout les exemples et les libraires gratuites que j’ai trouvé (ex : librairie pour l’affichage des boutons). Beaucoup d’améliorations pourraient être apportés au simulateur : 21 - Améliorer les compilateurs pour la gestion d’erreurs - Restructurer le code C++ surtout pour l’AM2901 (mauvais style) - On peut changer la taille de la macromémoire, On peut concevoir un gestionnaire d’interruptions et mapper les contenus dans les adresses ajoutés, par exemple une idée qui m’est parvenue est un afficheur simple qui affiche un nombre hexadécimal, on pourra alors programmer des Instruction de la sorte : SCREEN Rx, IMM (inspirez vous des parties du cours (8051 et PIC) - Ajouter l’effet du timing (CLOCK) avec variation de délai. - Enfin vos talons de conception Hardware et programmation C++ pour rendre ce projet plus complet et plus ambitieux. Tutoriels Dans cette section on présentera une démonstration d’utilisation du Simulateur et quelques exemples pour vous familiariser avec. I- Explications à bien lire: Avant tout, des explications importantes doivent être bien assimilées pour bien programmer la micromemoire, quelque champs on été modifiés afin de simplifier la lecture et la programmation de la micromemoire : Le champ RDWR: 0 : aucune opération 1 : Écrire la mémoire 2 : Lire la mémoire Le champ ONTO : 0 : ALU_OE 1 : MBR_OE 2 : MICRO_OE 3 : MACRO_OE 4 : CONST_OE 5 : IR_MSB_OE 6 : IR_LSB_OE 22 7 : pas d'opération Le champ OFFOF : Vu qu'on peut écrire sur plusieurs parties du processeur, le codage d’OFFOF est sur 4 bits : [IR_LSB_LD, IR_MSB_LD, MAR_LD, MBR_LD] Ex: si OFFOF est 7 ou 0111 cela veux dire qu'on écrit dans IR_MSB, MAR, MBR Le champ FLAGSRC : 0 : ALU_TO_MICRO 1 : ALU_TO_MACRO 2 : MICRO_TO_MACRO 3 : MACRO_TO_MICRO 4 : MACRO_SWITCH_MICRO 5 : Aucune opération Le reste des champs est similaire aux notes de cours. II- Comment coder : Pour bien coder vos programmes, des règles doivent être suivies, il est à remarquer que les compilateurs de codes sont encore en 1ere version, ils sont sensibles à la mointre erreur, aucun générateur d’erreur n’est encore intégré (Laissé en Exercice pour ceux qui veulent coder du C++ !) En cas d’erreur tout ce que vous aller remarquer, est un fonctionnement imprévisible du Simulateur. Remarques : 1- Les espaces sont permis, la notation est en hexadécimale pour tout vos codes. 2- Par défaut le simulateur insère des zéros dans tout les champs de mémoire, alors si vous voulez coder une adresse il suffit d’ajouter juste son code, le reste sera gardé à zéro. 3- Les commentaires sont permis (ex : -- Je veux mettre un commentaire) mais la technique est différente du C++, le commentaire ne peux jamais être après une instruction. 4- Afin de clarifier le code des « LABELS » peuvent être insérés au début d’une ligne, mais ne comptez pas trop sur un appel de CALL à l’assembleur pour aller à ce LABEL (sujet à développer pour les coders C++ aussi !) 23 5- Pour les codes mappingProm et Macromemoire, la technique est la suivante : ADRESSE#CONTENU 6- Voir les codes dans la section CODES, des modèles sont fournis. III- Préparer le terrain : En général, pour un processeur, l’exécution d’une instruction se fait en 2 étapes nécessaires : Chercher l’instruction (FETCH), et exécuter (EXECUTE), chaque fois qu’une instruction est exécutée, le machine d’états du processeur saute vers l’état FETCH qui sera exécuté à l’infini si on ne débranche pas la prise ! Pour notre cas, dans l’Am2900, avant de se lancer dans la conception de micro-instructions, on doit préparer le processeur à deux choses : 1- Le SOFTWRE RESET, et le 2- FETCH INSTRUCTION. Les fichiers correspondants à ces tutoriels sont dans la section CODES 1- SOFTWARE RESET : Le rôle du reset software est de réaliser une mise à zéro de tout les registres système et surtout le PC, même dans les nouveaux processeurs cette procédure est primordiale surtout pour résoudre les blocages système (l’écran bleu de Windows fait ça!). Pour notre cas on a réalisé un reset simple à l’adresse 0h qui fait une mise à zero du PC et continue sur FETCH INSTRUCTION à l’adresse 01h (voir le code dans Getting Started). 2- FETSH INSTRUCTION : Le principe de cette instruction qui est codé sur 4 adresses micromemoire est simple, le standard Am2900 veut qu’une instruction soit codée sur 2 bytes au minimum, le FETCH cherche ces deux bytes dans la macromemoire, les mets successivement dans le registre d’instruction IR_MSB et IR_LSB et à la fin, fait un saut (NAS = 2) à la correspondance spécifiée par le mappingPROM à l’adresse IR_MSB, donc il faut faire attention à mettre l’adresse du saut au tout premier byte d’une macroinstruction. IV- Pratiquer vous ! 24 25