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