Initiation à lassembleur 6809
Cours n°4
L'instruction RTS est une instruction très utilisée. Elle correspond au RETURN du basic.
Nous avons vu dans le cours n°2 que S était le pointeur de pile officiel de l'ordinateur. Il est généralement défini
dès l'allumage de l'ordinateur. Il s'agit du pointeur de pile du système. Il
peut aussi être défini par l'utilisateur, mais sous de strictes conditions.
Une pile est une zone mémoire dans laquelle la valeur des registres peut être protégée. Selon les nécessités du
programmeur, certains registres peuvent être "empilés", c'est-à-dire
écrits dans cette zone puis "dépilés", c'est-à-dire récupérés à
partir de la même zone. Cette procédure est constamment utilisée lorsque l'on
doit protéger un registre utilisé dans une routine et récupérer ce registre au
sortir de la routine dans le même état qu'à l'entrée. Les termes d'"empiler" et "dépiler" se
justifient lorsque l'on sait que les registres sont écrits "vers
l'arrière" dans la pile lors de l'empilement, puis lus "vers
l'avant" lors du dépilement. Un empilement et un dépilement peuvent
toucher tous les registres sauf, évidemment, celui utilisé comme pointeur de
pile.
Imaginons que l'on veuille empiler les registres A, B et U à partir du pointeur de pile officiel S. Sous assembleur,
on écrirait alors:
PSHS U,B,A
... dont l'exécution, toutes proportions gardées, aurait l'effet suivant:
STU ,--S Ecrit U dans la pile > S=S-1:POKE S,U AND &HFF:
S=S-1:POKE S,FIX(U/256)
STB ,-S Ecrit B dans la pile > S=S-1:POKE S,B
STA ,-S Ecrit A dans la pile > S=S-1:POKE S,A
Son pendant, pour récupérer les registres empilés serait:
PULS A,B,U
... dont l'exécution aurait l'effet suivant:
LDA ,S+ Lit A dans la pile > A=PEEK(S):S=S+1
LDB ,S+ Lit B dans la pile > B=PEEK(S):S=S+1
LDU ,S++ Lit U dans la pile > U=PEEK(S)*256):S=S+1:U=U+PEEK(S):S=S+1
L'ordre d'inscription des registres derrière les instructions PSHS et PULS n'a pas d'importance. Il n'obéit ici
qu'à l'ordre d'empilement et de dépilement des registres (coquetterie de
programmeur!).
Essayez le programme suivant, pour les TO:
DEBUT LDA #$20 Charge A > A=&H20
PSHS A Empile A > S=S-1:POKE S,A
LDA #$FF Change la valeur de A > A=&HFF
PULS A Dépile A > A=PEEK(S):S=S+1
SWI Arrêt du programme > END
END - Fin du programme -
...et pour les MO:
DEBUT LDA #$20 Charge A > A=&H20
PSHS A Empile A > S=S-1:POKE S,A
LDA #$FF Change la valeur de A > A=&HFF
PULS A Dépile A > A=PEEK(S):S=S+1
STOP Arrêt du programme > END
END - Fin du programme -
En examinant les registres par la commande "R"+RETURN, vous remarquerez que le registre A a été protégé
puisquil a toujours la valeur $20 malgré le fait que sa valeur ait été changée
par $FF en cours de programme.
Revenons à notre instruction RTS (ReTurn from Subroutine) qui est censée conclure tout sous-programme. Le sous-programme est appelé par
un JSR (Jump to SubRoutine), un BSR (Branch to SubRoutine) ou un LBSR (Long
Branch to SubRoutine) selon la proximité du sous-programme suivi de l'adresse
du sous-programme. Après l'exécution de cette instruction, le registre PC (le
doigt pour la lecture [cours n°2]) est empilé puis chargé avec l'adresse du sous-programme, ce qui
fait que l'exécution saute au sous-programme. Lors de la rencontre avec le RTS, le registre PC est récupéré dans la pile et donc
l'exécution saute juste après le branchement au sous-programme dans le
programme principal. On peut dire que l'effet de RTS équivaut à l'effet de
"PULS PC". Exécutez le programme suivant:
DEBUT LDA #$20 Charge A avec $20 > 10 A=&H20
BSR SOUSPG Va au sous-programme > 20 GOSUB 50
FIN SWI Arrêt du programme > 30 END
* Remplacer SWI par STOP pour les MO
* Sous-programme > 40 REM Sous-programme
SOUSPG LDA #$FF Charge A avec $FF > 50 A=&HFF
RTS Retour au programme > 60 RETURN
END - Fin du programme -
Vous remarquerez que le nom du message de break est bien "FIN", ce qui prouve que le programme s'est bien
arrêté à cet endroit et est donc revenu du sous-programme puis, en consultant
l'état des registres par la commande "R"+RET, que A n'a pas la valeur
$20 mais bien la valeur $FF, ce qui prouve que le sous-programme a bien été
exécuté.
Si voulez faire un programme binaire tournant sous Basic, il est important de connaître l'instruction RTS: le retour
au Basic en dépend. Les registres S et DP devront être conservés dans leur état
initial pour éviter le bogue.
Concevons un programme tournant sous Basic et qui sera donc conclu par un RTS. Définissons l'origine (adresse
d'implantation) en $9000 (en $5000 pour les MO) pour pouvoir le faire tourner
en mémoire non-commutable. La directive FCC nous servira à déclarer un message
directement en ASCII et la directive FCB à marquer la fin du message par un 0.
Marquer la directive "END" avec l'étiquette "DEBUT"
définira l'adresse d'exécution du programme ce qui nous permettra de lancer ce
programme par un simple "LOADM<fichier>,,R". Assemblons-le sous
éditeur directement sur le disque en tapant dans la barre d'éditeur
"A"+<Numéro de lecteur>+":"+<Nom de fichier>
(le suffixe par défaut est "BIN"). Puis exécutons ce programme
machine assemblé sur disquette par un LOADM,,R sous Basic en n'oubliant pas le
« CLEAR,,,&H9000 » préalable (« CLEAR,,,&H5000 »
pour les MO):
ORG $9000
10 POKE &H900C,"COUCOU!"
+CHR$(0)
DEBUT LDX #MESSAG Pointe sur message > 20 X=&H9000
SUITE LDB ,X+ Récupère caractère > 30 B=PEEK(X):X=X+1
JSR $E803 Affiche caractère > 40 PRINT CHR$(B);
TSTB Teste le caractère > 50 IF B<>0 THEN 30
BNE SUITE Si <> 0, boucle
RTS Retour au basic > 60 RETURN
* Message "COUCOU!"
MESSAG FCC "COUCOU!"
FCB 0
END DEBUT - Fin du programme -
Le fichier est chargé, le message "COUCOU!" s'affiche à l'écran puis la main
est rendue au Basic (Pour les MO, remplacer « ORG $9000 » par « ORG
$5000 » et « JSR $E803 » par « CALL $02 »).
|