Rapport de Micro TP1

JIN Zhuoyuan 22213816

Exercice1

ex1.

Que contient le fichier startup_stm32f446retx.s ? Que permet-il selon vous ?

Contenu :
Le fichier startup_stm32f446retx.s est un fichier d’assemblage. Il contient principalement le code de démarrage pour le microcontrôleur STM32F446RETx. Il inclut la définition de la table des vecteurs d’interruption, l’initialisation de la pile, l’initialisation des segments de données (.data et .bss), l’appel à la fonction SystemInit pour configurer l’horloge du système, et l’appel à la fonction main de l’application.
Il définit également des gestionnaires d’exceptions par défaut (Default_Handler) qui entrent dans une boucle infinie en cas d’interruption inattendue.
Fonctionnement :
Ce fichier permet de préparer l’environnement pour l’exécution du code de l’application. Il initialise l’état initial du microcontrôleur, notamment en configurant le pointeur de pile, en copiant les données initialisées depuis la mémoire flash vers la mémoire SRAM, en mettant à zéro le segment .bss , et en démarrant le système en appelant la fonction main.

Ligne 126, une table des vecteurs est créée en mémoire. Que contient-elle ?

La table des vecteurs (g_pfnVectors) créée à la ligne 126 contient les adresse:adresse de la pile(l’adresse de la fin de la pile _estack) ; adresse du gestionnaire de réinitialisation(adresse de la routine Reset_Handler) ; adresse des gestionnaires d’exceptions et d’interruptions(NMI, le Hard Fault, les fautes de mémoire ect)

Trouver la section Reset_Handler (ligne 55). Que réalise-t-elle selon vous ?

La section Reset_Handler réalise les opérations suivantes :
1.Initialisation du pointeur de pile : Elle charge l’adresse de la fin de la pile (_estack) dans le registre r0, puis affecte cette valeur au pointeur de pile (SP).
2.Initialisation de l’horloge du système : Elle appelle la fonction SystemInit pour configurer l’horloge du microcontrôleur.
3.Copie des données initialisées : Elle copie les données initialisées du segment .data depuis la mémoire flash vers la mémoire SRAM.
4.Mise à zéro du segment .bss : Elle met à zéro le segment .bss.
5.Appel aux constructeurs statiques : Elle appelle la fonction __libc_init_array pour exécuter les constructeurs statiques des objets globaux.
6.Appel à la fonction main : Enfin, elle appelle la fonction main de l’application pour démarrer l’exécution du code utilisateur.

ex2

(1)Analyse du fichier
Analyser les différentes lignes de code, ainsi que tous les mots clés.
  • .text : Il s’agit d’un indicateur de section en langage assembleur.
  • .global main : Le mot - clé .global est utilisé pour déclarer un symbole global. Ici, il déclare main comme un symbole global
  • .type main, %function :Le mot - clé .type est utilisé pour spécifier le type d’un symbole. %function indique que main est un symbole de type fonction.
  • /* — A COMPLETER —*/ : C’est une commentaire
    Stop : C’est également une étiquette qui marque une position dans le code. Du point de vue du microprocesseur, c’est une destination de saut.
  • .B stop :B est une instruction de saut en langage assembleur, utilisée pour effectuer un saut inconditionnel à l’étiquette spécifiée. Ici, B stop signifie qu’il faut sauter à l’adresse marquée par l’étiquette stop.
  • .BX LR :BX est une instruction de branchement avec échange, utilisée pour sauter à une adresse spécifiée et changer l’ensemble d’instructions.
  • .end : C’est un indicateur de fin du fichier assembleur
Que représente « main: » ainsi que « stop: »? Que représentent main et stop d’un point de vue du microprocesseur ?
  • “main”:Du point de vue du microprocesseur, lorsque le programme est mis sous tension ou se rétablit d’un état d’exception, le pointeur d’instruction (PC) sera défini sur l’adresse mémoire correspondant à l’étiquette main, et le microprocesseur commencera à extraire et à exécuter les instructions à partir de cette adresse.
  • “stop”:est une adresse de destination de saut. Lorsque l’instruction B stop est exécutée, le microprocesseur définira le pointeur d’instruction (PC) sur l’adresse mémoire correspondant à l’étiquette stop, puis commencera à exécuter les instructions à cette adresse. Étant donné que l’étiquette stop est suivie immédiatement par l’instruction B stop, le microprocesseur saute constamment entre cette adresse et l’étiquette stop, créant ainsi une boucle infinie.
(2) programme-V1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.text
.global main
.type main, %function

main:

MOV R0, #1
MOV R1, #3
MOV R2, #5
ADD R3,R0,R1
ADD R4,R3,R2

stop: B stop
BX LR
.end
(3)Débogage
Q : Combien de registres génériques dispose le processeur ? Que représente le registre PC ?
  • 13(R0~R12)
  • Le registre PC est le compteur de programme. Il contient l’adresse de l’instruction suivante à exécuter. Lorsque le processeur exécute une instruction, il incrémente le PC pour pointer vers l’instruction suivante dans la mémoire.
Q : Que contient-il ? Pourquoi sa valeur est 0x80000204 (ou une valeur proche) ? Dans quelle zone mémoire se situe ce code ?
  • Contenu:Le registre PC contient l’adresse mémoire de l’instruction qui sera exécutée ensuite.
  • Pourquoi:Dans les microcontrôleurs STM32, la mémoire flash démarre généralement à l’adresse 0x08000000. La valeur 0x80000204 (ou proche) indique que le programme est en train d’exécuter une instruction située dans la mémoire flash.
  • Le code se situe dans la mémoire flash.
Q : Que contient le registre LR et à quoi sert-il ?

Le registre LR contient l’adresse de retour d’une sous - routine.
Il est utilisé pour permettre au programme de retourner à l’endroit où il était avant d’appeler la sous - routine.

Q : Que contient le registre SP et à quoi sert-il ?

SP contient l’adresse de la tête de la pile,et il est utilisé pour gérer la pile.

Q : Que contient le registre xPSR et à quoi sert-il ?

Le registre xPSR est un registre de statut étendu. Il regroupe plusieurs registres de statut tels que le APSR, le IPSR et le EPSR.
Il est utilisé pour stocker des informations sur l’état du processeur et le résultat des opérations.

Avant d’exécuter la première instruction,la valeur du registre PC

0x8000204
avant

Après d’exécuter

0x800020e
après

Q : Que pouvez-vous conclure ?

J’ai découvert que la valeur du registre PC change selon l’ordre des instructions dans le code. Il stocke l’adresse de l’instruction suivante à exécuter.

R4

après
R4 = 9
Selon les valeurs initiales R0 = 1, R1 = 3 et R2 = 5, le résultat attendu de R4 est (1 + 3)+ 5 = 9. Et la valeur de R4 = 9, donc c’est correspond parfaitement à la logique du code.

(4) Ex1_V2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.data 
SUM: .byte 1

.text
.global main
.type main, %function

main:

MOV R0, #1
MOV R1, #0x03
MOV R2, #0x05
ADD R3,R0,R1
ADD R4,R3,R2
LDR R5,=SUM /*@ de SUM stockée dans R5*/
STR R4,[R5] /*stockage de R4 à @ contenue dans R5*/

stop: B stop
BX LR
.end
la valeur de SUM avant d’exécuter

après

la valeur de SUM après d’exécuter

après

(5) Ex1_V3 (tab)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
.data 
SUM: .byte 1
RES: .byte 0
tab: .byte 1,12,28,4,3 /*déclaration d'un tableau tab */

.text
.global main
.type main, %function

main:
MOV R0, #0 /*R0=SUM initialisée à 0*/
LDR R1, =tab /*@tab dans R0*/
MOV R5, #0 /*R5 est utilisé comme index*/
LDRB R2,[R1] /* LDRB=Load 8bits de données*/
ADD R5,R5,#1
ADD R0,R2,R0
LDRB R2,[R1, R5]
ADD R5,R5,#1
ADD R0,R2,R0
LDRB R2,[R1, R5]
ADD R5,R5,#1
ADD R0,R2,R0
LDRB R2,[R1, R5]
ADD R5,R5,#1
ADD R0,R2,R0
LDRB R2,[R1, R5]
ADD R0,R2,R0
LDR R3,=RES /*@RES dans R3 */
STRB R0, [R3] /*sauvegarde de la somme dans RES */

stop: B stop
BX LR
.end
la valeur de RES avant d’exécuter

avant

après add 1

+1

+12

+12

+28

+28

+4

+4

+3

+3

fini le valeur de RES

fin

(6) Ex1_V4 (Branchement conditionnel)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
.data 
SUM: .byte 1
RES: .byte 0
tab: .byte 1,12,2,4,3
VALEUR_SUP30: .byte 0

.text
.global main
.type main, %function

main:
MOV R0, #0 /*R0=SUM initialisée à 0*/
LDR R1, =tab /*@tab dans R1*/
MOV R5, #0 /*R5 est utilisé comme index*/
LDRB R2,[R1] /* LDRB=Load 8bits de données*/
ADD R5,R5,#1
ADD R0,R2,R0
LDRB R2,[R1, R5]
ADD R5,R5,#1
ADD R0,R2,R0
LDRB R2,[R1, R5]
ADD R5,R5,#1
ADD R0,R2,R0
LDRB R2,[R1, R5]
ADD R5,R5,#1
ADD R0,R2,R0
LDRB R2,[R1, R5]
ADD R0,R2,R0
LDR R3,=RES /*@RES dans R3 */
STRB R0, [R3] /*sauvegarde de la somme dans RES */

/*condition pour vérifiez si le valeur de SUM >=30 */
LDR R4, =VALEUR_SUP30
CMP R0, #30 /* si le valeur >=30, alors VALEUR_SUP30 = 1 */
BGE sup /* Sauter à "sup" */
MOV R6,#0 /* sinon, alors VALEUR_SUP30 = 0 */
STR R6, [R4]
B stop

sup: MOV R6,#1
STR R6, [R4]
stop: B stop
BX LR
.end
Avant la condition de test

avant

Cas1. SUM = 22

22
22
Car la somme des éléments dans le tableau tab est égale à 22, qui est inférieure à 30, il n’y a pas de saut à l’étiquette sup. Ainsi, la valeur de R6 reste à 0.

Cas2. SUM =

48
Étant donné que la somme des éléments dans le tableau tab est de 48, qui est supérieure à 30, le programme saute donc à l’étiquette sup, et la valeur de R6 est assignée à 1.

Exercice 2

(1)Boucle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.data /*mot clé de déclaration d'une zone de données */
SUM: .byte 1 /*déclaration d'une variable SUM sur 8 bits initialisée à 1*/
RES: .byte 0
tab: .skip 9 /*déclaration d'un tableau tab vide de 9 octets */

.text
.global main
.type main, %function

main:
/*Solution sans boucle*/
MOV R0, #1 /*R0=reg de valeur*/
LDR R1, =tab /*@tab dans R1*/
MOV R2, #0 /*R2 est utilisé comme index de boucle */
boucle: STR R0,[R1,R2] /* LDRB=Load 8bits de données*/
ADD R0,R0,#1 /*incrémente valeur de reg*/
ADD R2,R2,#1 /*incrémente index*/
CMP R2, #9
BLT boucle /*branchement au label loop si R2<9*/

stop: B stop
BX LR
.end
Le tableau tab avant l’affectation

avant

Le tableau tab après la fin de l’affectation(boucle)

avant

(2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
.data
N: .byte 5 /*Taille */
tab: .byte 14, 25, 2, 16, 5 /*déclaration d'un tableau tab */

.text
.global main
.type main, %function

main:
LDR R0, =N /*taille*/
LDRB R0, [R0]
MOV R1, #0 /* indice i */

outer_loop:
CMP R1, R0
SUBS R2, R0, #1 /* R2 = N - 1 */
BEQ stop /* Si i >= N, fin du tri */

inner_loop:
CMP R2, R1
BEQ end_inner_loop /* Si j <= i, fin de la boucle interne */

LDR R3, =tab
LDRB R4, [R3, R2] /* R4 = tab[j] */
SUBS R5, R2, #1
LDRB R6, [R3, R5] /* R6 = tab[j - 1] */

CMP R4, R6
BGE no_swap /* Si tab[j] >= tab[j - 1], pas de permutation */

/* Permutation de tab[j] et tab[j - 1] */
STRB R4, [R3, R5]
STRB R6, [R3, R2]

no_swap:
SUBS R2, R2, #1 /* j = j - 1 */
B inner_loop

end_inner_loop:
ADD R1, R1, #1 /* i = i + 1 */
B outer_loop

stop:
B stop
BX LR
.end

Exercice 3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
.data /* mot clé de déclaration d'une zone de données */
mot1: .asciz "salut" @ Déclaration de la première chaîne
mot2: .asciz "bonjour" @ Déclaration de la deuxième chaîne
SAME: .byte 0 @ Variable pour stocker le résultat de comparaison

.text
.global main
.type main, %function

main:
LDR R0, =mot1 @ Charger l'adresse de mot1
LDR R1, =mot2 @ Charger l'adresse de mot2
MOV R2, #0 @ Initialiser l'index
MOV R4, #0
MOV R5, #0
LDR R6, =SAME @ Charger l'adresse de SAME

loop:
LDRB R4, [R0, R2] @ Charger un caractère de mot1
LDRB R5, [R1, R2] @ Charger un caractère de mot2
CMP R4, #0 @ Vérifier fin de mot1
BEQ check_mot2
CMP R5, #0 @ Vérifier fin de mot2
BEQ fin2
CMP R4, R5 @ Comparer les caractères
BNE fin2
ADD R2, R2, #1 @ Incrémenter l'index
B loop

check_mot2:
CMP R5, #0 @ Vérifier fin de mot2
BNE fin2

fin:
MOV R7, #1 @ Chaînes identiques
STRB R7, [R6]
B end_program

fin2:
MOV R7, #0 @ Chaînes différentes
STRB R7, [R6]
B end_program

end_program:
BX LR
.end
Cas1. Les chaînes de caractères sont identiques.

same
same
Parce que les chaînes de caratères sont identiques, donc exécuter ‘fin’ R7 = 1.

Cas2. Les chaînes de caractères sont différentes

same
same
Parce que les chaînes de caratères sont différentes, donc exécuter ‘fin2’ R7 = 0.

Exercice 4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <stdio.h>
#include <stdlib.h>

const int TAB_SIZE=10;

void init_tab(void);
int somme_tab_asm(void);
int tab[10]={0};
int Somme = 0;

int main (void){

//Init tab Content with random values
init_tab();
//call to somme_tab function
int success = somme_tab_asm();

//Infinite loop
while(1){
}

return 0;
}

void init_tab(){
for (int i=0;i<TAB_SIZE;i++){
tab[i]=rand()%10;
}
}

int somme_tab_asm(void){

asm("mov r0,#0");
asm("mov r1,#0"); // r1 index de boucle
asm("mov r2,#0"); // r2=somme temporaire
asm("ldr r0,=tab"); //init r0 with @tab
asm("ldr r3,=TAB_SIZE"); //R3=@TAB_SIZE
asm("ldr r3,[r3]"); // R3=TAB_SIZE
asm("loop:ldr r1,[r0],#4");
asm("add r2,r2,r1");
asm("sub r3,r3,#1");
asm("cmp r3,#0");
asm("bne loop");
asm("ldr r4,=Somme"); // R4=@Somme
asm("str r2,[r4]");

return 0; // return 0 if success
}

le valeur de Somme avant d’exécuter

Somme = 0
avant

le valeur de Somme après d’exécuter

Somme = 48
avant