Laboratoire 8 - Routines
ASCII vers entier
Écrire la routine atoi (dans un programme atoi.s) qui prend un paramètre une chaîne de caractère représentant un entier décimal et retourne l’entier correspondant.
Note: la conversion s’arrête quand un non chiffre est rencontré. Si aucun chiffre n’est rencontré, 0 est retourné.
- Entrée:
a0adresse de la chaîne - Sortie:
a0nombre entier signé
Exemples:
.data
test1: .string "123" # atoi doit donner 123
test2: .string "toto" # atoi doit donner 0
test3: .string "42toto" # atoi doit donner 42
Somme des arguments
Écrire un programme soma.s qui fait la somme de tous les arguments de la ligne de commande en utilisant atoi pour les convertir en entier.
3 Tours de Hanoi
Implémentez la solution récursive du célèbre programme des Tours de Hanoï.
Pseudocode:
void main() {
int n = readInt();
Hanoï(n, 1, 3, 2);
}
void Hanoï(int n, int d, int a, int i) {
if (n > 0) {
Hanoï(n-1, d, i, a);
System.out.printf("Deplacer le disque de %d vers %d.\n", d, a);
Hanoï(n-1, i, a, d);
}
}
Contrainte: utilisez printf de libs.s pour l’affichage.
Si vous n’avez pas de tours de Hanoï sous la main, testez votre solution sur http://championmath.free.fr/tourhanoi.htm par exemple.
Exemple
Pour 5, cela devait donner
Deplacer le disque de 1 vers 3.
Deplacer le disque de 1 vers 2.
Deplacer le disque de 3 vers 2.
Deplacer le disque de 1 vers 3.
Deplacer le disque de 2 vers 1.
Deplacer le disque de 2 vers 3.
Deplacer le disque de 1 vers 3.
Deplacer le disque de 1 vers 2.
Deplacer le disque de 3 vers 2.
Deplacer le disque de 3 vers 1.
Deplacer le disque de 2 vers 1.
Deplacer le disque de 3 vers 2.
Deplacer le disque de 1 vers 3.
Deplacer le disque de 1 vers 2.
Deplacer le disque de 3 vers 2.
Deplacer le disque de 1 vers 3.
Deplacer le disque de 2 vers 1.
Deplacer le disque de 2 vers 3.
Deplacer le disque de 1 vers 3.
Deplacer le disque de 2 vers 1.
Deplacer le disque de 3 vers 2.
Deplacer le disque de 3 vers 1.
Deplacer le disque de 2 vers 1.
Deplacer le disque de 2 vers 3.
Deplacer le disque de 1 vers 3.
Deplacer le disque de 1 vers 2.
Deplacer le disque de 3 vers 2.
Deplacer le disque de 1 vers 3.
Deplacer le disque de 2 vers 1.
Deplacer le disque de 2 vers 3.
Deplacer le disque de 1 vers 3.
Extra: appel terminal
Il est possible de remplacer le second jal hanoi, qui est terminal (tail call) par un simple j.
Ceci nécessite d’ajouter une étiquette vers laquelle brancher (et éventuellement préparer les arguments)
Semaine 2
Majusculisation
Écrire un programme upper.s qui:
- Lit deux chaînes
str1etstr2de 80 caractères maximum (81 octets en contant le ‘\0’ final). - Les convertit en majuscules.
- Affiche la seconde chaîne puis la première.
Contraintes:
- Implémentez un routine
uppercasequi prend l’adresse d’une chaîne et la modifie pour la convertir en majuscule. - Les deux chaînes sont allouées dans les données statiques (
.data). - Utilisez
readStringetprintStringdelibs.spour lire et écrire les chaînes (et non les appels système de RARS).
Majusculisation dans la pile
- Adaptez
upper.spour allouer les deux chaînes dans la pile. - Utilisez des symboles (et
.eqv) pour identifier les deux chaînes.- Nommez le décalage dans la pile qui permet de retrouver les chaines.
Fold
Implémentez un programme fold.s qui fournit la routine fold (appelée aussi reduce dans d’autres langages).
fold ressemble à l’itérateur each vu en cours mais possède un paramètre supplémentaire.
fold applique successivement la routine passée en paramètre à chacun des éléments et retourne un résultat accumulé.
a0:tl’adresse du tableaua1:nle nombre d’éléments du tableaua2:sla taille d’un élément (en octets)a3:rl’adresse de la routine à appelera4:vune valeur initiale- retour:
a0la valeur accumulée
La routine pointée par r est appelée avec deux arguments:
a0: le résultats précédent.
Au premier appel, on utilisev, la valeur initialea1: l’adresse de l’élément courant.- retour:
a0qui sera utilisé comme premier paramètre de l’appel suivant.
Au dernier appel,a0sera retourné parfold
Pseudocode:
fold(t, n, s, r, v) {
while (n>0) {
v = r(v, t)
t += s;
n--;
}
return v;
}
Somme
.data
.eqv tlen, 10 # nombre d'éléments du tableau t
.eqv esize, 4 # taille d'un élément de t
t: .word 8, 1, 2, 10, 5, 5, -2, 2, 5, 4
.text
# somme: additionne a0 et le mot à l'adresse a1
somme:
lw a1, (a1)
add a0, a0, a1
ret
Utilisez fold pour calculer la somme des éléments du tableau.
a3doit êtresommea4doit être 0.
Minimum
Utilisez fold pour déterminer l’élément minimum de t.
- Développez la routine
minà utiliser poura3. - Note:
a4doit être la première case du tableau.
Adressage
Soit le code RISC-V 64 bits suivant:
# Appelant (programme principal)
#
# call: 0x0000000000400008
# foo: 0x0000000000400014
# sp: 0x000000007FFFEFFC
li a0, 42
li a1, -2
call:
jal foo
li a7, 10
ecall
# Appelé (routine)
foo:
# Prologue
addi sp, sp, -16
sd ra, 0(sp)
sw a0, 8(sp)
sw a1, 12(sp)
lb a2, 13(sp)
ebreak # <-- ICI
# [...]
Les adresses des étiquettes call et foo sont données, ainsi que la valeur initiale du registre sp.
Déterminez lors du ebreak (ICI):
- les valeurs des registres
raetsp(16 chiffres hexadécimaux) - les 16 octets du contenu de la pile (en commençant à l’adresse
sp) - la valeur du registre
a2(16 chiffres hexadécimaux)
Validez ensuite votre réponse avec le simulateur RARS