Ce travail pratique vaut 5% de la note totale du cours. Comme le stipule le plan de cours, le travail doit être fait individuellement.
Objectifs
Ce travail pratique vise les objectifs suivants:
Distinguer les adresses virtuelles et physiques;
Maîtriser le concept de la mémoire paginée;
Implémenter diverses fonctions nécessaires à l'utilisation de la mémoire paginée;
Comprendre pourquoi surviennent les fautes de pages et ce qu'il faut faire pour les traiter;
Utiliser une table des pages et une table des pages inversée dans un système réel.
Préparation
Important: lisez attentivement tout l'énoncé avant de commencer à travailler! Il contient plusieurs informations qui vous seront très utiles.
Ce TP ne contient pas de questions à répondre sur le portail des cours. Le fichier source.txt que vous remettrez compte donc pour 100% de la note de ce TP.
Survol
Dans ce TP, vous devrez mettre en place un système d'allocation pour une mémoire paginée. Ce système est très similaire à celui utilisé dans les ordinateurs modernes. Toutefois, dans le contexte de ce TP, nous utiliserons un système contenant beaucoup moins de mémoire que ce que doit gérer votre ordinateur ou votre téléphone intelligent. Ce système possède les caractéristiques suivantes:
Taille des pages (et des trames) mémoire : 32 octets;
Taille totale de la mémoire virtuelle : 640 octets, soit 20 pages distinctes;
Taille de la mémoire vive (RAM) dans laquelle les trames (frames) sont stockées : 96 octets, soit 3 trames.
Afin de faciliter votre tâche, nous avons déjà découpé le code à produire en plusieurs fonctions, que vous pourrez programmer et tester indépendamment. Vous trouverez plus d'informations sur chacune de ces fonctions dans la section détails ci-bas.
Lorsque vous aurez terminé, téléchargez tout d'abord votre fichier source.txt sur votre ordinateur grâce au bouton « sauvegarder » dans le simulateur, puis téléversez ce même fichier dans la boîte de dépôt qui est disponible sur le portail des cours.
Pour toutes questions concernant la procédure de remise ou le travail lui-même, posez vos questions sur Piazza!
Détails
1. Présentation générale
Le simulateur ne pouvant directement émuler un disque dur, nous utiliserons plusieurs zones dans sa mémoire de données pour simuler un système tel que décrit à la section précédente. Trois zones sont ainsi déclarées dans la mémoire de données:
MaRAM : espace de 96 octets commençant à l'adresse 0x1000;
MonDisqueDur : espace de 640 octets commençant à l'adresse 0x10E0;
MaPile : espace de 200 octets commençant à l'adresse 0x1364.
Afin de faciliter leur visualisation dans l'afficheur mémoire du simulateur, toutes ces sections sont séparées par des espaces vides. MaRAM est l'espace que nous utiliserons pour simuler la RAM de votre système à mémoire paginé. Ainsi, lorsque l'on parlera d'aller lire une donnée à l'adresse 0x04 de la RAM, cela équivaut, dans le contexte du simulateur, à aller lire à l'adresse 0x1000 + 0x04 = 0x1004. De la même manière, MonDisqueDur est l'espace que nous utiliserons pour simuler une mémoire de stockage telle qu'un disque dur, sur laquelle le système peut décharger les pages de la RAM au besoin. Finalement, MaPile est un espace mémoire indépendant que vous pourrez utiliser pour sauvegarder les registres lors de l'exécution des fonctions que vous devez coder.
2. Accès à la mémoire paginée
Dans un "vrai" système à mémoire paginée, la pagination devrait être transparente aux programmes, c'est-à-dire que toutes les instructions LDR et STR devraient référer directement à des adresses virtuelles. Dans notre cas, afin de simplifier la mise en place du système, cette pagination ne sera pas transparente pour les programmes. Ainsi, un accès mémoire tel que LDR Rx, [Ry] devra être effectué par les étapes suivantes:
Mettre dans R8 la valeur de l'adresse que l'on souhaite lire (Ry);
Appeler la fonction LoadVirtuel, qui mettra dans R9 la valeur lue (Rx).
; Equivalent de LDR Rx, [Ry]
MOV R8, Ry
BL LoadVirtuel ; Effectue le "LDR". Après, R9 contient la valeur de Rx
De la même manière, une écriture en mémoire comme STR Rx, [Ry] sera simulée par les étapes suivantes:
Mettre dans R8 la valeur de l'adresse à laquelle on souhaite écrire (Ry);
Mettre dans R9 la valeur que l'on veut écrire (Rx);
Appeler la fonction StoreVirtuel, qui effectuera cette écriture
; Equivalent de STR Rx, [Ry]
MOV R8, Ry
MOV R9, Rx
BL StoreVirtuel ; Effectue le "STR"
Les fonctions LoadVirtuel et StoreVirtuel sont déjà écrites pour vous, mais elles nécessitent l'implémentation des autres fonctions pour fonctionner!
3. Les structures de données
Afin de remplir la tâche demandée, vous aurez besoin de trois structures de données : la table de pages, la table de pages inverse et les compteurs d'accès. Ces structures correspondent à ce qui a été vu dans le cours sur la gestion de la mémoire.
3.1 La table de pages
La table de pages est la structure qui fait le lien entre les pages et les trames présentes en RAM. Dans ce TP, vous utilisez une mémoire virtuelle de 20 pages, il y a donc 20 entrées dans cette table. Elle est située à l'adresse 0x04. Lors de l'exécution de votre programme, cette table pourrait par exemple ressembler à ceci :
Dans ce cas-ci, la table de page indique que la page 0 est présente en RAM dans la trame 0, que la page 8 est dans la trame 1 et que le contenu de la page 16 est située dans la trame 2. Toutes les autres pages ont -1 (0xFFFFFFFF) comme valeur de trame pour indiquer qu'elles ne sont pas en mémoire.
Notez que chaque entrée de la table de pages fait 4 octets (32 bits).
3.2 La table de pages inverse
La table de pages inverse met en relation les trames et les pages qu'elles contiennent. Elle peut donc être vue comme l'inverse de la table de pages : au lieu de chercher quelle trame correspond à une page donnée, on cherche quelle page correspond à une trame donnée. Puisque nous utilisons 3 trames en RAM, cette table possède donc 3 entrées. Par exemple, son état pourrait être le suivant :
Dans ce cas-ci, la table indique que la trame 0 contient la page 0, que la trame 1 contient la page 8 et que la trame 2 contient la page 0x10=16. Cette représentation est exactement l'opposé de la table de page présentée plus haut. Cette table inverse vous sera utile lorsque vous voudrez évincer une page de la RAM, puisqu'il faut alors connaître le numéro de cette page pour pouvoir la copier sur le disque dur.
3.3 Les compteurs d'accès
La dernière structure est un tableau de compteurs d'accès. Chaque trame mémoire possède son propre compteur, si bien que cette table a donc 3 entrées. Chaque entrée indique combien de cycles d'accès mémoire se sont écoulés depuis que cette trame a été accédée. Par exemple, une trame qui vient d'être accédée verra son compteur remis à 0; toutes les autres verront leur compteur incrémenté. Un exemple type de l'état des compteurs est donnée à la figure suivante :
La mise à jour de ces compteurs est faite par la fonction AjusteCompteurAcces, qui est déjà codée pour vous. Vous devrez cependant déterminer la page à retirer de la RAM, sachant que l'on souhaite toujours retirer la page la moins récemment utilisée (algorithme LRU, pour « Least Recently Used »).
4. Détail des fonctions à écrire
La mise en place d'un système à mémoire paginée n'est pas simple, aussi la structure du code à écrire a déjà été établie pour vous. Cette structure est présentée à la figure suivante :
Dans ce diagramme, chaque boîte correspond à une fonction. Chaque ligne allant vers la droite correspond à un appel de fonction (BL nomdelafonction), et chaque ligne allant vers la gauche à un retour de fonction (BX LR). Les fonctions dont le nom est en blanc sont déjà écrites pour vous. Vous n'avez donc rien à faire pour ces dernières, si ce n'est les utiliser. Par contre, vous devez implémenter les fonctions dont le nom est de couleur orange sur ce diagramme. Ces fonctions sont décrites en détail dans le code fourni dans l'onglet simulation, avec des informations concernant:
Les paramètres d'entrée : quels registres contiendront les entrées requises pour l'exécution de la fonction;
Les valeurs de retour (sortie) : quels registres doivent être modifiés par la fonction. Tous les autres registres utilisés par la fonction doivent être préalablement sauvegardés puis restaurés avant la fin de la fonction;
Une description du comportement attendu de la part de la fonction;
Les suppositions que vous pouvez faire dans le cadre de cette fonction. Un exemple d'une telle supposition pourrait être la taille des pages mémoire;
5. Test de votre programme
Tester et déboguer un programme assembleur complexe n'est pas simple. Afin de vous aider dans ce travail, nous vous fournissons des tests pré-implémentés. Ceux-ci se situent dans le bloc main. Les premiers tests visent une seule fonction à la fois, de manière à vous permettre de programmer chaque fonction indépendamment. Une fois tous les tests individuels réussis avec succès, vous pouvez passer aux tests globaux, qui vérifient le bon comportement de votre système en utilisation réelle. Il ne sert à rien de passer aux tests globaux si un des tests précédents a échoué, puisque toutes les fonctions doivent fonctionner correctement pour que les tests globaux produisent des résultats valides.
La vérification de la réussite des tests est faite avec les commandes ASSERT. Par exemple, la ligne ASSERT R2=2 indique qu'après l'exécution de l'instruction précédente, R2 devrait contenir la valeur 2. Un « X » s'affichera à la gauche de cette ligne si la condition n'est pas rencontrée.
Si vous rencontrez des erreurs dans les tests, affairez-vous à régler ces erreurs avant de passer aux tests suivants, car plusieurs tests assument que toutes les fonctions précédentes fonctionnent correctement.
Pondération
Tel que mentionné précédemment, le code compte pour 100% de la note de ce TP. Chacune de vos fonctions sera tout d'abord évaluée indépendamment des autres en employant la pondération suivante:
DecomposeAdresse: 10%
TrouverPage: 15%
TrouverValeurMaximum: 20%
CopieMemoire: 5% (cela ayant déjà été évalué dans le TP3)
ChargerPage: 20%
EvincerPage: 20%
La réussite des tests globaux compte pour 10% de la note totale.
Activer
Type
cycles
cycles (premier)
Vitesse d'exécution : ms
Français
SECTION INTVEC
B main
; Table de pages (correspondance page / trame)
tableDePages ASSIGN32 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
; Table de pages inverse (correspondance trame / page)
tableDePagesInverse ASSIGN32 -1, -1, -1
; Compteurs d'accès à chaque trame
tableAcces ASSIGN32 0, 0, 0
SECTION CODE
;############################################################################
DecomposeAdresse
; Paramètres d'entrée :
; - R8 : Adresse virtuelle à décomposer
;
; Valeurs de sortie :
; - R0 : Index de la page correspondant à cette adresse, numéroté à partir de 0
; - R1 : Décalage (offset) à l'intérieur de cette page
;
; Description :
; Cette fonction doit, à partir d'une adresse virtuelle, déterminer à quelle
; page cette adresse appartient. Elle doit également calculer le décalage
; requis à partir du début de la page pour atteindre l'adresse demandée.
; La fonction doit retourner dans R0 l'index de la page en question et dans
; R1 le décalage calculé.
;
; Notes:
; Dans l'énoncé de ce TP, on emploie les termes:
; - « index » pour dénoter le numéro de page
; - « décalage » pour dénoter la position dans la page.
; Cette spécification vous est donnée pour faire le parallèle avec ce qui est
; indiqué dans les notes de cours.
;
; Suppositions nécessaires :
; - Ce système utilise des pages de 32 octets.
;
; ÉCRIVEZ VOTRE CODE ICI
BX LR
;############################################################################
TrouverPage
; Paramètres d'entrée :
; - R0 : Numéro de la page demandée
;
; Valeurs de sortie :
; - R2 : -1 si cette page n'est pas présente en RAM (défaut de page), sinon
; le numéro de la trame en RAM contenant cette page
;
;
; Description :
;
; Cette fonction doit déterminer la trame contenant une page en RAM.
; Pour ce faire, elle utilise le numéro de page i reçu en argument dans R0, et
; retourne la valeur contenu à la position i de la table de pages. Par exemple,
; si la table de pages contient les valeurs 1, -1, -1, 2, -1, 0, -1, ... et que
; l'on demande la page numéro 3, alors cette fonction doit retourner 2
; (puisque la valeur du 4e élément de la table de page est 2, et qu'on commence
; à compter à partir de zéro). Si on avait plutôt demandé la page numéro 0,
; alors la fonction aurait dû retourner 1. Si on avait demandé la page numéro 5,
; alors le retour devrait être 0. Finalement, si on demande une page inexistante
; en RAM (qui n'est contenue dans aucune trame), alors il faut retourner -1.
; Par exemple, si on avait demandé la page numéro 2, ou la page numéro 4,
; il aurait fallu retourner -1, puisque c'est la valeur de la table de pages
; à ces positions.
;
; Suppositions nécessaires :
; - Chaque entrée de la table de pages fait 4 octets.
;
; ÉCRIVEZ VOTRE CODE ICI
BX LR
;############################################################################
CopieMemoire
; Paramètre d'entrée :
; - R10 : Adresse source
; - R11 : Adresse destination
; - R12 : Nombre d'octets à copier
;
; Valeurs de sortie :
; - Aucune valeur de sortie requise
; - La copie doit cependant bien avoir été effectuée
;
; Description :
; Cette fonction doit copier les données d'un endroit à l'autre de la mémoire.
; Elle est analogue à celle du TP3, mais la formulation de ses arguments
; diffère légèrement, faites donc attention!
;
; Suppositions nécessaires :
; - Le nombre d'octets à copier sera toujours un multiple de 4.
;
; ÉCRIVEZ VOTRE CODE ICI
BX LR
;############################################################################
TrouverValeurMaximum
; Paramètres d'entrée :
; - Aucun paramètre d'entrée
;
; Valeurs de sortie :
; - R2 : index de la trame possédant le compteur le plus élevé
;
; Description :
; Cette fonction doit retourner l'index de la trame qui a été le moins
; récemment utilisée. Pour ce faire, elle doit lire le contenu de tableAcces
; et déterminer l'index de la plus GRANDE valeur. Par exemple, si tableAcces
; contient 8, 3, 5, alors cette fonction doit retourner 0x00 dans R2. Si elle
; contient plutôt 2, 7, 1, alors c'est 0x01 qui doit être retourné (la position
; du 7 dans le tableau).
;
; Suppositions nécessaires :
; - La RAM contient 3 trames (donc il y a 3 compteurs).
;
; ÉCRIVEZ VOTRE CODE ICI
BX LR
;############################################################################
ChargerPage
; Paramètres d'entrée :
; - R0 : index de la page à charger
; - R2 : index de la trame où la charger
;
; Valeurs de sortie :
; - Aucun registre modifié
; - Une copie doit être faite entre la page à charger sur le disque et la
; trame où la charger en RAM.
; - La table des pages et la table des pages inverse doivent être mises à
; jour pour refléter ce changement
;
; Description :
; Cette fonction doit copier une page à partir du disque dur dans une trame
; en mémoire vive. Elle doit également mettre à jour la table des pages et la
; table des pages inverse.
; Chaque page est stockée à l'endroit sur le disque dur correspondant à son
; numéro (index). Par exemple, la page 0 est stocké dans les premiers
; 32 octets du disque dur, la page 1 dans les 32 octets suivants, etc.
; CopieMemoire vous sera certainement utile dans cette fonction.
;
; Suppositions nécessaires :
; - Ce système utilise des pages de 32 octets.
;
; ÉCRIVEZ VOTRE CODE ICI
BX LR
;############################################################################
EvincerPage
; Paramètres d'entrée :
; - Aucun paramètre d'entrée
;
; Valeurs de sortie :
; - R2 : index de la trame à utiliser, trame qui doit préalablement avoir été
; sauvegardée sur le disque dur
; - La table des pages doit être mise à jour pour indiquer que la page qui
; occupait précédemment cette trame n'est plus en mémoire
;
; Description :
; Cette fonction doit d'abord utiliser la fonction TrouverValeurMaximum pour
; déterminer la trame ayant été accédée le moins récemment. Par la suite, elle
; doit copier cette page de la RAM vers le disque, afin de permettre son
; remplacement. Chaque page doit être stockée à l'endroit sur le disque dur
; correspondant à son numéro. Par exemple, la page 0 est stocké dans les premiers
; 32 octets du disque dur, la page 1 dans les 32 octets suivants, etc.
; Finalement, la table des pages doit être mise à jour.
; Il existe une EXCEPTION à ce comportement : si la table de pages inverse
; indique que la trame mémoire visée n'a jamais contenu une page valide jusqu'à
; maintenant (la valeur de la table de pages inverse à cet endroit est -1),
; alors il ne faut PAS essayer de copier la trame, puisque copier une zone
; mémoire non initialisée générera une erreur.
; En résumé, la copie doit être effectuée SAUF SI la table de pages inverse
; contient -1 à l'index correspondant à la trame.
; CopieMemoire vous sera certainement utile dans cette fonction.
;
; Suppositions nécessaires :
; - Ce système utilise des pages de 32 octets.
;
; ÉCRIVEZ VOTRE CODE ICI
BX LR
;############################################################################
; NE RIEN MODIFIER À PARTIR D'ICI
; TOUTES LES FONCTIONS SUBSÉQUENTES SONT DÉJÀ CODÉES POUR VOUS
AjusteCompteursAcces
; Paramètres d'entrée :
; - R2 : Numéro de la trame (frame) à laquelle on accède
;
; Valeurs de sortie :
; - Aucune valeur de sortie
;
; Description :
; Cette fonction met à jour les compteurs d'accès de chaque trame en mémoire.
; Une trame qui est accédée voit son compteur remis à 0, alors que toutes
; les autres ont leur compteur incrémenté.
;
; Suppositions nécessaires :
; Vous pouvez supposer que nous utilisons un système ne pouvant stocker que
; trois (3) pages dans sa RAM.
;
; CETTE FONCTION EST DÉJÀ CODÉE POUR VOUS!
; VOUS N'AVEZ PAS À LA MODIFIER!
;
PUSH {R3, R4, R5}
LDR R3, =tableAcces
MOV R4, #2 ; Index de la page dont on ajuste le compteur.
; On commence à la fin pour simplifer la condition de sortie de la boucle
boucleAjusteCompteursAcces
CMP R4, R2
MOVEQ R5, #0 ; Trame à laquelle on accède : on remet son compteur à 0
LDRNE R5, [R3, R4, LSL #2] ; Page non-accédée, on ajoute 1 à son compteur
ADDNE R5, R5, #1
STR R5, [R3, R4, LSL #2] ; On inscrit la nouvelle valeur en mémoire
SUBS R4, R4, #1 ; On passe à la page précédente
BPL boucleAjusteCompteursAcces ; Si on n'a pas traité toutes les pages, on continue!
POP {R3, R4, R5}
BX LR
;############################################################################
PrepareAccesMemoire
; Paramètres d'entrée :
; - R8 : Adresse VIRTUELLE à convertir vers une adresse PHYSIQUE
;
; Valeurs de sortie :
; - R3 : Adresse PHYSIQUE demandée. Cette adresse doit OBLIGATOIREMENT se situer
; à l'intérieur des limites de la variable MaRAM, soit entre
; 0x100000 et 0x10005F
;
; Description :
; Cette fonction doit retrouver l'adresse physique correspondant à une adresse
; virtuelle passée en paramètre. Cette adresse virtuelle peut correspondre à
; une page qui n'est PAS chargée en RAM, auquel cas il faut la charger!
;
; CETTE FONCTION EST DÉJÀ CODÉE POUR VOUS!
; VOUS N'AVEZ PAS À LA MODIFIER!
;
PUSH {R0-R2,LR}
; Décomposition de l'adresse en # de page (dans R0) et offset en octets
; par rapport au début de cette page (dans R1)
BL DecomposeAdresse
; Cette page est-elle présente en mémoire?
; Si oui R2 contiendra l'index en RAM de la page.
; Sinon, il contiendra -1, valeur spéciale indiquant un défaut de page
BL TrouverPage
CMP R2, #-1
BNE finPrepareAccesMemoire ; Pas de faute de page, donc on peut
; sauter directement à l'accès en RAM
BL EvincerPage ; Évincer la page utilisée depuis le plus
; longtemps, et retourner dans R2 la position
; de cette trame
BL ChargerPage ; Charger la page voulue à cet endroit
finPrepareAccesMemoire
; À cet endroit on sait que la page est présente en RAM, dans la trame R2
; et que l'offset par rapport au début de le page est R1
LDR R3, =MaRAM ; Debut de la RAM
ADD R3, R3, R2, LSL #5 ; On additionne 32 * l'index de page
ADD R3, R3, R1
BL AjusteCompteursAcces ; On met à jour les compteurs nous permettant
; de déterminer quelle page évincer
POP {R0-R2,LR}
BX LR
;############################################################################
LoadVirtuel
; Paramètres d'entrée :
; - R8 : Adresse VIRTUELLE à charger
;
; Valeurs de sortie :
; - R9 : Valeur (sur 4 octets) de la donnée à cette adresse virtuelle
;
; Description :
; Effectue l'équivalent de LDR R9, [R8], où R8 contient une adresse virtuelle
;
; Suppositions nécessaires :
; On charge toujours 4 octets
;
PUSH {LR}
BL PrepareAccesMemoire
LDR R9, [R3] ; On va chercher la valeur
POP {LR}
BX LR
;###############################################################################
StoreVirtuel
; Paramètres d'entrée :
; - R8 : Adresse VIRTUELLE à laquelle écrire
; - R9 : Valeur à y écrire
;
; Valeurs de sortie :
; - Aucune
;
; Description :
; Effectue l'équivalent de STR R9, [R8], où R8 est une adresse virtuelle
;
; Suppositions nécessaires :
; On écrit toujours sur 4 octets
;
PUSH {LR}
BL PrepareAccesMemoire
STR R9, [R3] ; On stocke la valeur
POP {LR}
BX LR
;###############################################################################
main
; Initialisation de la pile
LDR SP, =MaPile
ADD SP, SP, #200
; Ne pas effacer cette ligne: ${TEST_CORRECTION}
; DÉBUT DES TESTS
; LES LIGNES SUIVANTES SONT DES PETITS PROGRAMMES QUI TESTENT CHAQUE FONCTION
; VOUS DEVEZ VOUS ASSURER VOUS-MÊMES DE LA RÉUSSITE DE CES TESTS
; CHAQUE TEST NECESSITE QUE LES TESTS PRÉCÉDENTS SOIENT FONCTIONNELS
; Test de DecomposeAdresse
MOV R8, #196
BL DecomposeAdresse
ASSERT R0=6,R1=4
MOV R8, #0
BL DecomposeAdresse
ASSERT R0=0,R1=0
MOV R8, #88
BL DecomposeAdresse
ASSERT R0=2,R1=24
; Test de TrouverPage
LDR R0, =tableDePages
MOV R1, #1
MOV R2, #0
MOV R3, #-1
MOV R4, #-1
MOV R5, #-1
MOV R6, #2
STMIA R0, {R1-R6}
MOV R0, #0
BL TrouverPage
ASSERT R2=1
MOV R0, #1
BL TrouverPage
ASSERT R2=0
MOV R0, #5
BL TrouverPage
ASSERT R2=2
MOV R0, #4
BL TrouverPage
ASSERT R2=-1
MOV R2, #5
MOV R0, #2
BL TrouverPage
ASSERT R2=-1
MOV R1, #-1
MOV R2, #-1
MOV R3, #-1
MOV R4, #-1
MOV R5, #-1
MOV R6, #-1
LDR R0, =tableDePages
STMIA R0, {R1-R6}
; Test de TrouverValeurMaximum
LDR R0, =tableAcces
MOV R1, #5
MOV R2, #0
MOV R3, #6
STMIA R0, {R1-R3}
BL TrouverValeurMaximum
ASSERT R2=2
MOV R3, #4
STMIA R0, {R1-R3}
BL TrouverValeurMaximum
ASSERT R2=0
; Test 1 de CopieMemoire
LDR R10, =AdresseSource1
LDR R11, =AdresseDest1
MOV R12, #12
BL CopieMemoire
; >>> Le contenu de AdresseDest1 devrait être égal à celui de AdresseSource1
ASSERT 0x143C=0x12, 0x143D=0, 0x143E=0, 0x143F=0
ASSERT 0x1440=0x34, 0x1441=0, 0x1442=0, 0x1443=0
ASSERT 0x1444=0x45, 0x1445=0, 0x1446=0, 0x1447=0
ASSERT 0x1448=0xFFFFFFFF
; Test 2 de CopieMemoire
LDR R10, =AdresseSource2
LDR R11, =AdresseDest2
MOV R12, #8
BL CopieMemoire
; >>> Le contenu de AdresseDest2 devrait être égal à celui de AdresseSource2
ASSERT 0x1454=0x67, 0x1455=0, 0x1456=0, 0x1457=0
ASSERT 0x1458=0x89, 0x1459=0, 0x145A=0, 0x145B=0
ASSERT 0x145C=0xFFFFFFFF
; Test 3 de CopieMemoire
LDR R10, =AdresseSource3
LDR R11, =AdresseDest3
MOV R12, #32
BL CopieMemoire
; >>> Le contenu de AdresseDest3 devrait être égal à celui de AdresseSource3
ASSERT 0x1480=0, 0x1481=0, 0x1482=0, 0x1483=0
ASSERT 0x1484=1, 0x1485=0, 0x1486=0, 0x1487=0
ASSERT 0x1488=2, 0x1489=0, 0x148A=0, 0x148B=0
ASSERT 0x148C=3, 0x148D=0, 0x148E=0, 0x148F=0
ASSERT 0x1490=4, 0x1491=0, 0x1492=0, 0x1493=0
ASSERT 0x1494=5, 0x1495=0, 0x1496=0, 0x1497=0
ASSERT 0x1498=6, 0x1499=0, 0x149A=0, 0x149B=0
ASSERT 0x149C=7, 0x149D=0, 0x149E=0, 0x149F=0
ASSERT 0x14A0=0xFFFFFFFF
; Test 4 de CopieMemoire
LDR R10, =MonDisqueDur
MOV R1, #0
MOV R2, #0
boucleTestCopieMemoire
STR R1, [R10, R2]
ADD R2, R2, #4
CMP R2, #32
BNE boucleTestCopieMemoire
ADD R11, R10, #128
MOV R12, #32
BL CopieMemoire
; >>> Les adresses allant de 0x1160 à 0x117F devraient toutes valoir 0x00
ASSERT 0x1160=0,0x1161=0,0x1162=0,0x1163=0,0x1164=0,0x1165=0,0x1166=0,0x1167=0
ASSERT 0x1168=0,0x1169=0,0x116A=0,0x116B=0,0x116C=0,0x116D=0,0x116E=0,0x116F=0
ASSERT 0x1170=0,0x1171=0,0x1172=0,0x1173=0,0x1174=0,0x1175=0,0x1176=0,0x1177=0
ASSERT 0x1178=0,0x1179=0,0x117A=0,0x117B=0,0x117C=0,0x117D=0,0x117E=0,0x117F=0
; Test de ChargerPage
; (CopieMemoire DOIT fonctionner correctement avant de faire ce test)
MOV R0, #4
MOV R2, #2
BL ChargerPage
ASSERT 0x14=2,0x5C=4
; >>> Les adresses allant de 0x1040 à 0x105F devraient toutes valoir 0x00
ASSERT 0x1040=0,0x1041=0,0x1042=0,0x1043=0,0x1044=0,0x1045=0,0x1046=0,0x1047=0
ASSERT 0x1048=0,0x1049=0,0x104A=0,0x104B=0,0x104C=0,0x104D=0,0x104E=0,0x104F=0
ASSERT 0x1050=0,0x1051=0,0x1052=0,0x1053=0,0x1054=0,0x1055=0,0x1056=0,0x1057=0
ASSERT 0x1058=0,0x1059=0,0x105A=0,0x105B=0,0x105C=0,0x105D=0,0x105E=0,0x105F=0
MOV R0, #0
MOV R2, #0
BL ChargerPage
ASSERT 0x04=0,0x54=0
; >>> Les adresses allant de 0x1000 à 0x101F devraient toutes valoir 0x00
ASSERT 0x1000=0,0x1001=0,0x1002=0,0x1003=0,0x1004=0,0x1005=0,0x1006=0,0x1007=0
ASSERT 0x1008=0,0x1009=0,0x100A=0,0x100B=0,0x100C=0,0x100D=0,0x100E=0,0x100F=0
ASSERT 0x1010=0,0x1011=0,0x1012=0,0x1013=0,0x1014=0,0x1015=0,0x1016=0,0x1017=0
ASSERT 0x1018=0,0x1019=0,0x101A=0,0x101B=0,0x101C=0,0x101D=0,0x101E=0,0x101F=0
; Test de EvincerPage
; (TrouverValeurMaximum, CopieMemoire et ChargerPage DOIVENT fonctionner
; correctement avant de faire ce test)
; Les deux appels précédents à ChargerPage doivent avoir été exécutés
; sans erreur!
LDR R0, =MaRAM
MOV R1, #0xAA
STR R1, [R0]
STR R1, [R0, #8]
STR R1, [R0, #12]
LDR R0, =tableAcces
MOV R1, #5
MOV R2, #3
MOV R3, #4
STMIA R0, {R1-R3}
BL EvincerPage
ASSERT R2=0
ASSERT 0x10E0=0xAA,0x10E1=0x00,0x10E2=0x00,0x10E3=0x00
ASSERT 0x10E8=0xAA,0x10E9=0x00,0x10EA=0x00,0x10EB=0x00
ASSERT 0x10EC=0xAA,0x10ED=0x00,0x10EE=0x00,0x10EF=0x00
ASSERT 0x04=0xFFFFFFFF
LDR R0, =MaRAM
ADD R0, R0, #64
MOV R1, #0xBB
STR R1, [R0]
STR R1, [R0, #20]
STR R1, [R0, #28]
LDR R0, =tableAcces
MOV R1, #0
MOV R2, #7
MOV R3, #9
STMIA R0, {R1-R3}
BL EvincerPage
ASSERT R2=2
ASSERT 0x1160=0xBB,0x1161=0x00,0x1162=0x00,0x1163=0x00
ASSERT 0x1174=0xBB,0x1175=0x00,0x1176=0x00,0x1177=0x00
ASSERT 0x117C=0xBB,0x117D=0x00,0x117E=0x00,0x117F=0x00
ASSERT 0x14=0xFFFFFFFF
; Tests globaux. Ces tests sont plus complets que les précédents, car ils
; utilisent TOUTES vos fonctions (directement ou indirectement). Il est donc
; important de vous assurez que vos fonctions soient correctes individuellement
; avant de procéder aux tests suivants.
; Initialisation de la table de pages
LDR R0, =tableDePages
MOV R1, #-1
MOV R2, #0
boucleInitTablePages
STR R1, [R0, R2]
ADD R2, R2, #4
CMP R2, #80
BNE boucleInitTablePages
; Initialisation de la table de pages inversée
LDR R0, =tableDePagesInverse
MOV R1, #-1
MOV R2, #-1
MOV R3, #-1
STMIA R0, {R1-R3}
; Initialisation des compteurs
LDR R0, =tableAcces
MOV R1, #0
MOV R2, #0
MOV R3, #0
STMIA R0, {R1-R3}
; Initialisation de la mémoire virtuelle
; Chaque page mémoire se voit assigner la valeur correspondant à son index + 1
; Par exemple, la page 0 est remplie de 1, la page 1 est remplie de 2, et
; ainsi de suite
MOV R0, #1
LDR R2, =MonDisqueDur
b1
MOV R1, #32
b2
STR R0, [R2], #4
SUBS R1, R1, #4
BNE b2
ADD R0, R0, #1
CMP R0, #21
BNE b1
; Tests
MOV R8, #0x00
BL LoadVirtuel
ASSERT R9=1
MOV R8, #0x20
BL LoadVirtuel
ASSERT R9=2
MOV R8, #0x04
BL LoadVirtuel
ASSERT R9=1
MOV R8, #0x3C
BL LoadVirtuel
ASSERT R9=2
MOV R8, #0x08
MOV R9, #0xAA
BL StoreVirtuel
MOV R9, #0xBB
BL LoadVirtuel
ASSERT R9=0xAA
MOV R8, #0x40
BL LoadVirtuel
ASSERT R9=0x03
MOV R8, #0x20C
MOV R9, #0xCC
BL StoreVirtuel
MOV R8, #0xA8
BL LoadVirtuel
ASSERT R9=0x06
ASSERT 0x10E8=0xAA
MOV R8, #0x08
BL LoadVirtuel
ASSERT R9=0xAA
MOV R8, #0x110
BL LoadVirtuel
ASSERT R9=9
ASSERT 0x12EC=0xCC
MOV R8, #0x20C
BL LoadVirtuel
ASSERT R9=0xCC
; FIN DES TESTS
B main
SECTION DATA
; Espace simulant la RAM (96 octets)
MaRAM ALLOC8 96
; Espace vide (seulement utilisé pour faciliter la séparation visuelle
; entre la RAM et le disque)
EspaceVide ALLOC32 32
; Espace simulant le disque dur (640 octets)
MonDisqueDur ALLOC8 640
; Espace non initialisé (laissé volontairement vide)
Canari ALLOC32 1
; Utilisé pour sauvegarder les registres, à la discrétion du programmeur
MaPile ALLOC32 51
; Utilisé pour tester votre fonction CopieMemoire
AdresseSource1 ASSIGN32 0x12, 0x34, 0x45
AdresseDest1 ALLOC32 4
AdresseSource2 ASSIGN32 0x67, 0x89
AdresseDest2 ALLOC32 3
AdresseSource3 ASSIGN32 0, 1, 2, 3, 4, 5, 6, 7
AdresseDest3 ALLOC32 9
; Ne pas enlever cette ligne: ${TEST_DATA}