Site WWW de Laurent Bloch
Slogan du site

ISSN 2271-3905
Cliquez ici si vous voulez visiter mon autre site, orienté vers des sujets moins techniques.

Pour recevoir (au plus une fois par semaine) les nouveautés de ce site, indiquez ici votre adresse électronique :

Assembleur RISC-V : maintenant les tris !
Article mis en ligne le 31 mars 2021

par Laurent Bloch

Cet article fait suite à celui-ci et à celui-là.

Munis de la lecture et de l’écriture de nombres (à la console), ainsi que de chaînes de caractères (de longueur fixe), éventuellement dans des fichiers, nous pouvons créer des tableaux de nombres afin de nous amuser à les trier. Commençons par le tri à bulles, obligeamment procuré par Messieurs Patterson et Hennessy (au passage je salue Alfred Aho et Jeffrey Ullman, qui viennent de recevoir le prix Turing qui avait en 2017 été décerné à Hennessy et Patterson). Voici le programme principal, qui demande la saisie du tableau de nombres au clavier, appelle le programme de tri, puis affiche le résultat trié.

# Lire un tableau d’entiers, le trier, l’afficher

.globl _start  # adresse de démarrage du programme pour l’éditeur de liens

_start:

# Demander taille du tableau (< 17)
    la   a1, message1 # charger l’adresse
    jal  ra, print_str # affichage de la chaîne
# Lecture de la taille (< 17)
    jal  ra, read_int # a1 <-- l’entier lu
    la   x30, nb_items
    sw   a1, 0(x30) # sauve a1 dans nb_items
# Remplissage du tableau
    la   a0, tableau
    jal  ra, remplir
# Affichage du tableau
    la   a0, tableau
    lw   a1, nb_items
    jal  ra, afficher

# Tri du tableau
    la   a0, tableau
    lw   a1, nb_items
    jal  ra, bubble_sort

# Affichage du tableau trié
    la   a0, tableau
    lw   a1, nb_items
    jal  ra, afficher

exit:
# Fin du programme
    addi a0, x0, 0  # code de retour 0
    addi a7, x0, 93 # le code de commande 93 
    ecall           # Appel Linux pour finir

#####
# remplissage du tableau
# a0 : pointeur sur première case du tableau
# a1 : nombre de cases à remplir
remplir:
    addi sp, sp, -4
    sw   ra, 0(sp)    # sauvegarde ra sur la pile

    mv   x29, a0     # x29 -> tableau
    mv   x28, a1     # i <-- nb cases à remplir

loop2:
# Lecture d’un entier
    ble  x28, x0, exit2 # rempli
    la   a1, message2 # charger l’adresse
    jal  ra, print_str
    jal  ra, read_int  # a1 <-- l’entier lu
    sw   a1, 0(x29)   # tableau[i] <-- l’entier lu
    addi x28, x28, -1 # décrément de i
    addi x29, x29, 4  # case suivante
    j    loop2

# Retour
exit2:
# Retour chariot pour y voir clair
    la   a1, saut
    jal  ra, print_str # on y voit plus clair
    lw   ra, 0(sp)    # restauration de ra depuis la pile
    addi sp, sp,4    #  pour l’adresse de retour
    ret

#####
 # affichage du tableau
 # a0 : pointeur sur première case du tableau
 # a1 : nombre de cases à afficher
afficher:
    addi sp, sp, -4
    sw   ra, 0(sp)    # sauvegarde ra sur la pile

    addi x29, a0, 0 # x29 -> tableau
    addi x30, a1, 0 # x30 nb items à afficher
    addi x28, x0, 0 # i <-- 0

loop3:
# Affichage d’un entier
    lw   a0, 0(x29)    # a0 <-- l’entier à afficher
    jal  ra, print_int
# Retour chariot
    la   a1, saut
    jal  ra, print_str
    
    addi x28, x28, 1 # incrément indice boucle
    bge  x28, x30, exit3 # affiché
    addi x29, x29, 4 # case suivante
    j    loop3

# Retour
exit3:
# Retour chariot pour y voir clair
    la   a1, saut
    jal  ra, print_str # on y voit plus clair
    lw   ra, 0(sp)  # restauration de ra depuis la pile
    addi sp, sp,4   #  pour l’adresse de retour
    ret
#####
.include "read-print.s"
.include "strings.s"
.include "bubble-sort.s"
######

.data
.align    2
tableau:  .word    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
nb_items: .word    0
saut:     .string "\n"
message1: .string "Entrez le nombre de cases du tableau : \n"
message2: .string "Entrez un nombre entier : \n"
message3: .string "Oui, on est passé là !\n"

Et voici la procédure de tri à bulles (les autres procédures ont été publiées dans l’article précédent, cf. le lien ci-dessus).

######
 # Tri à bulles, d’après Patterson et Hennessy

bubble_sort:
    addi sp, sp, -20 # accroît la pile pour 5 registres
    sw   x1, 16(sp)  # sauve l’adresse de retour sur la pile
    sw   x22, 12(sp) # x22 sur la pile
    sw   x21, 8(sp)  # x21 sur la pile
    sw   x20, 4(sp)  # x20 sur la pile
    sw   x19, 0(sp)  # x19 sur la pile

    addi x21, x10, 0 # x21 <-- x10 v, vecteur à trier
    addi x22, x11, 0 # x22 <-- x11 n, nb de cases à trier
    addi x19, x0, 0  # i <-- 0
for1tst:
    bge  x19, x22, exit11 # si >= n exit11
    addi x20, x19, -1 # j <-- i - 1
for2tst:
    blt  x20, x0, exit12 # si j < 0 exit12
    slli x5, x20, 2  # x5 <-- j * 4
    add  x5, x21, x5 # x5 <-- v + j * 4
    lw   x6, 0(x5)   # x6 <-- v[j]
    lw   x7, 4(x5)   # x7 <-- v[j + 1]
    ble  x6, x7, exit12 # si x6 < x7 exit12
    addi x10, x21, 0 # paramètre v -> swap
    addi x11, x20, 0 # paramètre j -> swap
    jal  x1, swap    # appel swap
    addi x20, x20, -1 # j for2tst
    jal  x0, for2tst # -> for2tst
exit12:
    addi x19, x19, 1 # i <-- i+1
    jal  x0, for1tst # -> for1tst
exit11:
    add  x10, x0, x21# x10 -> tableau
    lw   x19, 0(sp)  # restaure x19
    lw   x20, 4(sp)  # restaure x20
    lw   x21, 8(sp)  # restaure x21
    lw   x22, 12(sp) # restaure x22
    lw   x1, 16(sp)  # restaure adresse de retour
    addi sp, sp, 20  # restaure pointeur de pile

    jalr x0, 0(x1)   # retour à l’appelant

######

swap:
    slli x6, x11, 2  # x6 <-- k * 4
    add  x6, x10, x6 # x6 <-- v + (k * 4)
    lw   x5, 0(x6)   # x5 <-- v[k]
    lw   x7, 4(x6)   # x7 <-- v[k + 1]
    sw   x7, 0(x6)   # v[k] <-- x7
    sw   x5, 4(x6)   # x[k + 1] <-- x5
    jalr x0, 0(x1)   # retour à l’appelant

######