Compte rendu TP 5

publicité
UNIVERSITE Joseph FOURIER, Grenoble
U.F.R. d’ Informatique et Maths. Appliquées
Licence Sciences et Technologie
Parcours INM, INF, IAG, BIN
AFONSO Nicolas
VIVIEN Jonathan
MIN L2
10/03/2010
UE INF241 : Introduction aux Architectures Logicielles et
Matérielles
Feuilles de compte-rendu pour le travail pratique des séances 5 et 6: codage
des structures de contrôle
Introduction: dans la continuation de notre apprentissage en langage d'assembleur, nous allons
aujourd'hui apprendre à coder et résoudre des algorithmes en utilisant des structures de contrôle.
Vous trouverez en fin de ce compte-rendu le listing de nos programmes.
1/ Accès à un tableau
Nous commençons ce TP en travaillant sur les tableaux. On complète le fichier tableau.s afin de
réaliser les dernières affectations.
Nous rencontrons déjà un message d'erreur lorsque nous essayons de le compiler:
tableau.s: Assembler messages:
tableau.s:16: Error: invalid constant (14d) after fixup
tableau.s:24: Error: invalid constant (22b) after fixup
Ce souci vient du fait qu’on ne peut passer toutes les valeurs immédiates que l’on veut dans nos instructions
d’affectation. On pourra consulter la page 9 de la doc. Technique pour plus d’informations. Après un
changement mineur dans notre énoncé (on veut désormais affecter dans notre tableau les valeurs 11, 22,
33,44, 55), la compilation se passe sans problèmes. Attention tout de même à ne pas oublier de s’aligner sur
une adresse multiple de 4 (commande .balign 4) avant la déclaration de réservation de mémoire .skip ! Nous
avons fait cet oubli, repéré grâce au débogueur (que nous allons voir juste après) ; en résultait une non
exécution du programme jusqu’au bout.
Nous allons maintenant apprendre à nous servir du déboguer gdb, dans le but de suivre l’exécution de nos
programmes plus en détail, pas à pas.
Suivons l’exécution de notre programme tableau.s grâce à cet outil. La commande info reg nous permet de
connaître à tout moment les valeurs stockées dans tous les registres.
Regardons ce qu’on obtient en tout début de programme (aucune instruction n’a été exécutée).
info reg
r0
r1
r2
r3
r4
0x1 1
0x1ffff8 2097144
0x0 0
0xffffffff
4294967295
0x1 1
r5
r6
r7
r8
r9
r10
r11
r12
sp
lr
pc
fps
cpsr
0x1ffff8 2097144
0x0 0
0x0 0
0x0 0
0x0 0
0x200100 2097408
0x0 0
0x1fffe8 2097128
0x1ffff8 0x1ffff8
0x81fc 33276
0x8218 0x8218 <main>
0x0 0
0x40000013
1073741843
Aucune valeur particulière, nous sommes d’accord. Si maintenant nous réutilisons cette commande après
avoir exécuté les trois premières instructions du programme (on les rappelle) :
ldr r0, ptr_debutTAB @ on charge dans r0 l'adresse de la première case
mov r1, #11
@ r1 <- 11
str r1, [r0] @ on sauvegarde dans la case courante du tableau la valeur de r1
info reg
r0
r1
r2
r3
r4
r5
r6
r7
r8
r9
r10
r11
r12
sp
lr
pc
fps
cpsr
0x12ec0 77504
0xb 11
0x0 0
0xffffffff
4294967295
0x1 1
0x1ffff8 2097144
0x0 0
0x0 0
0x0 0
0x0 0
0x200100 2097408
0x0 0
0x1fffe8 2097128
0x1ffff8 0x1ffff8
0x81fc 33276
0x8224 0x8224 <main+12>
0x0 0
0x40000013
1073741843
On constate que notre programme fonctionne bien : on a chargé dans r0 l’adresse de la première case de
notre tableau et la valeur 11 dans r1.
On peut donc pour finir l’analyse de ce premier programme noter les valeurs successives de r0 :
77504, 77508, 77512, 77516, 77520.
De même pour le contenu de la mémoire à partir de l’adresse debutTAB en début de programme et après
l’exécution de toutes les instructions (on utilise la commande x/5w &debutTAB) :
x/5w &debutTAB
0x12ec0 <debutTAB>: 0x0000000b
0x00000016
0x12ed0 <debutTAB+16>: 0x00000037
0x00000021
0x0000002c
On retrouve l’adresse de la première case du tableau (débutTAB) : 0x12ec0, 0x0000000b en hexadécimal est
bien égal à 11 en décimal, 0x00000016 = 22, 0x00000021 = 33, 0x0000002c = 4. La dernière case du tableau
quand à elle contient bien la valeur 55 (codé en hexadécimal par 0x00000037) et est bien à l’adresse
0x12ed0 (soit debutTAB +16).
2/ Codage d’une itération
Regardons maintenant comment procéder pour coder une itération. On veut créer un programme ayant le
même résultat que précédemment, mais cette fois-ci nous voulons utiliser une itération pour être bien plus
efficace (imaginez donc devoir affecter 500 cases de tableau, à 3 instructions par affectation, il nous faudrait
taper au minimum 1 500 lignes de code !).
Ce programme est déjà réalisé, c’est le fichier iteration.s. Grâce à gdb, regardons quelles sont les valeurs
contenues à chaque itération dans les registres r0 et r2:
r0: ce registre doit contenir, d'après l'algorithme donné, l'adresse courante de la case de notre tableau que l’on
souhaite affecter. r0 prend pour valeurs successives : 77484 (debut_TAB+0*4), 77488 (debut_TAB +1*4),
77492 debut_TAB + 2*4), 77496 (debut_TAB + 3*4), 77500 ( debut_TAB + 4*4)
r2: ce registre doit contenir, d'après l'algorithme donné, la variable d’incrémentation. r2 prend pour valeurs
successives : 0, 1, 2, 3, 4, 5
La valeur contenue dans r2 à la fin de l’itération, c’est-à-dire lorsque le contrôle est à l’étiquette fintq est
donc 5 (normal car on veut réaliser 5 fois notre affectation).
Supposons maintenant que l’algorithme soit écrit avec tant que i <= 4 au lieu de tant que i <> 5. Le tableau
contiendra les mêmes valeurs à la fin de l’itération ! En effet dans cette deuxième version on va bien réaliser
5 fois notre affectation : pour i=0, 1, 2, 3, 4. Exactement comme dans notre premier algorithme. On décide de
coder avec le nouvel algorithme jusqu’à la fin de cette partie.
Supposons que le tableau soit maintenant un tableau de mots de 16 bits. On modifie le programme qui
devient iteration2.s (voir partie listing). Il nous suffit juste de prendre en compte que chaque case de notre
tableau ne fait plus que 2octets (car 16bits = 2octets) : on réserve donc moins de place en mémoire en début
de programme, on ne multiplie i que par 2 à chaque itération.
Même chose pour un tableau d’octets. Dans ce cas, chaque case ne fait plus qu’un seul octet. Voir le
programme iteration3.s
3/ Calcul de la suite de “Syracuse”
On désire désormais dans cette troisième partie créer un programme en assembleur qui nous calcule les n
premiers termes de la suite de Syracuse.
Donnons pour commencer les valeurs de la suite de Syracuse pour U0 = 15, calculées à la main: U0=15,
U1= 46, U2=23, U3= 70, U4=35, U5= 106, U6= 53,U7= 160, U8= 80, U9= 40, U10= 20, U11= 10, U12=5
U13= 16, U14= 8, U15= 4, U16= 2, U17=1, U18=4, U19=2, etc... On remarque que cette suite converge vers
1 avec un cycle de 3.
Pour coder ce programme il nous a fallu tout simplement suivre l’algorithme et les indications fournies dans
le poly (trop facile). On se limitera à calculer les 50 premiers termes de cette suite.
On vérifie sous gdb le bon déroulement de notre programme :
r4 : ce registre va nous servir de compteur du rang de la suite. r4 prend pour valeur successives : 0, 1, 2, 3, 4,
5, ….. 17. On a bien retrouvé que notre suite converge vers 1 à partir du 17ème terme.
r0 : ce registre contient à l’initialisation du programme la valeur qu’on attribue au premier terme (U0) de la
suite (ici 15). r0 est ensuite modifié selon l’algorithme de notre programme. C’est donc la valeur courante de
la suite. r0 prend bien pour valeurs successives les mêmes nombres que l’on a calculé à la main un peu plus
haut : 15, 46, 23, 70, …..,1
r3 : ce registre va nous servir de comparaison. On continue notre boucle tant que la valeur courante de la
suite (contenue dans r0) est différente de 1. r3 contient la valeur 1 et n’est pas modifié durant l’exécution du
programme.
La vérification sous gdb nous à permis de vérifier le bon fonctionnement de notre programme. Nous
réaliserons dans la dernière partie de ce TP un autre programme qui calculera des valeurs de suite, mais nous
utiliserons les fonctions d’affichage, ce qui nous permettra de vérifier l’exactitude de notre programme sans
utiliser gdb et taper à maintes et maintes reprises -s (la commande sous gdb pour passer à l’instruction
suivante). Passons maintenant au gros programme de ce TP…
4/ Tables de multiplication
On souhaite désormais réaliser un programme qui affiche un tableau avec les tables de multiplication de 1 à
10 suivant l'exemple donné dans le polycopié.
Pour réaliser celui-ci il nous faudra utiliser deux boucles itératives imbriquées ( une pour le parcours des
lignes et une autre pour celui des colonnes ).
En s'inspirant de l'algorithme donné en page 5 du polycopié et en travaillant avec méthode ( utilisation de
nombreuses étiquettes, de schémas pour s'y retrouver ), la réalisation ne nous à pas trop donné de problèmes.
Nous avons essayé de détailler aux maximum, par des commentaires, notre programme ( voir partie listing ).
Pour l'affichage nous avons dû jouer entre les EcrChn et EcrChaine (problème relaté avec plus de précisions
au programme suivant). A l'exécution de celui-ci on obtient bien le résultat recherché:
arm-elf-run tabmult
| 1| 2| 3| 4| 5| 6| 7| 8| 9| 10|
|---|---|---|---|---|---|---|---|---|---|
| 2| 4| 6| 8| 10| 12| 14| 16| 18| 20|
|---|---|---|---|---|---|---|---|---|---|
| 3| 6| 9| 12| 15| 18| 21| 24| 27| 30|
|---|---|---|---|---|---|---|---|---|---|
| 4| 8| 12| 16| 20| 24| 28| 32| 36| 40|
|---|---|---|---|---|---|---|---|---|---|
| 5| 10| 15| 20| 25| 30| 35| 40| 45| 50|
|---|---|---|---|---|---|---|---|---|---|
| 6| 12| 18| 24| 30| 36| 42| 48| 54| 60|
|---|---|---|---|---|---|---|---|---|---|
| 7| 14| 21| 28| 35| 42| 49| 56| 63| 70|
|---|---|---|---|---|---|---|---|---|---|
| 8| 16| 24| 32| 40| 48| 56| 64| 72| 80|
|---|---|---|---|---|---|---|---|---|---|
| 9| 18| 27| 36| 45| 54| 63| 72| 81| 90|
|---|---|---|---|---|---|---|---|---|---|
| 10| 20| 30| 40| 50| 60| 70| 80| 90|100|
|---|---|---|---|---|---|---|---|---|---|
Victoire !
5/ Calcul des nombres de la suite de Fibonacci
Pour finir ce TP, nous allons créer un programme qui va nous permettre de calculer les n premiers termes de
la suite de Fibonacci. Pour nous guider, on nous fournit un programme fibonacci.c (donc en langage c) sur
lequel nous devons nous appuyer pour réaliser notre programme homologue en langage d'assemblage ARM.
Le principe de réalisation va être d'utiliser des itérations, et de conserver les valeurs déjà calculées dans un
tableau.
Vérifions tout d'abord que le programme « modèle » fibonacci.c fonctionne bien. L'exécution de celui-ci
nous donne:
./fib
indice = 0, valeur = 0
indice = 1, valeur = 1
indice = 2, valeur = 1
indice = 3, valeur = 2
indice = 4, valeur = 3
indice = 5, valeur = 5
indice = 6, valeur = 8
indice = 7, valeur = 13
indice = 8, valeur = 21
indice = 9, valeur = 34
indice = 10, valeur = 55
indice = 11, valeur = 89
indice = 12, valeur = 144
indice = 13, valeur = 233
indice = 14, valeur = 377
indice = 15, valeur = 610
indice = 16, valeur = 987
indice = 17, valeur = 1597
indice = 18, valeur = 2584
indice = 19, valeur = 4181
indice = 20, valeur = 6765
indice = 21, valeur = 10946
indice = 22, valeur = 17711
indice = 23, valeur = 28657
indice = 24, valeur = 46368
indice = 25, valeur = 75025
indice = 26, valeur = 121393
indice = 27, valeur = 196418
indice = 28, valeur = 317811
indice = 29, valeur = 514229
indice = 30, valeur = 832040
indice = 31, valeur = 1346269
indice = 32, valeur = 2178309
indice = 33, valeur = 3524578
indice = 34, valeur = 5702887
indice = 35, valeur = 9227465
indice = 36, valeur = 14930352
indice = 37, valeur = 24157817
indice = 38, valeur = 39088169
indice = 39, valeur = 63245986
indice = 40, valeur = 102334155
indice = 41, valeur = 165580141
indice = 42, valeur = 267914296
indice = 43, valeur = 433494437
indice = 44, valeur = 701408733
indice = 45, valeur = 1134903170
indice = 46, valeur = 1836311903
indice = 47, valeur = 2971215073
indice = 48, valeur = 512559680
indice = 49, valeur = 3483774753
Après quelques calculs à la main, nous confirmons que ce programme calcule les valeurs correctes des 50
premiers termes de la suite de Fibonacci.
On réalise notre programme (voir partie listing) et vérifions à son tour qu'il nous retourne des
valeurs correctes:
arm-elf-run fibonacci
indice = 0, valeur = 0
indice = 1, valeur = 1
indice = 2, valeur = 1
indice = 3, valeur = 2
indice = 4, valeur = 3
indice = 5, valeur = 5
indice = 6, valeur = 8
indice = 7, valeur = 13
indice = 8, valeur = 21
indice = 9, valeur = 34
indice = 10, valeur = 55
indice = 11, valeur = 89
indice = 12, valeur = 144
indice = 13, valeur = 233
indice = 14, valeur = 377
indice = 15, valeur = 610
indice = 16, valeur = 987
indice = 17, valeur = 1597
indice = 18, valeur = 2584
indice = 19, valeur = 4181
indice = 20, valeur = 6765
indice = 21, valeur = 10946
indice = 22, valeur = 17711
indice = 23, valeur = 28657
indice = 24, valeur = 46368
indice = 25, valeur = 75025
indice = 26, valeur = 121393
indice = 27, valeur = 196418
indice = 28, valeur = 317811
indice = 29, valeur = 514229
indice = 30, valeur = 832040
indice = 31, valeur = 1346269
indice = 32, valeur = 2178309
indice = 33, valeur = 3524578
indice = 34, valeur = 5702887
indice = 35, valeur = 9227465
indice = 36, valeur = 14930352
indice = 37, valeur = 24157817
indice = 38, valeur = 39088169
indice = 39, valeur = 63245986
indice = 40, valeur = 102334155
indice = 41, valeur = 165580141
indice = 42, valeur = 267914296
indice = 43, valeur = 433494437
indice = 44, valeur = 701408733
indice = 45, valeur = 1134903170
indice = 46, valeur = 1836311903
indice = 47, valeur = 2971215073
indice = 48, valeur = 512559680
indice = 49, valeur = 3483774753
Nous avons donc bien réalisé ce programme. Il nous a fallu cependant faire attention à bien
jongler dans l'utilisation de EcrNdecim32, EcrNdecimal32, EcrChn et EcrChaine si l'on veux obtenir
exactement la même présentation qu'avec le programme en langage c ( EcrNdecim32 et EcrChn
ne font pas un retour à la ligne après l'affichage alors que les deux autres instructions oui ). Pour
conclure avec ce programme on aurait pu l'optimiser quelque peu en ne réalisant qu'une seule
boucle où calcul des valeurs de la suite et affichage de ceux-ci sont mêlés ( un peu comme dans
notre programme des tables de multiplication précédant ).
Conclusion: Nous avons manipulé aujourd'hui bon nombre d'itérations (voir même d'itérations
imbriquées), ainsi que plus généralement des structures de contrôle, ce qui nous a permis de
maîtriser cet outil important de la programmation. Ce TP nous à également permis de remanier
tous nos acquis en langage d'assemblage ARM accumulés jusqu'ici. Nous attendons maintenant
impatiemment le prochain TP où nous pourrons enfin apprendre à coder des fonctions...
Téléchargement