Emulation graphique du fonctionnement d’un microprocesseur
L’apprentissage de la programmation passe par la connaissance de l’architecture des ordinateurs, et en particulier par la compréhension de son élément central, à savoir le microprocesseur. Celle-ci peut être réalisée de deux manières complémentaires : soit d’un point de vue purement électronique, c’est-à-dire axée sur ses composants, soit d’un point de vue fonctionnel, plutôt axée sur son mode de fonctionnement. Cette deuxième approche induit la découverte, pour chaque microprocesseur, de langages de bas niveau tels que le langage machine ou le langage d’assemblage. Cette étape peut présenter quelques difficultés, car les langages impératifs sont généralement les seuls langages que connaissent les étudiants. Or, ces langages, étant de haut niveau, n’imposent pas un découpage aussi strict des opérations effectuées. Entres autres, l’absence de structures de contrôle telles que les « if » ou les « while », ainsi que de tableaux ou d’enregistrements désarçonne les néophytes. L’objectif de ce projet est de créer une application permettant de simuler l’exécution d’un programme écrit dans un langage d’assemblage ressemblant à celui du microprocesseur 8086.
Cette simulation ayant pour but de faciliter la compréhension d’un langage d’assemblage, elle se doit de présenter clairement l’ordre d’exécution des instructions, leur impact sur les données, ainsi que sur les différents éléments manipulés par ce microprocesseur, que sont la pile, les registres et les flags. Il existe déjà de tels débogueurs dans le commerce, mais l’apprentissage de leur syntaxe et de leur mode de fonctionnement nécessite de passer de nombreuses heures à compulser la documentation. Notre but est de créer un interpréteur minimaliste, d’un sous-ensemble du langage d’assemblage du 8086, très rapidement compréhensible, même pour un utilisateur n’ayant que peu de connaissances sur ce microprocesseur. Le langage retenu pour effectuer le développement de cette application est Java. L’intérêt d’utiliser ce langage est que Java est un langage objets, ce qui a permis d’effectuer une modélisation du problème sous forme de classes. A cela s’ajoutent les fonctionnalités offertes par ce langage en terme d’Interfaces Homme-Machine. Dans un premier temps, nous allons présenter succinctement les principales caractéristiques du microprocesseur Intel 8086. Ensuite nous aborderons nos choix d’implémentation, la modélisation effectuée et le fonctionnement de la partie émulant le 8086. Enfin, nous nous intéresserons plus particulièrement à l’utilisation de l’interface graphique de l’application.
Modélisation de l’émulateur
Simuler complètement le fonctionnement d’un 8086 aurait demandé un travail considérable car ses propriétés sont nombreuses. La durée imposée pour le stage nous a conduit à sélectionner celles qui nous ont paru essentielles. La gestion de la mémoire à la manière du 8086 n’étant pas non plus l’objectif principal de l’émulateur, nous avons opté pour un système à mi-chemin entre celle-ci et celle proposée dans un langage impératif comme le Pascal. Cette gestion passe donc par l’utilisation de variables et de tableaux, au lieu de segments. Le type d’une variable ou d’un élément d’un tableau est systématiquement un entier non signé sur 16 bits, ce qui autorise les valeurs de 0 à 65535. Au niveau du processeur, les registres supportés sont au nombre de 7 : les registres de données (AX, BX, CX, DX), les deux registres pointeurs de pile (BP et SP) et le pointeur d’instruction IP. Les autres registres ont été laissés de coté en raison de leur utilisation dans les interruptions (abandonnées du fait d’une trop grande complexité) et la gestion de la mémoire par segments. Les flags conservés sont ZF, CF, OF et SF, les autres ayant été rejetés car n’intervenant pas dans les instructions que nous avons choisi de supporter.
La pile, quand à elle, est gérée non pas comme une partie de la mémoire centrale mais comme une pile de données pouvant contenir des adresses et des valeurs. Le langage d’assemblage supporté par notre émulateur a été déterminé en réalisant un compromis entre le langage d’assemblage réel du 8086 et notre besoin de supporter les variables et les tableaux. Le besoin de réaliser des sauts d’une instruction à une autre sans passer par la mémoire ont été rendus possibles par l’utilisation d’étiquettes placées dans le texte du programme écrit dans notre langage.La gestion des entrées/sorties par le microprocesseur 8086 s’effectue par le biais d’interruptions faisant intervenir d’autres périphériques. Dans un souci de simplicité, nous avons remplacé ce mécanisme par deux instructions permettant les entrées/sorties de valeurs numériques. L’instruction LIRE réalise une demande d’une valeur numérique depuis l’émulateur, tandis que l’instruction ECRIRE réalise une écriture d’une valeur numérique. Ces opérations d’entrée/sortie ne sont pas gérées directement au niveau du processeur mais déléguées à l’émulateur.