Processeur ARM Cortex 2
1 - Appel d’une fonction ( Suite )
1.1 - Problème des Fonction Imbriquées
Dans le makefile, effectuer la modification suivante :
ASRC += src/main_calc_3.s ### A MODIFIER ###
Considérons la fonction average qui fait appel à notre fonction sum_tab précédente :
//======================================================================
// VARIABLES GLOBALES
.data
tab: .word 1,2,3,4,5
resultat: .word 0
//======================================================================
// PROGRAMME
.text
.thumb
.syntax unified
.global main, average, sum_tab
main:
ldr r0,=tab
mov r1,#5
bl average // Appel fonction average
ldr r1,=resultat
str r0,[r1] // resultat <- acc
theend: b theend
//-----------------------------------------------------------------------
average:
mov r7,r1 // sauvegarde r1
bl sum_tab
sdiv r0,r0,r7
mov pc,lr
//-----------------------------------------------------------------------
sum_tab: mov r4,#0 // R3 <- 0
LOOP: ldr r5,[r0] // val <- tab[R2]
add r4,r4,r5 // acc <- acc+val
add r0,r0,#4 // R0++
subs r1,r1,#1 // compteur --
bne LOOP // PC <- PC - 12
mov r0,r4
mov pc,lr
//======================================================================
Etant donné que mon 2ème bl a pour effet d’écraser le registre LR contenant le retour à la fonction main, je reste coincé dans la fonction average.
1.2 - Utilisation de la pile
Dans le makefile, effectuer la modification suivante :
ASRC += src/main_calc_4.s ### A MODIFIER ###
Afin de sauvegarder le registre LR en cas d’appels de fonctions imbriqués, nous utilisons un espace en mémoire
appelé la pile. Pour se repérer dans cette zone mémoire, nous utilisons le registre pointeur de pile SP (stack pointer).
En plus du registre LR, il est possible de sauvegarder des registres généraux afin de conserver le contexte de la fonction appelante.
//======================================================================
// VARIABLES GLOBALES
.data
tab: .word 1,2,3,4,5
resultat: .word 0
//======================================================================
// PROGRAMME
.text
.thumb
.syntax unified
.global main, average, sum_tab
main:
ldr r0,=tab
mov r1,#5
bl average // Appel fonction sum_tab
ldr r1,=resultat
str r0,[r1] // resultat <- acc
theend: b theend
//-----------------------------------------------------------------------
average: push {r4-r5,lr}
mov r4,r1
bl sum_tab
sdiv r0,r0,r4
pop {r4-r5,pc}
//-----------------------------------------------------------------------
sum_tab: push {r4-r5,lr}
mov r4,#0 // R3 <- 0
LOOP: ldr r5,[r0] // val <- tab[R2]
add r4,r4,r5 // acc <- acc+val
add r0,r0,#4 // R0++
subs r1,r1,#1 // compteur --
bne LOOP // PC <- PC - 12
mov r0,r4
pop {r4-r5,pc}
//======================================================================
2 - Mix C/assembleur
Dans le makefile, effectuer la modification suivante :
SRC += src/main_5.c
ASRC += src/calc_5.s ### A MODIFIER ###
Par la suite nous utiliserons uniquement le langage C.
Le compilateur effectue donc dans un premier temps une conversion du langage C vers l’assembleur.
Lors d’un appel de fonction, le compilateur respecte les règles du standart AAPCS ( R0,R1,R2,R3 pour passer les paramètres, R0 pour la valeur de retour ).
int tab[5]={1,2,3,4,5};
int result=0;
int average(int*, int);
int main()
{
result = average( tab, 5 );
return 0;
}
//======================================================================
.text
.thumb
.syntax unified
.global average, sum_tab
//-----------------------------------------------------------------------
average: push {r4-r5,lr}
mov r4,r1
bl sum_tab
sdiv r0,r0,r4
pop {r4-r5,pc}
//-----------------------------------------------------------------------
sum_tab: push {r4-r5,lr}
mov r4,#0 // R3 <- 0
LOOP: ldr r5,[r0] // val <- tab[R2]
add r4,r4,r5 // acc <- acc+val
add r0,r0,#4 // R0++
subs r1,r1,#1 // compteur --
bne LOOP // PC <- PC - 12
mov r0,r4
pop {r4-r5,pc}
//======================================================================
Disassembly :
L’interprétation assembleur du code en C se trouve dans la fenêtre disassembly :
main:
080007b0: ldr r0, [pc, #48] ; (0x80007e4 <LOOP+16>)
15 mov r1,#5
080007b2: mov.w r1, #5
17 bl average // Appel fonction sum_tab
080007b6: bl 0x80007c0 <average>
19 ldr r1,=resultat
080007ba: ldr r1, [pc, #44] ; (0x80007e8 <LOOP+20>)
20 str r0,[r1] // resultat <- acc
080007bc: str r0, [r1, #0]
22 theend: b theend
theend:
080007be: b.n 0x80007be <theend>
25 average: push {r4-r5,lr}
average:
080007c0: push {r4, r5, lr}
26 mov r4,r1
080007c2: mov r4, r1
28 bl sum_tab
080007c4: bl 0x80007ce <sum_tab>
3 - TRAVAUX PRATIQUES
PROJET SOURCE
WORKSPACE_LAB_F411_ASM_STM32CUBE.zip
Conversion valeur en décimal –> Chaine de caractères
Dans le makefile, effectuer la modification suivante :
SRC += src/main.c
# ASRC += src/main_remove_space.s
ASRC += src/int2ascii.s
On considère le programme c suivant permettant de convertir un entier en ASCII :
unsigned int puis10[] = {1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1, 0};
unsigned int var = 1205;
char s[11];
void int2ascii(unsigned int d, char *s)
{
unsigned int *p, digit;
p=puis10;
while (*p != 0) {
digit = 0;
while (d >= *p) {
d = d-(*p);
digit++;
}
*s++ = digit + 0x30;
p++;
}
*s=0x00;
}
void main()
{
int2ascii(var,s);
}
On se propose de coder en assembleur le sous programme int2ascii dont la spécification est donnée ci-dessous :
fonction int2ascii : convertit une valeur entière non signée en une chaîne de caractère.
- Paramètre 1 : r0 contient la valeur à convertir
- Paramètre 2 : r1 contient l’adresse de la chaîne de caractère
On donne l’organigramme de int2ascii :
Q1. Proposer un codage de la fonction int2ascii en assembleur, dans un contexte où la fonction main est en C.