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.

appel_fonction2.svg

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}
//======================================================================     

appel_fonction3.svg


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 :

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 :

main.c

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 :

algo_int2ascii.svg

Q1. Proposer un codage de la fonction int2ascii en assembleur, dans un contexte où la fonction main est en C.