
PMMU2, le Retour

Après avoir vu les registres et le fonctionnement global de la PMMU, il ne nous reste
plus qu'à voir les instructions et une petite utilisation de la PMMU : le mapping de
fichier en mémoire virtuelle. Mais avant tout, il y a une chose dont je n'ai pas
parlé : le cache de la table de traduction.
Le cache de traduction d'adresse : l'ATC
Ce cache permet de faire la correspondance entre une adresse logique et une adresse
physique. Il est composé de 22 entrées, dont chacune est
décomposé comme suit :
Partie "logique" de l'entrée Partie "Physique" de l'entrée
2 1 2 1
7 654 321098765432109876543210 7 6 5 4 321098765432109876543210
- --- ------------------------ - - - - ------------------------
^ ^ ^ ^ ^ ^ ^ ^
V FC adresse logique B C W M adresse physique
I P
La signification des bits est la suivante : - V : indique la validité de cette
entrée
- FC : code de fonction (les FC?)
- adresse logique : les 24 bits de poids fort de l'adresse, si une page à une taille
supérieur à 256 octets, les bits nécessaire sont ignorés.
- B : positionné si pendant la recherche dans les tables il y a eu une erreur bus
- CI : indique si il faut mettre en cache la page ou pas
- WP : indique si la page est protégée en écriture
- M : indique si la page est modifiée
- adresse logique : No de la page logique (ie : les bits de poids fort qui ne servent pas
à l'index dans la page)
- adresse physique : adresse physique de la page logique.
Je ne vais pas vous expliquer comment marche un cache, mais le principe est le suivant :
on stocke dans cette petite mémoire (22 entrées seulement!) rapide les
correspondances page logique->page physique. Ensuite au lieu de parcourir toutes les tables de
traduction, on commence par regarder si par hasard on aurait pas la correspondance pour la
page logique que l'on cherche. On comprend vite l'intérêt de ce cache, car à
chaque accès mémoire, il y a un besoin de traduction (même pour lire le code!),
donc chaque accès mémoire se traduirait par 3 ou 4 accès
supplémentaires! On arrive donc à une machine 3 ou 4 fois plus lente! Heureusement
le cache fonctionne bien, et donc souvent, la correspondance page logique->page physique est
présente.
Mais pourquoi je vous parle du cache? Et bien parcequ'il peut poser un problème.
Imaginez que pour une raison ou une autre, une page logique doit changer de place en
mémoire physique. Pour ce faire, vous copier votre page à la nouvelle place,
modifiez votre table de traduction, et le tour est joué! Sauf, si par (malchance??)
hasard la correspondance page logique->page physique se trouve dans le cache, et donc lors du
prochain accès à cette page, vous allez obtenir l'ancienne place de cette page! Ce
problème se fait plus ressentir dans des commutations de processus lourd, ou il faut
changer presque toutes les correspondances page logique->page physique.
Les instructions de la PMMU
La PMMU est un coprocesseur, et donc utilise les instructions cp????. Mais au lieu de devoir
préciser le numéro du coprocesseur (%000, pour la PMMU), on utilise les
instructions en P???? qui s'adresse directement à la PMMU. La liste des instructions est la
suivante :
PBcc Saut sur condition de la PMMU
PBcc.<taille du deplacement> <adresse de saut>
permet de faire un saut suivant les conditions de la MMU (le registre
MMUSR). Les conditions sont les suivantes :
BS : B à 1 BC : B à 0
LS : L à 1 LC : L à 0
SS : S à 1 SC : S à 0
AS : A à 1 AC : A à 0
WS : W à 1 WC : W à 0
IS : I à 1 IC : I à 0
GS : G à 1 GC : G à 0
CS : C à 1 CC : C à 0
PDBcc Tester, décrémenter, et saut
PDBcc Dn, <adresse de saut>
test une condition, si elle fausse, il y a décrémentation du registre
de donnée Dn, et saut à l'adresse de saut si ce dernier est différent
de -1. Les codes conditions sont les mêmes que pour PBcc.
PFLUSH Invalide une entrée de l'ATC
PFLUSHA
PFLUSH Fc, masque
PFLUSH Fc, masque, <adresse effective>
Cette instruction permet d'invalider (elles ne seront plus utilisée
pour la traduction) des entrées dans le cache de la PMMU. PFLUSHA
invalide toutes les entrées du cache. PFLUSH Fc, masque permet
d'invalider des entrées qui ont les bits FC correspondant. La dernière
forme permet d'invalider une entrée spécifique à une adresse.
PLOAD Charge une entrée dans le cache
PLOADR Fc,<ea>
PLOADW Fc,<ea>
Cette instruction charge une entrée de l'ATC avec une correspondance
adresse logique (l'adresse effective) -> adresse physique en prenant
soin de respecter les bits FC. Il existe deux variantes : une pour
l'écriture (PLOADW), et une autre pour la lecture (PLOADR).
PMOVE Accès aux registres de configuration de la PMMU
PMOVE MRn,<adresse effective>
PMOVE <adresse effective>,MRn
PMOVEFD <adresse effective>,MRn
Cette instruction permet de lire/modifier les registres de
configuration de la PMMU. Les transferts se font entre la mémoire et un
registre de la PMMU. PMOVEFD permet d'invalider le cache de traduction
d'adresse, en même temps que l'instruction. Ceci est très pratique
lorsque la configuration mémoire est très boulversée.
PTEST Test une adresse logique
PTESTR Fc,<adresse effective>,#<niveau max>
PTESTR Fc,<adresse effective>,#<niveau max>,An
PTESTW Fc,<adresse effective>,#<niveau max>
PTESTW Fc,<adresse effective>,#<niveau max>,An
Cette instruction cherche dans les tables de traduction la traduction
de l'adresse logique. Les registres MMUSR contient l'état lié à
l'adresse logique. Ainsi si une adresse logique provoque une erreur
bus, le bit B à 1. Fc, représente l'état des bits de fonctions lors de
la recherche de la traduction de l'adresse effective. Niveau max permet
de borner le nombre de niveau de table de traduction dans lesquels la
recherche s'effectue. Si niveau max=0, seul le cache est testé. Il est
possible de stocker, dans un registre d'adresse, l'adresse du
descripteur de page de la page logique. PTESTR test la correspondance
adresse logique->adresse physique pour une lecture et PTESTW pour une
écriture.
Voilà l'ensemble des instructions lié à la PMMU. Maintenant voici
le premier exemple d'utilisation de la PMMU :
Le mapping de fichier en mémoire
Le mapping de fichier en mémoire consiste à faire croire au programme qu'un
fichier est en mémoire alors qu'il ne l'est pas. Il est ainsi possible de manipuler un
fichier de plusieurs dizaine de Mo sur un Falcon avec 4 Mo de mémoire. Le principe est le
suivant : charger les parties utilisées du fichier en mémoire et les placer dans la
mémoire virtuelle. Il faut savoir maintenant quels sont les parties chargées en
mémoire et celles qui ne le sont pas, et ou. Cela se réalise grâce à
la table de traduction : lorsque le descripteur de page n'est pas valide c'est que la page n'est
pas en mémoire, et donc qu'il va falloir la charger. Lorsque l'on tente d'accéder
à une page non valide, il y a une erreur bus. En récupérant cette erreur
bus, on peut savoir si elle a eu lieu à cause d'un défaut de traduction (on
connaît l'adresse en question, et on peut déterminer si cette dernière
appartient au fichier mappé ou pas), et dans ce cas on charge la page correspondante
à l'adresse logique désirée.
Mais pour arriver à ceci, il faut savoir faire plusieurs choses. Savoir quelle page
physique sont occupées, et par qui. Pour ceci, il y a aussi des descripteurs de page
physique. Ces descripteurs contiennent l'adresse phy-sique de la page qu'ils décrivent,
son adresse logique, et l'adresse du descripteur de page correspondant. Notez que ce dernier
peut être retrouvé grâce à l'instruction PTEST.
Pour résumer, le principe est le suivant :
- on dit qu'un fichier est chargé en mémoire à partir d'une adresse
- ce fichier est en mémoire virtuelle, donc si une partie de ce fichier n'est pas
présent, il faut la charger en mémoire.
- pour détecter l'abscence de certaine partie du fichier, on utilise le fait que
l'échec de traduction produit une erreur bus.
Pour y arriver, il nous faut reprogrammer la PMMU, changer la table de traduction,
détourner les exceptions erreur bus et erreur PMMU (si on est très maladroit, on se
sait jamais!).
La PMMU se trouve configurée de la manière suivante :
- PMMU validée
- page de 4Ko !
- tous les bits significatifs pour la translation d'adresse
- 4 bits pour le premier niveau
- 4 bits pour le second
- 4 bits pour le troisième
- 8 bits pour le quatrième
Ce qui nous donne comme mot de configuration : $80C04448 (les amateurs
appréciront!). Aucune limite n'est mise sur la taille de la mémoire
virtuelle. Il n'y a pas utilisation des registres de transparence. L'initialisation de
la PMMU se déroule dans la routine creer_pmmu. Dans cette routine il a création
de la configuration PMMU en mémoire, puis chargement de cette configuration.
Ensuite on invalide le cache de traduction, pour détruire tous les relicats de
traductions incorrectes.
La table de traduction est basé sur la table de traduction du système. Ainsi
les 16 premiers Mo sont directement traduit (adresse logique=adresse physique), ainsi que les
16 derniers (ils correspondent en fait au 16 premiers !). Dans cette exemple, seulement le Mo
situé à l'adresse $80000000 pourra contenir le fichier. Donc il y a modification
de la table de traduction en conséquence. C'est la routine creer_tables qui se charge
de faire la copie (avec translation d'adresse!) de la table du système. Ensuite la routine
ajout_tables s'occupe de rajouter la partie de traduction nécessaire pour la zone du
fichier. Toutes les pages de cette zone sont non présente en mémoire virtuelle.
Il ne nous reste plus qu'a modifier la table des vecteurs d'exception. On utilise le
registre VBR pour savoir ou elle est stockée. Le registre VBR, pour ceux qu'ils ne le
savent pas, est l'adresse de début de la tables des vecteurs d'exceptions. On copie
cette table, et on modifie cette copie. Ensuite on modifie le registre VBR pour que le 68030
utilise cette table. La routine creer_vecteurs se charge de cette opération.
Il ne reste plus qu'a initialiser les descripteurs de pages physiques. Chaque descripteur
de page physique contient l'adresse du descripteur de page virtuelle qui utilise la page
physique; l'adresse physique de la page physique; l'adresse logique de la page. De plus, il y a
aussi l'adresse du descripteur de page suivant. Ceci permet de chaîner de manière
circulaire (le suivant du dernier est le premier) les descripteurs de page. Ce chaînage sert
lors de la recherche de page physique libre. L'algorithme de remplacement de page est le
suivant : on remplace la page courante, et on passe à la page suivante. Ainsi on
remplace les pages qui sont restée le plus longtemps en mémoire. Ce n'est pas un
algorithme optimal, mais il est très simple à implémenter.
Il ne reste plus qu'a voir le coeur de cet exemple : l'exception erreur bus. La
première chose réalisée est de récupérer l'adresse fautive sur la
pile. Ensuite on regarde si cette adresse appartient à la zone de mémoire
virtuelle. Si elle n'appartient pas à cette zone, alors il y a affichage
d'un petit message, restauration de la PMMU, de la table des vecteurs, et
retour au système qui va afficher fièrement 2 bombes. Si il s'agit d'une
adresse dans la zone virtuelle, alors le traitement est un peu plus long.
Il faut commencer par trouver une page physique libre. Pour ceci on prend la page physique
courante (pointeur desc_courant), on regarde si elle est utilisée par une page logique
(adresse de descripteur de page logique différent de 0). Si oui, on modifie le
descripteur de page logique (page non valide), et on invalide dans la cache la traduction
adresse logique -> adresse physique. On pense desc_courant à la page suivante.
Il faut ensuite déterminer la page logique fautive. Ceci se réalise en
examinant l'adresse logique. On prend les 20 bits de poids faible qui nous donne l'offset de
l'octet fautif. Il suffit de diviser par la taille de la page pour obtenir le numéro de
page. Ce numéro de page va nous servir à savoir quelle page du fichier
mappé il faut charger. Ensuite on place le pointeur sur le fichier au bon endroit, et on
lit la taille d'une page.
Pour modifier la table de traduction, c'est très simple. Sachant l'adresse virtuelle,
on utilise ptest qui nous donne l'adresse du descripteur de page, on modifie ce descripteur,
ainsi que le descripteur de page physique contenant cette page logique.
Et voilà la fin de ce premier exemple sur l'utilisation de la mémoire
virtuelle. Pour se convaincre de l'intérêt de cette technique il n'y a cas jeter un
coup d'oeuil à la routine d'affichage de l'image. On utilise que 16 Ko de mémoire
pour charger l'image. C'est un peu du direct to disk, mais en plus simple pour le programmeur!
Pour la prochaine fois, on regarde le swap de mémoire. Pour ceux qui ne pourront pas
attendre le prochain numéro, une petite astuce : lors de la libération de la page
physique, il suffit de regarder si elle a été modifiée, si oui, alors on la
sauve sur disque.
Bon code !
Golio Junior