1 Présentation
Transcription
1 Présentation
Licence ST mention mathématiques-informatique Informatique / MIP Architecture des ordinateurs Projet : une JVM câblée (Partie I) Université de Provence Année 2008-2009 1 Présentation Il existe deux façons d’exécuter un programme écrit dans un langage de haut niveau : – traduire le programme de haut niveau dans un programme en langage machine, que le processeur sait exécuter directement ; on parle alors de compilation (gcc est un compilateur pour le langage C). – un programme exécute le programme de haut niveau en traduisant à la volée ce dernier dans un langage de bas niveau et en exécutant cette traduction ; on parle alors d’interprétation (php est une langage interprété). Java a adopté une solution mixte : un programme Java est compilé à l’aide de la commande javac vers un fichier de ”bas niveau” indépendant de toute architecture matériel, un fichier .class. Ce fichier .class est ensuite interprété en utilisant la commande java. Cet interpréteur java est basé sur une modèle appelé machine virtuelle java (Java Virtual Machine - JVM). Cette JVM est bien sûr logiciel. L’objectif de ce projet est de faire une réalisation ”câblée” de cette JVM. Cependant, pour que cela reste réaliste, nous n’allons considérer qu’un fragment de Java et qu’une version simplifiée des des fichiers .class. 1.1 Fichiers .class, bytecode java et JVM Fichiers .class Les fichiers .class sont des fichiers binaires qui contiennent une version compilé des fichiers .java. Le langage ”machine” utilisé dans les fichiers .class est ce qui est communément appelé le bytecode java. Ce bytecode est le ”langage machine” de la JVM mais c’est un ”langage machine” orienté objet. La structure des fichiers .class est quelque peu complexe et ne nous intéressera pas, nous n’allons donc pas la décrire. Cependant, il est intéressant de voir ce qu’est ce fichier dans une forme plus lisible pour un être humain. De même qu’un programme assembleur est une forme lisible d’un programme en langage machine, on peut obtenir une version ”lisible” d’un fichier .class en utilisant sur ce fichier .class la commande javap -c. On peut voir à la figure 1 un programme Java à gauche et à droite le contenu du fichier .class correspondant (en version ”lisible”). Bytecode java Nous détaillerons plus tard ce qu’est le programme de droite et chacune de ses instructions (disons simplement que iadd sert à faire une addition de deux entiers). Une instruction de la machine virtuelle Java consiste en un opcode sur 1 byte (1 octet) spécifiant l’opération à effectuer, suivie par zéro ou plusieurs opérandes servant d’arguments ou de données qui seront utilisés par l’opération. Plusieurs instructions n’ont pas d’opérande et consiste donc simplement en un opcode. Concernant les types manipulés par les programmes bytecode, ils correspondent essentiellement au types manipulés par Java, à savoir les objets, les tableaux et les types primitifs ; ces types primitifs sont notamment byte (8 octets), short (16 octets) , int (32 octets), long (64 octets) pour les entiers ainsi que float (32 octets), double (64 octets) pour les flottants. Afin de simplifier le problème, nous n’allons considérer que le type primitif byte et donc toutes nos données seront des entiers codées sur 8 bits en complément à 2. JVM La JVM (qui se lance par la commande java) est le programme qui charge (en mémoire) et qui exécute le programme contenu dans un fichier .class. L’élément le plus important de la class essai extends java.lang.Object{ class essai { static void main(){ int i ; int s=0 ; for (i=0 ;i<10 ;i++) s = s + i; }} static void main() ; Code : 0 : iconst 0 1 : istore 1 2 : iconst 0 3 : istore 0 4 : iload 0 5 : bipush 10 7 : if icmpge 20 10 : iload 1 11 : iload 0 12 : iadd 13 : istore 1 14 : iinc 0, 1 17 : goto 4 20 : return } Fig. 1 – programme Java et son bytecode JVM est une pile. C’est ce dispositif qui est utilisé pour récupérer les opérandes des instructions et y placer les résultats. Par exemple, l’instruction iadd prendra deux entiers en sommet de pile, en fera la somme et empilera le résultat. Outre la pile, la JVM utilise aussi une mémoire classique pour y mettre notamment les variables locales (des méthodes). Cette mémoire contient aussi les objets crées mais ceci ne nous concerne pas car nos programmes ne contiendront pas d’objet. 2 2.1 Architecture de la machine câblée Description Vous trouverez à la figure 2 l’architecture générale de la JVM câblée. Celle-ci est incomplète mais permet de réaliser nombre des instructions que nous allons considérer pour notre JVM. Nous allons décrire ici un à un ses éléments contituants et nous verrons dans la section suivante la réalisation de ces éléments : – Contrôleur : c’est le coeur du dispositif mais nous allons garder cette partie pour la fin du travail – Mémoire programme : cette mémoire contient le programme bytecode à exécuter. – Mémoire variable : cette mémoire contient les variables locales du programme au cours de son exécution. – Registre d’instruction (RI) : ce registre 8 bits contient l’instruction/le bytecode en cours d’exécution. – Compteur programme (PC) : ce registre 16 bits contient l’adresse du bytecode en cours d’exécution. – VarNumReg : ce registre 8 bits contient le numéro de la variable dans lequel se fera la lecture ou l’écriture. – ALU : c’est une unité arithmétique et logique 8 bits. – X,Y : ce sont deux registres de 8 bits servant de registres d’entrée à l’ALU. – Pile : ce dispositif est de hauteur 8 et de largeur 8, c’est-à-dire qu’elle peut contenir 8 mots de 8 bits. 2 MVread MVwrite VarNum M U X Memoire variable MUX 8 SrcPushin Pile VarNumRegin VarNumReg MUX Push DataDest 8 +1 3 Fig. 2 – Architecture de la JVM Pop PCinH PCinL 16 PC PCin 1 0 0 1 0 1 0 1 0 1 0 1 16 Xin X Y Yin Memoire Programme 8 ALU ALUop 8 MPread MPwrite RIin RI Controleur 2.2 Réalisation des éléments Bien que non présent à la figure 2, tous les éléments de mémorisation de notre JVM ainsi que son controleur seront synchronisés par une horloge globale. Pour la plupart des éléments dont nous venons de parler, nous allons utiliser les éléments de mémoire prédéfinis dans tkgate. Les registres 8 et 16 bits seront des registres de tkgate tandis que la mémoire programme et la mémoire variable seront respectivement une ROM et une RAM, éléments existants dans tkgate. Les registres 8 bits VarNumReg, RI, X et Y sont chargés par la valeur présente sur leur bus d’entrée 8 bits lorsque leur ligne de contrôle, à savoir respectivement, VarNumRegin, RIin, Xin et Yin, est à 1. Il est à noter que le registre 16 bits PC possède deux bus d’entrée de données, un bus 16 bits et un bus 8 bits. Lorsque le signal d’entrée PCin est à 1 alors la valeur présente sur le bus 16 bits est chargée dans le registre. Les deux autres signaux concernent l’entrée 8 bits du registre : lorsque le signal PCinL est à 1 alors les 8 bits de l’entrée sont chargés dans la partie basse du registre PC tandis que si PCinH est à 1 alors ces 8 bits sont chargés en partie haute. Les 3 éléments importants à réaliser sont donc l’ALU, la pile et le contrôleur. La réalisation du contrôleur sera l’objet de la partie II de ce projet tandis que l’ALU ne sera qu’une extension de celle réalisée en TP 1 . Les entrées de contrôle ALUop détermine la fonction que doit réaliser l’ALU (addition, soustraction, et logique, ...). Notre pile possède une entrée de donnée (servant à entrer la donnée à empiler) et une sortie de donnée (servant à récupérer la donnée empilée en sommet de pile). Elle possède de plus 2 entrées de contrôle : – l’entrée Push mise à 1 fait que la valeur sur la ligne d’entrée de donnée est empilée. – l’entrée Pop mise à 1 fait que la valeur sur le sommet de la pile est dépilée. Il est à noter que la valeur de sortie est toujours la valeur au sommet de la pile. 1 Vous pourrez la compléter à l’aide du descriptif complet des instructions de la JVM donnée en partie II. 4