Projet Pratique de INF241 Parcours de Tableaux L objectif de ce projet est de travailler sur les tableaux en langage d assemblage ARM. Vous devez réaliser votre projet en partie lors des séances encadrées destinées au projet, en partie en dehors de ces séances. Le projet devra être soutenu la semaine du 04/05 par une présentation devant l enseignant. La résolution des problèmes de ce sujet, la validation de vos solutions, la qualité et la structure de votre présentation seront notées aussi bien que la participation des deux étudiants du binôme. 1 Tables de multiplications Les tables de multiplication de 1 à 10 peuvent être représentées par la figure 1. L objectif du projet est de réaliser un programme en ARM qui remplit un tableau en mémoire et qui l affiche à l écran comme sur cette figure 1. Le remplissage du tableau doit être réalisé de façon itérative, suivant l algorithme : //Remplissage d un tableau des multiplications de 1 à 10 //table[n-1,m-1] = n*m pour n et m compris entre 1 et 10. N_MAX : l entier 10 Ligne : le type tableau sur [0..N_MAX-1] d entiers table : le tableau sur [0..N_MAX-1] de Ligne n_lig,n_col : deux entiers relatifs pour n_lig parcourant [1..N_MAX] : pour n_col parcourant [1..N_MAX] : // produit de n_col par n_lig table[n_lig-1][n_col-1] <-- n_lig * n_col; Organisation du travail Vous devez écrire deux blocs de codes distincts qui seront exécutés en séquence : 1. le premier initialise (remplit) un tableau en mémoire 2. le second affiche à l écran le contenu du tableau stocké en mémoire 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 Figure 1 Tables de multiplication de 1 à 10 1
Le squelette du programme à compléter est donné en section 6. Il est fortement recommandé de ne tester qu un bloc de code à la fois : affichage puis remplissage ou remplissage puis affichage, et ensuite fusionner les codes. 2 Affichage du tableau L algorithme ci-dessous permet de réaliser la partie de programme ARM qui affichera le tableau conformément à la figure 1, une fois celui-ci rempli. Les fonctions d entrée/sortie suivantes sont utilisées : ecrire_car(c) : affiche sans retour à la ligne le caractère de code ascii c. ecrire_chn(s) : affiche sans retour à la ligne la chaine de caractères s. a_la_ligne() : provoque un retour à la ligne La manière d afficher un entier en format fixe cadré à droite est expliquée en annexe. N_MAX : l entier 10 ESPACE : le caractère // espace : code ascii 32 BARRE : le caractère // : code ascii 124 TIRETS : la chaîne "---" // - : code ascii 45 Ligne : le type tableau sur [0..N_MAX-1] d entiers table : le tableau sur [0..N_MAX-1] de Ligne n_lig,n_col : deux entiers naturels mult : un entier pour n_lig parcourant [0..N_MAX-1] : pour n_col parcourant [0..N_MAX-1] : mult <-- table[n_lig][n_col]; ecrire_int_cadré_à_droite(mult); a_la_ligne(); répéter N_MAX fois : ecrire_chn(tirets); a_la_ligne(); 1. Traduisez en langage d assemblage ARM cet algorithme en complétant la partie d affichage du code de la section 6. Utilisez si possible des conditions de terminaison des boucles parcourant de type (<,, >, ) plutôt que de simples tests d égalité basés uniquement sur l indicateur Z. Pour la traduction des fonctions d entrées-sorties utiliser les fonctions suivantes définies dans le fichier es.s : EcrChn pour implémenter ecrire_car et ecrire_chn. Pour écrire un caractère sans retour à la ligne déclarer le caractère comme chaîne. AlaLigne pour implémenter a_la_ligne. 2. Testez cette partie sans l algorithme de remplissage de table (valeur initiale des éléments de table nulle par défaut), pour afficher la même figure que 1, mais avec 0 dans toutes les cases. 3 Remplissage du tableau Traduisez en langage d assemblage ARM l algorithme de remplissage du tableau donné dans la section 1. 2
Dans un premier temps, gardez telle quelle l écriture de l accès à un élément du tableau (table[n_lig][n_col]). Pour réaliser la multiplication de deux entiers positifs vous ne devez pas utiliser d instruction mul, mais une boucle de sommation. L algorithme le plus simple (mais lent) est le suivant : mult, a et b : trois entiers positifs ou nuls mult <-- 0; répéter a fois : mult <-- mult + b; 3.1 Codage d un tableau à 2 dimensions Pour stocker le tableau à 2 dimensions, il faudra le traiter comme un tableau à une dimension en rangeant les lignes du tableau les unes après les autres. Chaque ligne est une suite de cases contenant chacune un élément du tableau. Par exemple, un tableau avec 4 lignes et 6 colonnes sera stocké comme un tableau à une seule dimension de 4 * 6 = 24 cases. e00 e01 e02 e03 e04 e05 e10 e11 e12 e13 e14 e15 e20 e21 e22 e23 e24 e25 e30 e31 e32 e33 e34 e35 tableau : e00 e01 e02 e03 e04 e05 e10 e11... e35 1. En définissant table comme l adresse de début du tableau (i.e. du premier élément), exprimez la formule qui donne l adresse de table[x][y] en fonction de table, x et y. 2. Vous devez alors traduire en langage d assemblage ARM la ligne correspondant à table[x][y] < valeur, c est-à-dire le calcul d adresse puis l écriture de la valeur en mémoire. 3.2 Codage du programme de génération de la table de multiplication (version 1) En rassemblant les différents algorithmes que vous avez traduits, vous avez maintenant une version complète et vous pouvez finaliser le code de la section 6, le compiler, l exécuter et vérifier vos résultats. Pour vérifier que votre tableau est correctement rempli, vous pouvez utiliser gbd ou ddd pour afficher le contenu de la mémoire à l adresse debuttab. Vous pouvez aussi utiliser la partie d affichage si celle-ci a été complètement testée. Attention, dans le cas où votre affichage aurait été insuffisament testé, vous n êtes pas à l abri des effets d un bug de cette partie. 3.3 Codage du programme de génération de la table de multiplication (version 2) Pour remplir le tableau à 2 dimensions, on pourrait aussi le parcourir comme un tableau à une dimension, du début à la fin, en utilisant une seule boucle. L algorithme de remplissage du tableau peut alors être récrit sans utiliser des multiplications. 1. Ecrivez la nouvelle forme de l algorithme complet. 2. Traduisez cette version en langage d assemblage ARM. Reprenez la version initiale du code de la section 1, complétez-le avec la traduction de votre algorithme. 3. Compilez votre programme, exécutez le et vérifiez vos résultats. 3
Les plus aguerris d entre vous pourront 1. accéder aux éléments du tableau via un pointeur plutôt que par leur indice 2. exprimer la condition de sortie de boucle uniquement sur la variable pointeur 4 Regroupement des étapes et extensions Au cas où vous ne l auriez pas encore fait, fusionnez les codes de vos deux parties (remplissage et affichage, version 1 et/ou 2), compilez, exécutez, vérifiez le résultat. Extensions Au choix vous complèterez le projet avec les extensions suivantes : 1. le calcul d autres tables que la multiplication (autre tables arithmétiques, ou logiques ou...) 2. une gestion des dimensions de la table (table 5x5, 12x12, 5x20,...) 3. un affichage en binaire, (octal), hexa 4. une amélioration de l algorithme de multiplication 5. un affichage graphique 6. ou une idée à vous 5 Présentation de votre projet Vous devez préparer un exposé de 10 minutes pour illustrer et didactiquement expliquer à l enseignant : 1. La problématique du projet ; 2. Les différentes étapes nécessaires pour réaliser le projet ; 3. Les algorithmes utilisés et réalisés ; 4. Les différentes versions du programme bien organisées et commentées en accord avec les conventions adoptées dans les algorithmes ; 5. Les différents tests exécutés ; 6. Les difficultés rencontrées ; 7. Les résultats obtenus. Utilisez les consignes de la formation C2i du DLST pour formater et organiser votre fichier de présentation du projet. Les deux étudiants du binôme devront présenter le projet et être capables de démontrer le fonctionnement du programme (compilation et exécution) aussi bien que répondre aux questions de l enseignant sur les codes développés. 6 Annexe 1 : tabmult.s @ Programme tabmult : Affiche les tables de multiplication de de 1 a 10 N_MAX= 10.data barre :.byte.byte 0 espace :.byte.byte 0 tirets :.asciz "---" debuttab:.skip N_MAX*N_MAX*4 @ adresse du debut du tableau 4
.text.global main main: @ remplissage du tableau @ a completer... @ affichage du tableau @ a completer... BAL exit ptr_debuttab :.word debuttab adr_barre :.word barre adr_espace :.word espace adr_tirets :.word tirets 7 Annexe 2 : écriture d entiers en format fixe En C, le format %3u indique d afficher un entier naturel cadré à droite sur 3 caractères (inclusion d espaces à gauche pour les nombres <100, utiliser %3d ou %3i pour un entier relatif). La fonction d écriture en format fixe n est pas disponible dans es.s, mais vous pouvez réutiliser le code ci-dessous : // Fonction ecriture_formattee // Ecrire un entier naturel sur une largeur de 3 caractères // Equivalent de printf("%3u",r1) en C // Convention d appel : l entier à afficher est stocké dans r1.text.global ecriture_formattee ptr_format_trois_u :.word format_trois_u format_trois_u:.asciz "%3u".balign 4 ecriture_formattee: mov ip, sp stmfd sp!, {r0, r1, r2, r3, fp, ip, lr, pc} sub fp, ip, #4 ldr r0,ptr_format_trois_u bl printf ldmea fp, {r0, r1, r2, r3, fp, sp, pc} 5