Page Personnelle de Vincent Kerhoas
Vincent Kerhoas
Professeur Agrégé
Page Personnelle de Vincent Kerhoas

Le processeur ARM Cortex - Partie 1

Back                  << Index >>


Présentation de la Famille des processeurs Cortex

L’architecture ARM Cortex est une architecture brevetée, fabriquée par différents fondeurs ( ST, NXP, TI, … ).
Les modèles proposés s’adaptent aux applications en fonction des performances exigées en temps de calcul, consommation, prix, supports pour OS.

Exemple d’Application


Equipement

Matériel

Logiciel

Plusieurs solutions sont possibles, je propose d’utiliser l’environnement de développement proposé par ST : STM32CubeIDE


Les Registres

Nous retrouvons en vert les registres de mu0-risc :
L’architecture ARM-cortex comporte 13 registres de calcul ( R0-R12 )


Quelques instructions ARM

L’objectif de cette partie n’est pas de passer en revue tous les instruction de l’architecture ARM Cortex, mais simplement d’en voir quelques unes pour coder des algorithmes simples.
L’assembleur reste uniquement un moyen pour bien comprendre les mécanismes dans un microprocesseur.
Nous passerons par la suite au langage C.

Toutes les instructions de calcul se font entre registres ( caractéristique d’une architecture RISC).
Il est possible dans une instruction d’indiquer une valeur immédiate ( en utilisant # )
Cette valeur doit tenir sur 8 bits ( ou pouvoir s’exprimer avec un décalage )

Instructions Arithmétiques et Logiques

Reprenons les instructions évoquées dans la partie précédente, avec quelques suppléments ou variantes.

mov r1, #5 // r1 <- 5
mov r1, r2 // r1 <- R2

add r1,r2,#1 // r1 <- r2+1
add r1,r2,r3 // r1 <- r2+r3

sub r1,r2,#1 // r1 <- r2-1
sub r1,r2,r3 // r1 <- r2-r3

mul r1,r2,r3 // r1 <- r2*r3

and r1,r2,r3 // r1 <- r2 and r3
orr r1,r2,r3 // r1 <- r2 or r3

REMARQUE : Par défaut l’exécution d’une instruction ne modifie pas les bits d’état NZVC.
le suffixe s permet de modifier les bits d’état NZVC à l’issue d’un calcul :

adds r1,r2,#1 // r1 <- r2+1 ; modification(NZVC) ;

Instruction de lecture/écriture mémoire de données

Lecture d’une donnée de 32 bits en mémoire

ldr r0,=val // r0 <- adr(val)
ldr r1, [r0] // r1 <- [r0]

Nous avons toujours le problème qu’une adresse fait 32 bits, et une instruction est codée sur 32 bits.
Je ne peux donc pas indiquer dans une même instruction le nom de l’instruction, un numéro de registre et une adresse mémoire de 32 bit__s.
La pseudo instruction __ldr r0,=val
est remplacé à la compilation par ldr r0,[PC+offset]. Le compilateur prendra soin lors de la compilation de placer l’adresse de la variable val à une case mémoire située à offset instructions de ldr r0,[PC+offset].

Lecture d’une donnée de 8 bits en mémoire

Comme chaque octet possède une adresse, l’instruction ldrb permet de rapatrier 8 bits dans un registre de 32 bits.
L’extension de format se fait par défaut en considérant des nombres non signés ( ajout de zéros sur les poids forts )

ldr r0,=val // r0 <- adr(val)
ldrb r1, [r0] // r1 <- [r0]

Ecriture d’une donnée de 32 bits en mémoire

ldr r0,=val
str r1, [r0]

Ecriture d’une donnée de 8 bits en mémoire

ldr r0,=val
strb r1, [r0]

Post Incrémentation

Lors du parcours d’un tableau, au lieu d’utiliser l’instruction add pour faire évoluer la valeur du pointeur, il est possible décrire :

ldr r1,[r0],#4 // r1 <- [r0] ; r0 <- r0+4

Instructions de comparaison et de Saut ( Branch )

b loop // PC <- loop : Saut inconditionnel, dans tous les cas on va à l’adresse loop

Une séquence If then else ou une boucle conditionnelle ( for / while ) en langage C se traduit par un saut conditionnel en Assembleur.

REMARQUE : l’instruction cmp r0, r1 permet de faire la modification des bits NZVC pour une soustraction r0-r1 ( le résultat n’est pas récupéré )

beq loop // PC <- loop si résultat précédent égal à 0 ( on regarde NZVC pour cela )
bne loop // PC <- loop si résultat précédent différent de 0 ( Not Equal )

conditions de saut :


Premier Programme : Somme des éléments d’un Tableau

PROJET SOURCE


WORKSPACE_F411_ASM_STM32CUBE


Pour tester les différents exemples ci-dessous, il faudra modifier le fichier makefile

Environnement de Développement ( IDE )

Tutorial STM32CubeIDE

L’ IDE STM32CUBE comporte :

STM32CUBE est basé sur le logiciel ECLIPSE

Le fichier Makefile donne les conditions de compilation et d’édition de liens.

Système de fichiers d’un projet

Reprenons le programme faisant la somme des éléments d’un tableau afin de le tester :

On distingue le segment “.data” et ‘.text” :

main_calc_1.s

Compilation et placement mémoire

Lorsque je compile mon programme ( raccourcis CTRL+B, j’exécute mon makefile.
Le makefile fait référence au compilateur arm-none-eabi-gcc pour transformer des fichiers C/C++ ou Assembleur en fichiers objets binaires .o
L’éditeur de lien arm-none-eabi-ld permet de réaliser le placement mémoire de ces fichiers objet en tenant compte du fichier de configuration stm32f411re_flash.lds ( ce fichier indique dans quelle zone mémoire il faut placer les différents segments ( code, datas )). L’exécutable résultant main.elf peut alors être transmis à la cible.

extrait de stm32f411re_flash.lds :

stm32f411re_flash.lds

Démarrage d’un programme : startup_stm32f411xe.s

A l’issue d’une mise sous tension ou d’un reset, PC reçoit l’instruction d’adresse Reset_Handler
On peut noter la boucle pour copier les données d’initialisation de la flash vers la RAM.
La fonction SystemInit() permet de configurer l’horloge du microcontrôleur.

startup_stm32f411xe.s

Test d’un Programme

Après avoir compilé et donc généré un exécutable .elf ( à condition qu’il n’y ait pas eu d’erreur de compilation ), nous pouvons charger et debugger notre programme.

La configuration de debug se trouve dans Run –> Debug Configurations ; nous y faisons référence à main.elf.

Accès direct :

Pour placer un point d’arrêt, double cliquer dans la marge ( ou appuyer sur SHIFT+CTRL+B )
Pour aller directement au point d’arrêt, appuyer sur F8 (Resume).
Mode pas à pas pour analyser l’exécution de chaque instruction :

Dans l’environnement de Debug, les registres sont visibles dans la fenêtre Registers ( Window -> Show View -> Registers )

Pour observer la mémoire, utiliser la fenere Memory Browser :


Appel d’une fonction

Dans le makefile, effectuer la modification suivante :

ASRC += src/main_calc_2.s ### A MODIFIER ###

Instruction BL ( Branch with Link)

main_calc_2.s

Lors de l’étude du langage C, nous avons évoqué l’intérêt du découpage d’un programme en fonctions ( rangement et réutilisation ).
Une fonction reste un bout de code situé à une certaine adresse.
Pour y accéder je dois donc effectuer un saut.
L’instruction b pourrait être utilisée, mais après exécution de la fonction, il faut retourner à l’instruction suivant l’appel de la fonction.
Je doit donc mémoriser l’adresse de retour.

L’instruction bl permet donc de :

Par convention, les paramètres des fonctions sont placés dans R0 et R1 ( puis R2, R3 si nécéssaire ).
Le paramètre de retour de fonction est placé dans R0.


Traitement d’une Chaine de caractères

Dans le makefile, effectuer la modification suivante :

ASRC += src/main_str.s ### A MODIFIER ###

Représentation d’une chaine de caractères dans un processeur : le code ASCII

Comme toute donnée dans un système à processeurs, les caractères sont codés avec des 0 et des 1.

Algorithme : passage de minuscules à majuscules

Le codage du caractère ‘a’ est 0x61
Le codage du caractère ‘A’ est 0x41
Pour toute lettre, il y a une différence de 0x20 entre la minuscule et la majuscule.

Considérons la chaîne de caractères “abscefgh”, et observons la en mémoire :

C’est un tableau d’octets, dont l’adresse du premier élément est 0x200000b0
Le dernier élément du tableau est le caractère Nul ( 0x00 ).

L’algorithme consiste donc à :

main_str.s

TRAVAUX PRATIQUES

PROJET SOURCE


WORKSPACE_LAB_F411_ASM_STM32CUBE


Traitement d’une 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

Q1. Proposer un codage de la fonction remove_space permettant de remplacer tout espace dans une chaine de caractères ( ch_src ) par un undescore (‘_’).
La chaîne modifiée sera placée à l’adresse ch_dest.


Back                  << Index >>