L'émulation JIT du code 68K

Le principe

JIT = Just In Time = juste à temps

La méthode standard d'émulation, basée sur le trap ILLEGAL, nécessite un redécodage de l'instruction à émuler à chacune de ses exécutions. Ajoutez à cela le temps pris pour exécuter le TRAP et le temps pour en ressourtir (RTE), et vous aurez une bonne idée de la lenteur engendrée par cette méthode.

L'émulation JIT consiste à convertir toutes les instructions devant être émulées dès le lancement du programme. Le programme est modifié, les instructions originales sont remplacées par les séquences d'instructions de remplacement. C'est paradoxal, mais en fait de conversion "juste à temps", celle-ci est en réalité réalisée bien à l'avance. En fait le terme JIT est initialement destiné aux machines virtuelles Java dont l'exécutable est de type semi-compilé (comme le GFA Basic), le compilateur Java JIT effectue donc l'étape de compilation juste au moment d'utiliser le programme et non pas lors de sa création, d'ou cette appellation.

Quelques rappels

C'est le code de l'instruction Pexec qui doit être réécrit. Pour commencer, voyons ce que fait le Pexec dans un TOS standard.

- Réservation du plus grand bloc de mémoire disponible.
- Chargement du fichier (PRG, APP, TTP...) au début du bloc mémoire
- Décodage de la basepage du programme et initialisation de celle-ci
- Relocation du programme en mémoire
- Retour au mode utilisateur et saut au début du segment TEXT

L'émulateur JIT peut-être placé avant ou après la routine de relocation, ou mieux, constituer lui-même la nouvelle routine de relocation. Commençons donc par analyser ce en quoi consiste la routine de relocation.

Pour revenir aux sources, les microprocesseurs 68K disposent de nombreux modes d'adressages. Certains sont dits absolus et d'autres sont relatifs. Un mode d'adressage absolu désigne l'emplacement d'une case mémoire par rapport au début de la mémoire. L'adresse 10000 désigne le 10000e octet de la mémoire. En revanche, un mode d'adressage relatif désigne l'emplacement d'une case mémoire par rapport à un registre d'adresse ou au compteur de programme (PC). Dans ce cas, l'adresse 10000(PC) (c'est comme cela que l'adressage relatif est noté) avec un PC égal à 20000, désigne le 30000e octet de la mémoire.

Lors de leur compilation, tous les programmes TOS/GEM sont enregistrés comme débutant à l'adresse zéro. Or cela est faux, le bloc mémoire alloué par le Pexec peut être situé n'importe où en mémoire (et d'ailleurs surtout pas en zéro, qui contient des vecteurs d'interruption et de RESET vitaux pour le microprocesseur).

La relocation consiste donc à adapter tous les adressages absolus en ajoutant à chaque adresse de ce genre, l'adresse de départ du bloc mémoire alloué par le Pexec. Pour faire cela, nul besoin d'analyser le programme pour y rechercher les adressages à modifier, une table de relocation est enregistrée avec tous les exécutables TOS/GEM (elle est placée en dernier après les segments TEXT, DATA et BSS). Cette table est une liste de tous les adressages absolus à modifier. Il existe également des adressages absolus qui doivent rester inchangés (vecteurs d'interruption, variables système, zone d'entrées-sortie), cette table ne les liste pas, ils ne sont donc pas affectés par la relocation.

Mise en oeuvre

La convesion du code 68K en code ColdFire s'effectue en plusieurs passes.

Tout d'abord, le code est analysé pour y trouver tous les adressages, qu'ils soient absolus ou relatifs. Ceux-ci sont stockés dans une table indexée par rapport au programme original. les adressages relatifs sont temporairement convertis en absolu.

Pendant la deuxième passe, l'ensemble du code est à nouveau analysé. Toutes les instructions non reconnues par le ColdFire sont remplacées par la séquence d'instructions de remplacement. Il s'ensuit logiquement un décalage dans les adresses mémoire, a chaque fois que le convertisseur passe sur une adresse indexée dans la table des adressages, la nouvelle adresse vient remplacer l'ancienne. Le code converti est temporairement stocké à un emplacement séparé du code original. Une fois l'étape de conversion terminée, le code original est remplacé par la version convertie.

La troisième et dernière passe consiste à parcourir l'ensemble de la table des adressages. Reconvertir en relatif les adressages qui y étaient à l'origine et remplacer les anciennes valeurs d'adressage par les nouvelles.

Voilà, c'est tout... Ou presque... Il y a un cas qui n'a pas été abordé. La conversion du code 68K en code ColdFire entraîne un grossissement de celui-ci. Les adressages relatifs courts, car codés sur 8 bits risquent d'excéder la marge de manoeuvre de plus ou moins 127 octets (à quelque chose près) qu'ils permettent et devront être convertis en adressages longs. De la même façon, des adressages relatifs longs, codés sur 16 bits risquent de dépasser la limite de 32767 octets qui leur est permise, il faut alors les coder sur 32 bits. Pour les instructions comme Bcc qui n'ont pas de mode 32 bits, il changer le code. Un petit exemple.

bcc loin_ailleurs

devient

bcs suite
jmp loin_ailleurs
suite:

Le principe est simple: il suffit de tester la condition inverse pour éviter si nécessaire un branchement absolu en 32 bits.

L'idée qui m'a JIT

Cette fois-ci, c'est tout. Je pense que le principe du convertisseur JIT est dorénavant aussi clair pour vous qu'il l'est pour moi.

- Pascal Barlier - 9 fev 2001 - coldfire.online.fr -