Appendix C ASM : le manuel de référence

publicité
Appendix C
ASM : le manuel de référence
C.1
Présentation d’asm
Le logiciel asm est un mini assembleur susceptible de générer du code pour
la machine virtuelle simplifiée mac. Ce code "objet" peut être exécuté, sous
contrôle d’un metteur au point, sur le simulateur de cette machine, sim.
C.2
Spécifications du logiciel asm
Il lit ses entrées sur stdin, génère le code, sous forme symbolique, sur stdout, et
signale les erreurs sur stderr. Sous UNIX, il est mis en oeuvre par la commande
asm. Le code fourni est compatible avec les entrées attendues par le logiciel
sim, et il est possible d’écrire :
asm < toto.asm | sim
pour assembler et exécuter immédiatement le programme.
C.3
Format des instructions
Le format général des instructions acceptées par asm est le suivant :
[ étiquette : ] [ code-opération [ opérande ] ] <fin-de-ligne>
Une fin de ligne étant le caractère CR (et/ou LF), ou un commentaire débutant
par le caractère * et se terminant par CR (et/ou LF). Ex:
boucle:
ld.l
r4,tab(r2)
85
* Element suivant
86
APPENDIX C. ASM : LE MANUEL DE RÉFÉRENCE
Le format est libre, un blanc devant séparer le code-opération de l’opérande.
L’assembleur ne tient pas compte de la casse (majuscule ou minuscule) des lettres.
L’étiquette est un identificateur alphanumérique, c’est-à-dire une suite de
lettres et de chiffres débutant par une lettre.
Le code-opération peut éventuellement être suivi de .L pour préciser que
le format de l’instruction est long. Dans la plupart des cas, cette précision est
inutile.
Les constantes, sur 16 bits, peuvent s’exprimer sous forme décimale (235),
hexadécimale (0xa30c), binaire (0b1111000000110101) ou caractère (’xy’).
Les opérandes acceptés correspondent à la syntaxe suivante :
registre R0 à R15
registre, registre
registre, constante
registre, identificateur
registre, identificateur(registre)
registre,(registre)
identificateur
identificateur(registre)
constante
constante, constante
ex:
ex:
ex:
ex:
ex:
ex:
ex:
ex:
ex:
ex:
R12
R2,R4
R5,3
R8,total
R6,table(R2)
R4,(R7)
suite
table(R2)
0x2fc3
’c’,0
Dans la quasi-totalité des cas, il est nécessaire d’utiliser le préfixe "#" devant
une constante pour indiquer une opération immédiate :
LD.L R2,0x3f4 Le registre R2 reçoit le contenu du mot mémoire d’adresse
0x3f4.
LD.L R2,#0x3f4 Le registre R2 reçoit la valeur hexadécimale 0x3f4.
Le suffixe .L indique que l’opération est une instruction longue (sur 4 octets) :
LD R2,#12 Le registre R2 reçoit la valeur 12 car l’instruction créée est
0x012C.
LD.L R2,#0x3f4 Le registre R2 reçoit la valeur 0x3f4 car l’instruction créée
est 0x812003f4.
LD R2,#0x3f4 L’assembleur ne peut générer une constante courte : il assemble l’instruction au format long comme ci-dessus.
LD.L R2,#12 Le registre R2 reçoit la valeur décimale 12, mais l’instruction
est explicitement créée au format long : 0x8120000C.
C.3. FORMAT DES INSTRUCTIONS
87
C.3.1 Directives de l’assembleur
ORG {origin}
Syntaxe :
ORG constante
Indique que les instructions seront implémentées à partir de l’adresse précisée par la constante. ex:
ORG 0x200
L’adresse précisée est une adresse d’octet. Elle doit être paire.
BSS {Block Started by Symbol}
Syntaxe :
BSS constante
Réserve à l’adresse courante une zone de mémoire de taille égale à la
valeur de la constante. Cette valeur est un nombre d’octets.
DATA
Syntaxe :
DATA constante
Définit à l’adresse courante une constante de type mot [16 bits]. La constante peut éventuellement s’exprimer sous la forme d’un couple de deux
constantes 8 bits, séparées par une virgule, et représentant les octets de
poids fort et de poids faible du mot à créer.
START
Syntaxe :
START étiquette
Définit le point d’entrée du programme (adresse de la première adresse à
exécuter).
88
APPENDIX C. ASM : LE MANUEL DE RÉFÉRENCE
C.3.2 Instructions de l’assembleur
L’assembleur reconnaît toutes les instructions décrites dans la documentation
relative à la machine. Il offre une souplesse (limitée) sur les points suivants :
Quand une instruction nécessite manifestement un format "long", alors
que ".L" n’a pas été précisé comme suffixe de l’opération, il considère que
le format long est implicite. C’est le cas d’instructions telles que :
add r3,#2f1
ld r5,toto
pour lesquelles un format court ferait perdre une partie du sens (premier
cas, constante réduite à "1"), ou ne permettrait pas un assemblage correct
de l’instruction (second cas).
Les instructions push, pop, jsr et ret font référence explicitement à
un registre de pile. Si ce registre n’est pas précisé dans l’instruction,
l’assembleur considérera qu’il s’agit du registre 15, et générera le code
en conséquence.
L’instruction trap permet de préciser un niveau et un sous-niveau
d’interruption, sous la forme de deux constantes séparées par une virgule.
Si une seule constante est spécifiée, l’assembleur considérera qu’il s’agit
du sous-niveau, et utilisera 13 comme niveau, correspondant aux "appels
du superviseur".
Signalons enfin que l’assembleur transmet en sortie les commentaires
débutant par trois astérisques. De tels commentaires sont reconnus
comme des ordres d’impression par le simulateur, et permettent ainsi de
documenter du code source et du code objet.
C.3.3 Format du code objet
L’assembleur génère un code objet "absolu" (c’est à dire qu’il doit être chargé à
une adresse précise de la mémoire). Ce code est composé de directives destinées
au simulateur, consistant en une succession de directive /addr pour spécifier
une adresse de chargement suivie d’une directive /w pour indiquer la valeur
d’un ou de plusieurs mots devant chargés en mémoire à partir de l’adresse indiquée. Si une directive start a été utilisée dans le programme, l’assembleur
générera une commande /run pour le simulateur.
C.4. EXEMPLES
C.4
89
Exemples
C.4.1 Calcul de PGCD
Le programme ci-dessous reprend un exemple donné en cours : le calcul du
PGCD de deux nombres.
*** PGCD
pgcd:
suite:
fin:
*
main:
org
cmp
jeq
jlt
ld
ld
ld
sub
jmp
ret
0x1000
r2,r3
fin
suite
r0,r3
r3,r2
r2,r0
r3,r2
pgcd
r15
la.l
r15,pile
ld.l
r2,#1144
ld.l
r3,#858
jsr
r15,pgcd
ld.l
r3,#1287
jsr
r15,pgcd
* Pour avoir un resultat
ld
r0,r2
trap
3
trap
2
*** Resultat attendu : 143
halt
bss
16
pile:
bss
0
start
main
Quelques remarques sur cet exemple :
Le programme définit explicitement une zone attribuée à la pile, de taille
16 (instruction bss 16). Comme la pile opère "en remontant" vers les adresses
basses, la valeur affectée au registre désignant la pile doit être celle de la fin
de la zone. Ici, cette adresse est obtenue en plaçant l’étiquette après la déclaration de la zone de 16 octet. Cette étiquette est associée à la déclaration d’un
bloc de taille zéro, mais le même effet aurait été obtenu en plaçant simplement
l’étiquette seule dans sa ligne.
APPENDIX C. ASM : LE MANUEL DE RÉFÉRENCE
90
Le programme, pour calculer le pgcd des trois nombres 1144, 858 et 1287,
effectue deux appels successifs au sous-programme PGCD. Le résultat du premier appel (le pgcd de 1144 et 858) se retrouve dans R2 et R3 à la sortie du
sous-programme. Il suffit donc, pour le second appel, de placer la valeur du
troisième nombre dans l’un des registres R2 ou R3.
Le code objet généré par l’assembleur pour l’exemple ci-dessus est le suivant :
*** PGCD *** Resultat attendu : 143
/addr 1000
/w 2523 8f10 1016 8f40 1010 2103 2132 2120 2432 8f00
/w 1000 1cf0 abf0 1048 8120 0478 8130 035a 8cf0 1000
/w 8130 0507 8cf0 1000 2102 1ad3 1ad2 1e00
/run 1018
C.4.2 Édition d’un nombre sous forme d’une chaîne de caractères
Bien qu’il existe une méthode pour imprimer un nombre sous forme décimale (la trappe 13,3), le programme suivant se propose de créer une chaîne de
caractères, terminée selon les conventions du langage C par un octet de valeur
0, contenant la représentation décimale du nombre. Voici le sous-programme
edit, réalisant cette opération, et le programme principal faisant appel à ce
sous-programme pour éditer le nombre 9237.
Quelques remarques préliminaires :
– Une chaîne de caractères est constituée d’une suite d’octets non nuls, terminée par un octet de valeur 0.
– Il s’agit ici de créer la représentation décimale d’un nombre, 9237 en l’occurrence. Cette représentation va s’effectuer par l’intermédiaire de caractères du code ASCII, représentant les chiffres décimaux successifs du
nombre. On notera que ces caractères, les chiffres allant de 0 à 9, sont
représentés par les codes consécutifs du code ASCII, ’0’ (valeur hexadécimale 0x30, valeur décimale 48, valeur binaire $00110000) à ’9’ (valeur
hexadécimale 0x39, valeur décimale 57, valeur binaire $00111001). Pour
un nombre compris entre 0 et 9, on obtient donc, de manière très simple, le
code ASCII du chiffre correspondant en ajoutant la valeur 48 à ce nombre.
*
*
*
*
edit:
Édition d’un nombre sous forme
de chaine de caracteres
cmp
r2,#0
C.4. EXEMPLES
*
next:
*
zero:
fin:
jeq
zero
jge
next
Le nombre est négatif
ldb.l
r0,#’-’
stb
r0,(r3)
add
r3,#1
neg
r2
push
r4
ld
r4,#10
jsr
subedit
pop
r4
jmp
fin
Le nombre est nul
ldb.l
r0,#’0’
stb
r0,(r3)
add
r3,#1
ldb.l
r0,#0
stb
r0,(r3)
ret
*
* Sous-programme d’édition du car. suivant
*
subedit:
ld
r0,#0
ld
r1,r2
div
r4
add.l
r1,#’0’
ld
r2,r0
jeq
sub1
push
r1
jsr
subedit
pop
r1
sub1:
stb
r1,(r3)
add
r3,#1
ret
*
*
Programme principal
*
début:
ld.l
r2,#9237
la
r3,str
jsr
edit
la
r0,str
91
92
APPENDIX C. ASM : LE MANUEL DE RÉFÉRENCE
trap
trap
trap
str:
bss
start
*** Resultat : 9237
1
*
2
*
0
*
10
début
Impression de chaine
Impression de "\n"
Arrêt
Le code généré par l’assembleur est le suivant :
*** Resultat : 9237
/addr 0000
/w 0520 8f10 0022 8f50
/w 2df4 014a 8cf0 0032
/w 0331 8200 0000 4a03
/w 2120 8f10 004a 2df1
/w 8120 2415 ab30 0066
/w 1ad0
/run 0050
0014
2ef4
1cf0
8cf0
8cf0
8200
8f00
0100
0032
0000
002d
002a
2112
2ef1
ab00
4a03
8200
1940
4a13
0066
0331
0030
8310
0331
1ad1
1620
4a03
0030
1cf0
1ad2
et son exécution fournit :
*** Resultat : 9237
9237
*** Arret du programme par TRAP 13,0
psw = ...P...Z 1100 0066
*** SIM/CPU - 63 insts. 1815 ticks.
Remarque Bien que le programme ci-dessus fasse appel à la pile (puisqu’il
utilise des sous-programmes, empile des valeurs), le registre r15 n’a pas été
initialisé par le programmeur. En effet, le simulateur initialise tous les registres, donc r15, avec la valeur 0. Lors de l’utilisation de r15 pour empiler
des valeurs (par push) ou des adresses de retour (par jsr), r15 va désigner
les adresses successives 0xfffe, 0xfffc, 0xfffa, etc, et référencer ainsi les
derniers mots de la mémoire. Ceux-ci sont inutilisés (puisque le programme est
chargé en début de mémoire), et peuvent donc être employés sans inconvénient
pour représenter la pile d’exécution.
Téléchargement