![]() ![]() ![]() |
Il existe deux piles, nous étudierons seulement la pile utilisateur car je ne connais pas la pile de supervision (utilisée par le système d'exploitation) que, de toute façon, nous n'utiliserons pas.
Nous utiliserons le terme générique pile pour désigner la pile utilisateur.
La pile, d'une taille de 16 Ko (16384 octets), commence à l'adresse $000120 et fini à l'adresse $004120.
Attention il y a un point crucial à retenir, le départ de la pile est l'adresse $004120 et sa fin l'adresse $000120 !
La pile s'utilise donc à l'envers, nous y reviendrons plus tard avec un exemple concret.
Les valeurs que nous pouvons mettre dans cette pile peuvent être de toutes natures, entre autres des variables locales, paramètres, registres sauvegardés, adresses, structures…), à condition de s'y retrouver et surtout de respecter les valeurs d'autrui !
En effet tout le monde utilise la pile y compris le processeur, ainsi un programme appelant un sous-programme ne souhaite pas voir des valeurs personnelles altérées par ce dernier, sous peine de perdre les pédales voire provoquer un plantage.
Pour comprendre le fonctionnement de la pile, prenons un exemple facile.
Nous avons devant nous une table symbolisant le départ de la pile et à notre droite dix assiettes numérotées de 1 à 10.
Empilons maintenant ces assiettes dans l'ordre croissant, soit 1,2,3,4,5,6,7,8,9 puis 10.
Si nous voulons les remettre à leur place initiale, nous constatons que c'est l'assiette empilée en dernière qui doit être dépilée en première, c'est donc une structure LIFO (Last In, First Out) et ainsi de suite : 9,8,7,6,5,4,3, 2 puis 1.
C'est exactement la même chose pour la pile, sauf qu'au lieu d'empiler les valeurs vers le haut nous les empilerons vers le bas (la pile s'utilise à l'envers comme nous l'avons souligné au départ).
Par conséquent, pour empiler une valeur sur la pile nous décrémenterons son pointeur avec le mode d'adressage -(An), puis pour dépiler cette valeur nous incrémenterons le pointeur avec le mode d'adressage (An)+.
Pour accéder aux données empilées sur la pile il faut un pointeur (adresse) pointant la dernière valeur empilée.
Dans l'absolu nous pourrions utiliser n'importe quel registre d'adresse comme pointeur de pile, mais le choix de Texas Instrument s'est porté sur le registre d'adresse A7.
Il serait catastrophique de vouloir en changer car les fonctions en ROM l'utilisent !
Vous pouvez utiliser la désignation SP (Stack Pointer) au lieu d'A7 dans vos codes source, attention SP n'est pas un registre mais une manière équivalente de nommer le registre A7.
Lorsque la pile est vide ce pointeur pointe juste avant celle-ci car le mode d'adressage -(An) décrémente d'abord le registre avant d'enregistrer la valeur.
Dernier élément à connaître impérativement, l'adresse du pointeur de pile est toujours paire.
Il est impossible d'empiler un octet, le compilateur vous le fera savoir :o)
Tout ceci pour ne pas empiler ou dépiler un mot ou double mot à une adresse impaire (ce qui est impossible et provoque l'interruption d'anomalie ADRESS ERROR).
Voici un bref exemple avec une pile de 100 octets (ce qui est faux dans la réalité), supposons que celle-ci est vide :
A7 | 100 | |
98 | vide | |
96 | vide | |
94 | vide | |
92 | vide | |
90 | vide | |
... | vide | |
0 | vide |
100 | ||
98 | Première valeur déposée (double mot) | |
96 | ||
A7 | 94 | Deuxième valeur déposée (mot) |
92 | vide | |
90 | vide | |
... | vide | |
0 | vide |
100 | ||
98 | Première valeur déposée (double mot) | |
A7 | 96 | |
94 | Deuxième valeur déposée (mot) | |
92 | vide | |
90 | vide | |
... | vide | |
0 | vide |
100 | ||
98 | Registre PC déposé automatiquement par l'instruction BSR (double mot) | |
96 | ||
A7 | 94 | Registre D3 (premier mot) |
92 | vide | |
90 | vide | |
... | vide | |
0 | vide |
![]() ![]() ![]() |
SOLUTION :
empiler les registres sur la pile (les sauvegarder), utiliser la bibliothèque, puis sortir les valeurs la pile qui sont restées inchangées.
PROGRAMMATION :
MOVE.w D0,-(A7) | ; on dépose D0 dans la pile |
MOVE.w D1,-(A7) | ; on dépose D1 dans la pile |
MOVE.w D2,-(A7) | ; on dépose D2 dans la pile |
MOVE.l A0,-(A7) | ; on dépose A0 dans la pile |
JSR xlib::xfonction | ; on appel une bibliothèque (D0, D1, D2 et A0 changent) |
MOVE.l (A7)+,A0 | ; on sort la valeur de A0 |
MOVE.w (A7)+,D2 | ; on sort la valeur de D2 |
MOVE.w (A7)+,D1 | ; on sort la valeur de D1 |
MOVE.w (A7)+,D0 | ; on sort la valeur de D0 |
AVANTAGES / UTILISATION :
On n'utilise pas de variables temporaires pour sauvegarder les valeurs de D0 et D2, ce qui augmente un peu sa vitesse et réduit un peu la taille du programme.
![]() ![]() ![]() |
SOLUTION :
On utilise l'instruction MOVEM (une variante de MOVE) qui est très intéressante car elle permet, en une ligne de code, de empiler autant de registre que l'on souhaite.
Reprenons notre programme ci-dessus et raccourcissons le un peu.
PROGRAMMATION :
MOVEM D0-D2/A0,-(A7) | ; on dépose D0, D1, D2 et A0 sur la pile |
JSR xlib::xfonction | ; on appel une bibliothèque (D0, D1, D2 et A0 changent) |
MOVEM D0-D2/A0,-(A7) | ; on sort D0, D1, D2 et A0 |
![]() ![]() ![]() |
SOLUTION :
Il faut donc simuler par nous même la sortie des valeurs déposé (ici D1) en incrémentant l'adresse de la pile de la taille de la somme des valeurs que nous avons déposées.
PROGRAMMATION :
MOVE.b #0,-(A7) | ; paramètre de la hauteur de police (petite) |
JSR tios::FontSetSys | ; lance la fonction |
ADD #2,A7 | ; on restaure la pile de 2 (mot avec la pile) |
AVANTAGES / UTILISATION :
On incrémente le pointeur de la pile de 2 (mot) car nous avons déposé un mot sur la pile. Maintenant l'adresse de la prochaine instruction a exécuter est la valeur qui sera sorti la prochaine fois.
Vous pouvez tout à fait utiliser l'instruction LEA pour incrémenter le pointeur de la pile, le résultat est le même, voilà ce que ça donne pour notre exemple :
lea 2(A7),A7 ; on restaure la pile de 2 (mot)
Si vous ne connaissez pas encore cette instruction, sachez qu'elle charge une adresse dans un registre d'adresse, ici nous utilisons le mode d'adressage x(An), nous chargeons l'adresse de A7+2 dans A7 donc nous avons bien incrémenté A7 de 2.
![]() ![]() ![]() |
SOLUTION :
Nous allons utiliser l'instruction PEA qui effectue exactement le même travaille que l'instruction LEA mais au lieu de charger l'adresse dans un registre d'adresse elle le dépose sur la pile.
Il faudra là aussi restaurer la pile pour éviter le plantage, le petit piège c'est que l'adresse (pointeur) de la chaîne de caractère déposée sur la pile est un double mot (4 octets) car un pointeur est toujours définie sur 32 bits.
PROGRAMMATION :
MOVE.w #4,-(A7) | ; on dépose la couleur |
PEA bonjour(PC) | ; on dépose le pointeur de la variable bonjour |
MOVE.w #0,-(A7) | ; on dépose l'ordonnée |
MOVE.w #0,-(A7) | ; on dépose l'abscisse |
JSR tios::DrawStrXY | ; on lance la fonction |
LEA 10(A7),A7 | ; on restaure la pile de 2+4+2+2=10 |
AVANTAGES / UTILISATION :
Nous avons pu expliquer les pièges de l'instruction PEA qui dépose sur la pile un pointeur et doit être utilisé avec le registre PC (Program Counter).
Notez que l'instruction
PEA bonjour(PC)
est équivalente, par exemple, aux instructions
LEA bonjour(PC),A0
MOVE.l A0,-(A7)
![]() ![]() |
SOLUTION :
Il nous faut a tout prix garder la valeur du pointeur intacte pour retourner au programme, il y a plusieurs façons d'opérer, je propose de le sortir dans un registre d'adresse puis de le empiler à nouveau sur la pile à la fin, ainsi l'instruction RTS sortira bel et bien le pointeur voulu.
PROGRAMMATION :
; le code suivant est à mettre dans le programme | |
MOVE.w #4,-(A7) | ; on dépose un paramètre |
MOVE.l #4,-(A7) | ; on dépose un autre paramètre |
JSR SousProg | ; on saute au sous-programme |
; le code suivant est le sous-programme | |
SousProg : | ; label du départ du sous-programme |
MOVE.l (A7)+,A0 | ; on sort le pointeur de retour dans A0 ; les paramètres sont accessibles |
MOVE.l (A7)+,D0 | ; on sort le dernier paramètre dans le registre D0 |
MOVE.w (A7)+,D1 | ; on sort le premier paramètre dans le registre D1 ; les paramètres sont accessibles |
MULU D1,D0 | ; on peut par exemple effectuer une multiplication ; les paramètres sont accessibles |
LEA 6(A7),A7 | ; on restaure la pile de 4+2=6 |
MOVE.l A0,-(A7) | ; on dépose à nouveau le pointeur de retour |
RTS | ; on revient au programme |
AVANTAGES / UTILISATION :
Nous pouvons donc simuler une macro avec des paramètres, c'est un peu plus lent et surtout plus compliqué mais on peut économiser beaucoup de mémoire ainsi.
Zguide © 1998 - 1999 par Florian DREVET. Tous droits réservés