Вы находитесь на странице: 1из 165

Haute école spécialisée bernoise

Technique et informatique
Section Electricité et systèmes de communication
Laboratoire d’informatique technique

Informatique 3
Microordinateur
Programmation assembleur
Interface C / Assembleur

© 2008 HESB-TI / Dr E. FIROUZI

Dernier changement : Juin 2008


Auteur : Dr E FIROUZI
Version : 3.1
Informatique 3 Avant propos

Avant propos
Ce manuscrit est distribué aux étudiants du module « Informatique 3 » de la section Electricité et système de
communication de la Haute école spécialisée bernoise. Il est complété par des exercices, qui sont distribués en
supplément durant le cours, et un projet, qui est réalisé à la fin du semestre.

La première partie du manuscrit traite la structure d’un microordinateur. Cette partie comprend l’organisation de
la CPU et sa connexion avec les composants externes. La seconde partie du manuscrit introduit la
programmation en assembleur. Cette introduction s’effectue avec des exemples, qui se basent sur un
microcontrôleur RISC à 32 bits : le PXA270 de Intel. La dernière partie du manuscrit traite l’interface C –
assembleur, en se référant aux cours de C (modules informatiques 1 et 2).

Toutes les exercices et le projet sont réalisés avec le kit de développement CARME, qui est introduit au
deuxième semestre.

Des information supplémentaires sont mises à disposition sur le site: http://prof.hti.bfh.ch/fue1

A la fin de ce module, les étudiants sont en mesure de :


1) Concevoir un schéma hardware contenant un microcontrôleur, de la mémoire externe et des composants
périphériques
2) Réaliser un projet en C et assembleur

Un grand remerciement à G. KRUGER et R. WEBER pour définition de la version originale du manuscrit en


allemand ; ainsi qu’à M. MÜHLEMANN et E. STUCKI pour la mise en place de l’environnement de
développement.

Bienne, septembre 2008


E. FIROUZI

Version 3.1, juin 2008 Page I


Informatique 3 Table des matières

Table des matières


1 Architecture d’un microordinateur standard ....................................................................................................1
1.1 Les catégories des ordinateurs................................................................................................................. 1
1.1.1 La classification selon Flynn........................................................................................................... 1
1.1.2 La communication chez les ordinateurs MIMD .............................................................................. 2
1.2 Les architectures des microordinateurs ................................................................................................... 3
1.2.1 L’architecture de Von Neumann ..................................................................................................... 3
1.2.2 L’Architecture de Harvard .............................................................................................................. 4
1.3 La CPU.................................................................................................................................................... 4
1.4 Le système de bus ................................................................................................................................... 5
1.4.1 Les bus d’adresse, de données et de contrôle .................................................................................. 5
1.4.2 Le plan de mémoire......................................................................................................................... 7
1.4.3 Le décodeur d’adresse..................................................................................................................... 8
1.5 La mémoire ............................................................................................................................................. 9
1.5.1 Les technologies.............................................................................................................................. 9
1.5.2 L’organisation de la mémoire........................................................................................................ 10
1.5.3 Les architectures............................................................................................................................ 10
1.5.4 La documentation.......................................................................................................................... 12
1.6 La hiérarchie de la mémoire.................................................................................................................. 13
1.7 La MMU ............................................................................................................................................... 14
1.7.1 Les adresses physiques et virtuelles .............................................................................................. 14
1.7.2 Pages et trames, Tableau de pages ................................................................................................ 15
1.7.3 Les tampons auxiliaires de traduction ........................................................................................... 16
1.8 DMA ..................................................................................................................................................... 17
1.9 La périphérie ......................................................................................................................................... 18
1.9.1 Les amplificateurs de sortie........................................................................................................... 18
1.9.2 Digital Input / Output .................................................................................................................... 19
1.9.3 L’interface sérielle ........................................................................................................................ 20
1.9.4 Le timer ......................................................................................................................................... 25
1.9.5 Les convertisseurs A/D ................................................................................................................. 26
1.9.6 Les convertisseurs D/A ................................................................................................................. 26
1.10 Les types de processeur......................................................................................................................... 27
1.10.1 Les microprocesseurs .................................................................................................................... 27
1.10.2 Les microcontrôleurs..................................................................................................................... 27
1.10.3 Les DSP......................................................................................................................................... 27
1.10.4 CISC / RISC27
1.11 Exemple de famille de microcontrôleur ................................................................................................ 27
1.12 Les critères pour le choix d'un microcontrôleur .................................................................................... 28
2 Le microcontrôleur PXA270..........................................................................................................................30
2.1 L’architecture ARM .............................................................................................................................. 30
2.2 Intel XScale........................................................................................................................................... 33
2.2.1 L’architecture XScale.................................................................................................................... 33
2.2.2 Le coeur d’exécution du XScale ................................................................................................... 34
2.2.3 Le super pipeline du XScale.......................................................................................................... 35
2.3 Le PXA270 de XScale .......................................................................................................................... 37
2.3.1 Les propriétés ................................................................................................................................ 37
2.3.2 Le diagramme de bloc ................................................................................................................... 38
2.4 Les modes de fonctionnement............................................................................................................... 39
2.5 Le modèle des registres......................................................................................................................... 39
2.6 CPSR Current Program Status Register ................................................................................................ 41
2.7 Les bits d’état ........................................................................................................................................ 41

Version 3.1, juin 2008 Page II


Informatique 3 Table des matières

2.8 Les modèles de mémoire et les format de données ............................................................................... 43


2.9 Le plan de mémoire du PXA270........................................................................................................... 44
2.10 Le plan de mémoire du CARME........................................................................................................... 45
2.11 Le schéma des pins................................................................................................................................ 46
2.12 Connexion des composants Flash et SDRAM....................................................................................... 46
2.13 Schéma hardware avec le PXA270 & la mémoire ................................................................................ 48
3 La programmation en assembleur ..................................................................................................................49
3.1 Introduction........................................................................................................................................... 49
3.2 Les niveaux des langages de programmation........................................................................................ 49
3.3 La structure d’un fichier en assembleur ................................................................................................ 50
3.4 La syntaxe assembleur .......................................................................................................................... 51
3.4.1 La structure d’une ligne assembleur.............................................................................................. 51
3.4.2 Les symboles................................................................................................................................. 53
3.4.3 Les constantes ............................................................................................................................... 53
3.4.4 Les opérateurs et les opérandes ..................................................................................................... 54
3.5 L’environnement de développement ..................................................................................................... 55
3.5.1 L’éditeur........................................................................................................................................ 56
3.5.2 L’assembler ................................................................................................................................... 57
3.5.3 Le compilateur .............................................................................................................................. 57
3.5.4 Le relieur / locateur ....................................................................................................................... 58
3.5.5 Le débuggeur................................................................................................................................. 58
3.5.6 La gestion du projet....................................................................................................................... 58
4 Jeu d’instruction du processeur ARM V5 ......................................................................................................60
4.1 Les instructions ..................................................................................................................................... 60
4.1.1 La syntaxe des instructions ARM ................................................................................................. 62
4.1.2 La syntaxe de la notation............................................................................................................... 62
4.1.3 Exécution d’instruction conditionnelle.......................................................................................... 63
4.1.4 Le jeu d’instruction Thumb........................................................................................................... 64
4.1.5 Les coprocesseurs.......................................................................................................................... 65
4.2 La vue d’ensemble du jeu d’instructions............................................................................................... 65
4.3 Les transferts de données ...................................................................................................................... 65
4.3.1 Les instruction de transfert de données entre registres MOV, MVN................................................. 66
4.3.2 Le décalage à barilier (barrel shifter) ............................................................................................ 67
4.3.3 Les instructions de chargement de données LDR et STR ......................................................... 68
4.3.4 Modes d’adressage pour les instructions de chargement et de stockage ....................................... 69
4.3.5 L’instruction SWP.......................................................................................................................... 71
4.3.6 Chargement et stockage multiple LDM et STM .............................................................................. 72
4.3.7 Les instructions de la pile.............................................................................................................. 74
4.3.8 Les instructions d’état MRS et MSR ............................................................................................... 75
4.3.9 Les instructions du coprocesseur LDC, STC, MRC, MCR et CDP ................................................... 76
4.4 Les instructions arithmétiques et logiques ............................................................................................ 77
4.4.1 L’arithmétique des entiers............................................................................................................. 78
4.4.2 Les instruction logiques ................................................................................................................ 81
4.4.3 Les instructions de décalage et de rotation.................................................................................... 82
4.5 Saut de programme ............................................................................................................................... 82
4.5.1 Généralité ...................................................................................................................................... 82
4.5.2 Les sauts de programme inconditionnels ...................................................................................... 83
4.5.3 Les sauts de programmes conditionnels ........................................................................................ 85
4.6 Les autres instructions ARM................................................................................................................. 86
4.6.1 Les interruptions software SWI..................................................................................................... 86
4.6.2 Les points d’arrêt BKPT ................................................................................................................ 87
4.6.3 Le comptage des zéros CLZ .......................................................................................................... 87
5 Les directives de l’assembleur .......................................................................................................................89

Version 3.1, juin 2008 Page III


Informatique 3 Table des matières

5.1 Introduction........................................................................................................................................... 89
5.2 Aperçu................................................................................................................................................... 89
5.3 .arm, .thumb..................................................................................................................................... 90
5.4 .global, .extern ........................................................................................................................... 91
5.5 .align.................................................................................................................................................. 91
5.5.1 .balign ....................................................................................................................................... 92
5.5.2 .p2align.................................................................................................................................... 93
5.6 .ascii, .asciz ................................................................................................................................ 93
5.7 .byte................................................................................................................................................... 94
5.7.1 .2byte, .hword ........................................................................................................................ 94
5.7.2 .word, .4byte .......................................................................................................................... 95
5.8 .space ................................................................................................................................................ 95
5.9 .include ........................................................................................................................................... 96
5.10 .equ, .set, = ..................................................................................................................................... 96
5.11 .org ..................................................................................................................................................... 97
5.12 .section ........................................................................................................................................... 97
5.13 .end ................................................................................................................................................... 101
5.14 Les opérations assembleur .................................................................................................................. 101
5.15 Les structures de contrôle en assembleur ............................................................................................ 102
5.15.1 L’assemblage conditionnel avec .if ......................................................................................... 102
5.15.2 L’assemblage conditionnel avec .ifdef .................................................................................. 103
5.15.3 L’assemblage conditionnel avec .ifndef ................................................................................. 103
5.16 La définition de macro avec .macro................................................................................................. 103
5.17 Les structures de répétitions en assembleur ........................................................................................ 104
5.17.1 La répétition avec .rept ........................................................................................................... 105
5.17.2 La répétition paramétrée avec .irp........................................................................................... 106
6 Les sous routines..........................................................................................................................................107
6.1 Introduction......................................................................................................................................... 107
6.2 Appel et retour de sous routine ........................................................................................................... 107
6.2.1 Appel de sous routine.................................................................................................................. 107
6.2.2 Appel emboîté de sous routine, pile ............................................................................................ 108
6.3 La sauvegarde du contenu des registres .............................................................................................. 111
6.4 Le transfert des paramètres ................................................................................................................. 112
6.4.1 Le transfert de paramètres à l’aide de registre............................................................................. 112
6.4.2 Le transfert de paramètres avec la pile ........................................................................................ 113
6.5 APCS................................................................................................................................................... 114
6.6 Définition de variable locaux .............................................................................................................. 115
6.7 Sources d’erreurs................................................................................................................................. 116
6.8 Comparaison entre sous routine et macro ........................................................................................... 117
7 Les interruptions et les exceptions ...............................................................................................................118
7.1 Introduction......................................................................................................................................... 118
7.2 Les propriétés des interruptions .......................................................................................................... 119
7.3 La priorité des exceptions et les modes du processeur........................................................................ 119
7.4 Les interruptions ................................................................................................................................. 120
7.5 Le masquage des interruptions............................................................................................................ 121
7.6 Le Tableau des vecteurs d’exception .................................................................................................. 122
7.7 Déroulement d’une requête d’interruption .......................................................................................... 123
7.8 Comportement temporel des interruptions .......................................................................................... 125
7.9 Le contrôleur d’interruption du PXA270 ............................................................................................ 126
7.10 Les variante pour le contrôleur d’interruption..................................................................................... 129
8 Les Structures de contrôle en assembleur ....................................................................................................131
8.1 Introduction......................................................................................................................................... 131

Version 3.1, juin 2008 Page IV


Informatique 3 Table des matières

8.2 La ramification simple ........................................................................................................................ 132


8.3 La ramification multiple...................................................................................................................... 133
8.4 La boucle avec évaluation de la condition au début............................................................................ 135
8.5 La boucle avec évaluation de la condition à la fin .............................................................................. 135
8.6 La boucle itérative............................................................................................................................... 136
9 Les structures de données en assembleur .....................................................................................................138
9.1 Introduction......................................................................................................................................... 138
9.2 Les Tableaux unidimensionnels .......................................................................................................... 138
9.3 Les Tableaux multidimensionnels....................................................................................................... 139
9.4 Les chaîne de caractères...................................................................................................................... 140
9.5 Les structures ...................................................................................................................................... 140
9.6 La pile (stack)...................................................................................................................................... 141
9.7 Queues et anneaux de tampons (Queue / Ring buffers) ...................................................................... 142
10 Le démarrage d’un programme C ............................................................................................................145
10.1 Le processus de démarrage d’un programme C .................................................................................. 145
10.2 Le reset................................................................................................................................................ 145
10.3 Le code de démarrage du système (bootloader) .................................................................................. 145
10.4 Le code de démarrage de l’application................................................................................................ 146
10.5 Le programme principale .................................................................................................................... 148
11 L’interface C et assembleur .....................................................................................................................151
11.1 Introduction......................................................................................................................................... 151
11.2 Les appels des sous routines assembleur depuis le C.......................................................................... 151
11.3 Transmission de paramètres aux sous routines assembleur................................................................. 152
11.4 Les registres utilisés par le compilateur .............................................................................................. 152
11.5 L’utilisation de variables en commun ................................................................................................. 152
11.6 L’assembleur en ligne ......................................................................................................................... 153
12 L’adressage des registres en C .................................................................................................................155
12.1 L’adressage avec #define ............................................................................................................... 155
12.2 La définition de sections absolues....................................................................................................... 155
12.3 L’utilisation de mots clés spécifiques du fabriquant ........................................................................... 156
Annexe A: Stockage des nombres........................................................................................................................157
Annexe B: Les format des nombres .....................................................................................................................158
Complément à deux ........................................................................................................................................ 158
Nombre à virgule flottante .............................................................................................................................. 158
Annexe C: La documentation...............................................................................................................................159
Annexe D: Tableau des valeurs ASCII ................................................................................................................160
Index ....................................................................................................................................................................161

Version 3.1, juin 2008 Page V


Informatique 3 Architecture d’un microordinateur standard

1 Architecture d’un microordinateur standard


Ce chapitre traite l’architecture des microprocesseurs et le principe de fonctionnement du matériel (hardware),
qui comprend la CPU (Central Processing Unit), la MMU (Memory Management Unit), le DMA (Direct
Memory Access), la mémoire externe et les composants périphériques. Ce chapitre traite le sujet de manière très
générale, sans distinction entre les différentes familles de CPU.

1.1 Les catégories des ordinateurs


1.1.1 La classification selon Flynn
Selon Michael J. Flynn, les ordinateurs peuvent être répartis en quatre catégories. Cette classification se base sur
la structure des instructions du programme et des jeux de données. En effet, ces derniers peuvent être soit
« simples » ou « multiples ».

SISD SIMD
Single Instruction, Single Data Single Instruction, Multiple Data
Ordinateur séquentiel Ordinateur vectoriel en pipeline

MISD MIMD
Multiple Instruction, Single Data Multiple Instruction, Multiple Data
Tableau systolique Multiprocesseur et multi ordinateurs

Tableau 1 : Les catégories des ordinateurs

SISD:
Les ordinateurs SISD travaillent de façon séquentielle. Ces
derniers traitent un seul jeu de donnée en fonction d’une seule load A
instruction : load B
t

Single instruction veut dire, qu’une instruction est exécutée par C=A+B
cycle d’horloge. store C
Single Data veut dire, qu’un jeu de donnée est traité par cycle
d’horloge. CPU
Les ordinateurs SISD sont les ordinateurs les plus répandus,
comme par exemple les ordinateurs personnels (PC) ou les
stations de travail.
Toutefois, avec l’introduction des processeurs multi corps, les
systèmes MIMD seront bientôt plus nombreux.

SIMD:
Les ordinateurs SIMD permettent d’exécuter la même instruction
sur plusieurs jeux de données. Ces derniers sont utilisés par load A1 load A2
exemple pour le traitement des images (JPEG, MPEG). load B1 load B2
t

Single Instruction veut dire, que tous les CPU exécutent la même C1 = A1 + B1 C2 = A2 + B2
instruction à un cycle d’horloge donné. store C1 store C2
Multiple Data veut dire, que chaque CPU traite un jeu de donnée
différent. CPU 1 CPU 2
De nombreux microprocesseur, comme par exemple les PowerPC
ou les x86, possèdent des extensions SIMD avec des instructions
supplémentaires. La CPU peut ainsi traiter simultanément
plusieurs jeux de données, en fonction d’une seule instruction.

Version 3.1, juin 2008 Page 1


Informatique 3 Architecture d’un microordinateur standard

MISD:
Un seul jeu de donnée est traité simultanément par plusieurs
CPU, avec des instructions différentes. load A1 load A1
Multiple Instruction veut dire, que chaque CPU exécute une load B1 load B1

t
instruction différentes. C1 = A1 + B1 C2 = A1 * B1
Single Data veut dire, que chaque CPU traite le même jeu de store C1 store C2
donnée.
Les ordinateurs MISD ne sont presque plus utilisés aujourd’hui. CPU 1 CPU 2

MIMD:
Aujourd’hui presque tous les ordinateurs multiprocesseurs se
basent sur l’architecture MIMD. load A1 load D
Multiple Instruction veut dire, que chaque CPU exécute une load B1 E = func1(D)

t
instruction différente par cycle d’horloge. Des programmes C1 = A1 + B1 F=D/2
entiers ou des partitions de ces derniers (process, thread, task) store C1 func2()
sont souvent répartis entre les différents CPU.
Multiple Data veut dire, que chaque CPU traite un jeu de données CPU 1 CPU 2
différent.

1.1.2 La communication chez les ordinateurs MIMD


Dans les systèmes MIMD, la communication entre les différents CPU s’effectue selon plusieurs principes :

a) Les systèmes fortement couplés (shared memory)


Plusieurs CPU partagent la même zone de mémoire
(shared memory). Mémoire
Tous les CPU travaillent indépendamment. Mais ils Bus
sont avertis, lorsqu’un CPU accède à une autre zone
de mémoire.
L’accès à la mémoire doit être synchronisé. Car CPU 1 CPU 2 CPU 3
plusieurs CPU ne peuvent pas accéder simultanément
à la mémoire.
Figure 1 : Les systèmes fortement couplés

b) Les systèmes faiblement couplés (distributed memory)


Plusieurs CPU communiquent à l’aide d’un réseau.
Réseau
Les CPU travaillent indépendamment et chaque CPU
possède sa propre zone de mémoire. Les échanges de
données entre les CPU ont lieu à l’aide du réseau. CPU 1 CPU 2 CPU 3
Ces systèmes peuvent être composés de plusieurs
systèmes SISD, reliés par un réseau.
Mémoire 1 Mémoire 2 Mémoire 3

Figure 2 : Les systèmes faiblement couplés

Comparaison entre les systèmes fortement et faiblement couplés :


Les systèmes faiblement couplés sont plus facilement extensibles. L’accès mémoire y est beaucoup plus rapide.
Par contre l’échange des données à travers le réseau est plus lent et plus complexe.

c) Combinaison de systèmes fortement et faiblement couplés :


Aujourd’hui, les ordinateurs les plus rapides sont souvent un mélange de systèmes fortement et faiblement

Version 3.1, juin 2008 Page 2


Informatique 3 Architecture d’un microordinateur standard

couplés. Cela découle des avantages et des désavantages de ces systèmes.

Mémoire CPU CPU Mémoire CPU CPU


CPU CPU CPU CPU
Réseaux

Mémoire CPU CPU Mémoire CPU CPU


CPU CPU CPU CPU

Figure 3 : Combinaison de systèmes fortement et faiblement couplés

1.2 Les architectures des microordinateurs


Il existe deux variantes pour le transfert des données entre la CPU et la mémoire : l’architecture de « Von
Neumann » et celle de « Harvard ». Les deux architectures appartiennent à la catégorie des systèmes SISD.

1.2.1 L’architecture de Von Neumann


Actuellement, l’architecture de la plus grande partie des ordinateurs est basée sur celle de Von Neumann,
nommé selon le mathématicien hongrois János Von Neumann (1903 – 1957). Dans cette architecture les
instructions du programme, ses structures de données et les composants périphériques partagent la même zone de
mémoire. La CPU accède ainsi aux instructions, aux données et à la périphérie avec un seul system de bus. Par
conséquent, les instructions et les données ne peuvent être chargées que séquentiellement. C'est-à-dire qu’il faut
au moins deux cycles d’horloge pour lire une instruction et les données à traiter.
Bus pour les instructions et les données

Mémoire
programme

Mémoire des
CPU données

Périphérie

Figure 4 : Architecture de Von Neumann

La mémoire programme, comme son nom l’indique, contient les instructions du programme. Cette dernière est
en générale non volatile, c’est à dire que son contenu n’est pas perdu lorsque l’alimentation est coupée. Quant à
la mémoire des données, elle contient les variables du programme et est en générale volatile. La CPU lit les
instructions dans la mémoire programme et traite (lecture et écriture) les variables, qui sont stockées dans la
mémoire des données ou les composants périphériques, en fonction de ces dernières.

Le goulot de Von Neumann désigne la limitation du transfert des informations entre la CPU et la mémoire
(programme et données). Ce goulot résulte du système de bus unique.

Version 3.1, juin 2008 Page 3


Informatique 3 Architecture d’un microordinateur standard

1.2.2 L’Architecture de Harvard


Dans l’architecture de Harvard les instructions et les données sont déposées dans deux zones mémoire distinctes.
Dans cette structure deux systèmes de bus (bus des instructions et bus de données) permettent l’accès aux
différentes zones mémoire. Les instructions et les données peuvent ainsi être lues simultanément (c’est à dire en
parallèle). La largeur des buses (instructions et données) peut être différente.

Mémoire des
données

Bus de données
Mémoire du
programme Bus des instructions CPU

Périphérie

Figure 5 : L’architecture de Harvard

L’architecture de Harvard est souvent utilisée dans les DSP (Digitale Signal Processor). L’avantage de cette
architecture réside dans la lecture simultanée des instructions et des données du programme. Cette architecture
est donc plus rapide que celle de Von Neumann, mais elle est également plus complexe, ce qui influence
forcément le prix.

Dans les chapitres suivant nous nous limiterons à l’architecture de Von Neumann.

1.3 La CPU
La CPU (Central Processing Unit) est le coeur de l’ordinateur. Il contrôle l’exécution du programme et traite les
données. La Figure 6 illustre la structure générale de la CPU. Cette dernière varie en fonction du type et du
fabriquant de l’ordinateur.

Bus de contrôle Bus d’adresse Bus des données

Interface du bus

Register
Program-Counter
Opérande
Bus interne

Instruction
Unit
ALU

Résultat

Unité de contrôle Unité de calcul

Figure 6 : Structure de la CPU

L’unité de contrôle est responsable de l’exécution du programme. Il est composé des éléments suivants :
• Instruction Unit (dispositif de commande) : Il interprète et exécute les instructions du programme.

Version 3.1, juin 2008 Page 4


Informatique 3 Architecture d’un microordinateur standard

• Program-Counter (PC): Il contient l’adresse de la prochaine instruction du programme à exécuter.

Les tâches de l’unité de contrôle sont les suivantes :


• Chargement des instructions du programme à partir de la mémoire programme (fetch), qui sont adressées par
le compteur de programme.
• Décodage des instructions programme (decode).
• Exécution des instructions programme (execute) en quatre étapes :
− Génération des signaux de contrôle pour l’ALU ou les autres unités de calcul.
− Adressage et chargement des opérandes.
− Stockage du résultat.
− Adaptation du compteur de programme.

L’unité de calcul est responsable du traitement des données. Il contient les composants suivants :
• ALU (Arithmetic Logical Unit), qui exécute les opérations arithmétiques et logiques. L’ALU n’exécute que
des opérations avec des nombres entiers. Pour des instructions à virgule flottante ou des instructions
mathématiques plus complexes on emplois souvent un FPU (Floating Point Unit). Les opérations typiques
sont les suivantes :
− Les opérations de transfert (chargement et stockage)
− Les opérations logiques (AND, OR, EXOR et NON)
− Les opérations arithmétiques (addition, soustraction, multiplication)
− Comparaison et décision (compare et réalise le saut de programme si la condition est réalisée)
− Les opérations de décalage (shift left, shift right)
• Les registres de données, qui sont destinés aux stockages des opérandes et du résultat des opérations
(accumulateur). Un registre est une case mémoire rapide, qui se trouve à l’intérieure du processeur. Ce
dernier peut être accédé directement, c’est à dire sans système de bus, par la CPU.

Le bus interne relie l’unité de contrôle, celle de calcul et l’interface du bus. L’unité de contrôle gère les
opérations, qui doivent être exécutées dans l’unité de calcul. Cette dernière retourne des informations concernant
son état à l’unité de contrôle. L’interface du bus gère la communication avec des composants externes (mémoire
et périphérie).

1.4 Le système de bus


1.4.1 Les bus d’adresse, de données et de contrôle
Différents bus relient la CPU aux composants externes. Ces bus permettent d’échanger des informations
concernant l’adresse et les données. Remarque : ce chapitre se limite à l’architecture de « Von Neumann ».

Version 3.1, juin 2008 Page 5


Informatique 3 Architecture d’un microordinateur standard

Bus de contrôle

Bus d’adresse

CPU
Mémoire Mémoire des Périphérie
programme données

Bus de données

Figure 7: Bus d’adresse, de données et de contrôle

Le bus d’adresse permet de transmettre les adresses (pour la sélection des cases mémoires) Avec qui?
aux composants externes (mémoire et périphérie), qui sont connectés à la CPU. Ces adresses
sont déterminées par l’unité de contrôle de la CPU. Souvent des décodeurs d’adresse
supplémentaire doivent être utilisés, afin de pouvoir sélectionner un des composants externes
(voir chapitre 1.4.3).

Le bus de données permet de transmettre les instructions et les données du programme. Ces quoi?
dernières sont
a) lues par la CPU à partir des composants de stockage externes (RAM ou ROM) ou
périphériques.
b) générées par la CPU et écrites dans les composants de stockage externes ou
périphériques.

Le bus de contrôle permet de transmettre des informations supplémentaires pour la gestion de comment?
la communication (read/write, reset, interrupts, requests et acknowledge, handshake etc.).

Exemple :
Le fonctionnent du système de bus peut être illustré plus en détail, à l’aide d’un transfert de données depuis la
périphérie, en passant par la CPU, à la mémoire des données. Exemple : lecture de la température à l’aide d’une
sonde x (périphérie) et stockage de cette dernière dans la variable "temp", qui se situe dans le RAM. En C cella
serait définie de la manière suivante :

int temp = Temperatur_Sensor_x;

1) La CPU dépose l’adresse de l’instruction à lire sur le bus d’adresse. Cette adresse est stockée dans le
compteur de programme (Program counter).
2) La CPU fixe le sens du transfert « lecture », à l’aide du bus de contrôle.
3) La mémoire programme fournit l’instruction stockée dans la case mémoire, qui est sélectionnée par le bus
d’adresse, sur le bus de donnée.
4) La CPU lit cette instruction.
5) La CPU fournit l’adresse du composant périphérique, à partir de laquelle les données doivent être lues, sur
le bus d’adresse.
6) La CPU fixe le sens du transfert « lecture », à l’aide du bus de contrôle.
7) La périphérie fournit l’information, contenue dans la case mémoire sélectionnée, sur le bus de données.
8) La CPU lit les données.
9) La CPU sélectionne la case de destination « temp » dans la mémoire de donnée, à l’aide du bus d’adresse.

Version 3.1, juin 2008 Page 6


Informatique 3 Architecture d’un microordinateur standard

10) La CPU fournit les données sur le bus de données.


11) La CPU fixe le sens du transfert « écriture », à l’aide du bus de contrôle.
12) La mémoire des données saisit les données sur le bus de données, et les stocke dans la case mémoire
sélectionnée par le bus d’adresse.

Bus AMP APE AMD


d’adresse

Bus de DMP DPE DMD


données

Bus de RD RD WR
contrôle

1) 2) 3) 4) 5) 6) 7) 8) 9) 10) 11) 12)

Figure 8 : Le timing du bus

Les abréviations suivantes ont été utilisées dans la Figure précédente :


AMP : Adresse de la mémoire programme
APE : Adresse de la périphérie
AMD : Adresse de la mémoire des données
DMP : Donnée de la mémoire programme
DPE : Donnée de la périphérie
DMD : Donnée de la mémoire des données
RD : Read, lire
WR : Write, écrire

De plus les notations suivantes illustrent l’état de la tension du bus :

La tension du bus est stable et valable, elle est soit high ou low

La tension du bus n’est pas valable ("don't care")

La tension du bus change

1.4.2 Le plan de mémoire


Le plan de mémoire (memory map) définit les zones de mémoires pour les composants externes : comme par
exemple les mémoires externes (programme et données) ainsi que les composants périphériques. La Figure
suivante montre un plan de mémoire pour une zone d’adressage de 64 kilos bytes :

Version 3.1, juin 2008 Page 7


Informatique 3 Architecture d’un microordinateur standard

Adresse A15 A14 A13 A12


Périphérie 0xFFFF 1 1 1 1
0xE000 1 1 1 0
Non utilisé
Non utilisé
RAM 2 0xBFFF 1 0 1 1
(8kByte) 0xA000 1 0 1 0
RAM 1 0x9FFF 1 0 0 1
(8kByte) 0x8000 1 0 0 0
Flash 0x7FFF 0 1 1 1
(32kByte) 0 0 0 0 0

Figure 9 : Exemple d’un plan de mémoire avec un bus d’adresse de 16 bits

Les contrôleurs 8 bits (8 bit définit ici la largeur du bus des données) possèdent généralement un bus d’adresse
de largeur 16 bits. Ils sont ainsi en mesure d’adresser une zone de mémoire de 64 kilos bytes (0xFFFF). Quant
aux microcontrôleurs 32 bits, ils possèdent un bus d’adresse de largeur 32 bits et sont ainsi en mesure d’adresser
une zone de mémoire de 232 bytes (4 Giga bytes).

La taille de la mémoire dépend du type du contrôleur. Les contrôleur 8 bits possède en général quelques kilo
bytes de mémoire. Cela est suffisant, car ces derniers sont destinés aux applications relativement simples, qui ne
nécessitent pas de systèmes d’exploitation. Les contrôleurs 32 bits, qui sont destinés aux systèmes embarqués,
nécessitent en générale plusieurs Méga bytes de mémoire.

1.4.3 Le décodeur d’adresse


La tâche du décodeur d’adresse est de sélectionner un des composants externes. Admettons par exemple qu’un
système à microcontrôleur soit composé de plusieurs composants de stockage (RAM et ROM). Dans ce système,
du bus d’adresse ne suffit pas pour sélectionner un des composants. Par conséquent, il faut utiliser des signaux
de sélection (Chip Select, CS) supplémentaires. Ces signaux sont fournis par le décodeur d’adresse en fonction
des bits de poids plus fort du bus d’adresse.

Les décodages d’adresse simples sont réalisés avec de la logique discrète (AND, OR ou 1 of X decoder). Les
composants nécessaires pour réaliser ce genre de décodeur ne sont pas très chers. Toutefois, la logique discrète
nécessite plus de place sur la platine et elle n’est pas flexible. Par conséquent, les erreurs de conception ou les
éventuelles adaptations du plan de mémoire nécessitent souvent une nouvelle platine.

A cause des problèmes de la logique discrète décrits ci-dessus, les décodeurs d’adresse sont souvent réalisés à
l’aide de la logique programmable (GAL, PAL, CPLD etc.). Le décodeur d’adresse correspondant au plan de
mémoire de la Figure 9 peut être réalisé de la manière suivante :

CS0 Flash
CS1 RAM 1
Adresse Logique
program. CS2 RAM 2
CS3 Périphérie

Figure 10: Décodeur d’adresse programmable

Les équations logiques permettent de programmer ces décodeurs d’adresse. Par exemple les signaux CS pour le
plan de mémoire de la Figure 9 seraient programmés de la manière suivante :

Version 3.1, juin 2008 Page 8


Informatique 3 Architecture d’un microordinateur standard

CS1 = /A15
CS2 = A15 * /A14 * /A13
CS3 = A15 * /A14 * A13
CS4 = A15 * A14 * A13

La Figure suivante montre un schéma bloque d’un circuit contenant un décodeur d’adresse ainsi que des
composants de stockages externes et périphériques. Ce circuit contient une Flash de 32 kilos bits, deux RAM de
8 kilos bits et un convertisseur A/D à 1 Byte:

Bus de données

CS4
CS3 32k * 8 8k * 8 8k * 8 Périphérie
Décodeur RAM 1 RAM 2 (convertisseur
CS2 Flash
d’adresse A/D de 1 byte)
CS1

A0 .. A15 A0 .. A14 A0 .. A12 A0 .. A12

Bus d’adresse

Figure 11: Schéma bloque du circuit avec le décodeur d’adresse, les composants de stockage (Flash et ROM) et
périphérique

Remarque :
Ce schéma bloque ne contient pas les bits de contrôle /RD et /WR.

Le convertisseur A/D est sélectionné avec le chip select CS4. Du fait qu’il ne possède qu’une seule adresse
physique, il sera reproduit dans toute la zone de mémoire réservée à la périphérie. C'est-à-dire que la CPU peut
l’adresser entre 0xE000 et 0xFFFF.

1.5 La mémoire
1.5.1 Les technologies
Fondamentalement il existe les mémoires non volatiles, qui sont utilisée uniquement en lecture, et les mémoires
volatiles, qui peuvent être utilisées en lecture ou en écriture.

Mémoires non volatiles


Ces mémoires conservent leur contenu, même si leur alimentation est coupée. Les différents types de mémoire
non volatile sont les suivants :
• ROM (Read Only Memory) : Programmation par le fabriquant à l’aide de masques.
• EPROM (Erasable Programmable ROM) : Ces mémoires peuvent être programmées plusieurs fois par
l’utilisateur (outils de programmation spécifique) et effacés à l’aide de rayon UV.
• OTP (ou OTP ROM, One Time Programmable ROM) : Ces mémoires sont construites comme les EPROM,
toutefois sans fenêtre. Les OTP ne peuvent être programmées qu’une seule fois par l’utilisateur.
• EEPROM (Electrical Erasable Programmable ROM) : Ces mémoires peuvent être effacées et reprogrammées
case par case durant leur fonctionnement. Les EEPROM ont une capacité réduite (quelques kilos bytes) et
sont, par conséquent, utilisées pour stocker les données de production, comme par exemple les numéros de
série etc.

Version 3.1, juin 2008 Page 9


Informatique 3 Architecture d’un microordinateur standard

• FLASH (la définition exacte est FLASH EEPROM) : Ces mémoires peuvent être effacés électriquement par
bloque durant leur fonctionnement (pas de possibilité d’effacer uniquement des cases, comme avec les
EEPROM). Les FLASH possèdent une grande capacité de stockage (quelques Mégas bytes) et sont, par
conséquent, souvent utilisées pour stocker le code du programme.

Mémoire volatile
Ces mémoires perdent leur contenu dès que leur alimentation est coupée. Ces mémoires sont en générale
qualifiées de RAM (Random Access Memory). Random veut dire que les cases mémoires peuvent être accédées
de façon aléatoire. Il existe les catégories suivantes :
• DRAM (Dynamic RAM) : Ces mémoires stockent l’information à l’aide de condensateur et doivent, par
conséquent, être rafraîchies périodiquement.
• SRAM (Static RAM) : Ces mémoires possèdent une structure plus complexe que les mémoires DRAM mais,
par contre, elles ne doivent pas être rafraîchies périodiquement. Les SRAM sont plus rapide, nécessitent
moins de courant et sont plus cher que les DRAM.
• SDRAM (Synchronous Dynamic RAM) : Ces mémoire sont une version cadencée des DRAM. La fréquence
d’horloge est prédéfinie par le bus du système. Chez les DDR-SDRAM (Double Data Rate SDRAM), les
accès mémoires sont possibles aux flans montant et aux flans descendants de l’horloge.

Aujourd’hui il est également possible de travailler avec des technologies RAM non volatile (FeRAM, MRAM).
Toutefois, ces dernières possèdent une faible capacité de stockage et sont relativement chères.

1.5.2 L’organisation de la mémoire


Les mémoires sont organisées comme un Tableau, qui contient des cases mémoires. La largeur de ces cases
dépend du type de la mémoire et correspond à 1, 8 ou 16 bits.

La Figure suivante montre la structure d’une mémoire organisée en byte :

Mémoire
Adresse Byte
La plus petite adresse 0 0
1 7 0 1
MSB LSB

~ ~

La plus grande adresse n n


Largeur de la mémoire
(ici byte)
Figure 12 : Structure d’une mémoire organisée en byte

Le nombre de bit d’adresses, qui sont utilisés pour adresser la mémoire, dépend de la taille de la mémoire. Avec
m bits d’adresse, il est possible d’adresser 2m cases mémoires. Par exemple avec 16 bits d’adresses, il est
possible d’adresser un do maire de 64 k (ce qui est souvent utilisé avec de microcontrôleur à 8 bits).

1.5.3 Les architectures


Les mémoires sont organisées de tell façon, que les informations sont stockées dans un Tableau des cases
mémoires (Memory-Matrix). L’adressage des cases mémoires s’effectue à l’aide de décodeur d’adresse. Les
signaux de contrôle comme CS, OE, R/W contrôle les driver du bus.

Architecture d’une ROM :

Version 3.1, juin 2008 Page 10


Informatique 3 Architecture d’un microordinateur standard

Row-Decoder
A0 .. Memory-Matrix
An

Column-Output
D0 ..
Dn Column-Decoder

An+1
.. Az

OE Control
CS

Figure 13 : L’architecture d’un composant ROM

Les composants ROM possèdent typiquement un bus de données de largeur 8 ou 16 bits. La largeur du bus
d’adresse dépend de la capacité de stockage. Les signaux de contrôle sont composés d’un CS (Chip Select) pour
la sélection du composant, d’un OE (Output Enable) pour activer des amplificateurs de sortie du bus de données.
La Figure 13 ne contient que les signaux de contrôle, qui permettent la lecture de la ROM. La programmation
nécessite des signaux de contrôle supplémentaires.

L’architecture d’une SRAM :


Row-Decoder

A0 .. Memory-Matrix
An

Column-In/Output
D0 ..
Dn Column-Decoder

An+1
.. Az

OE Control
CS

R/W

Figure 14 : L’architecture d’un composant SRAM

La structure des composants SRAM est identique à celle des composants ROM. Toutefois, le bus de données est
bidirectionnel, afin que la CPU puisse lire et écrire. Un signal de contrôle supplémentaire (Read/Write) est par
conséquent nécessaire, afin de pouvoir définir le sens de la communication. Certain fabriquant utilise même deux
signaux de contrôle distincts (Read et Write) pour réaliser cette tâche.

L’architecture d’un composant SDRAM


Chez les composants DRAM et SDRAM l’adresse n’est pas fournie entièrement sur le bus d’adresse. En effet,
afin de pouvoir réduire de nombre de pin, cette dernière est fournie en deux étapes : d’abord les adresses
colonnes et ensuite les adresses lignes. Deux signaux de contrôle supplémentaires sont donc nécessaires, afin de

Version 3.1, juin 2008 Page 11


Informatique 3 Architecture d’un microordinateur standard

pouvoir signaliser laquelle de ces adresses est fournie sur le bus d’adresse. Ces signaux sont le RAS (Row
Address Strobe) et le (Column Address Strobe) CAS.

Figure 15 : Diagramme de bloc du SDRAM K4S561633F de Samsung (4M * 16 Bit * 4 Banks)

Le comportement temporel de la lecture d’une SRAM est le suivant :

ADDR row address column address

read row address


/RAS

disable output driver


/CAS
read column address
enable output driver

Dout valid

t access RAM

Figure 16: Le comportement temporel de la lecture d’une SDRAM

1.5.4 La documentation
Les caractéristiques les plus importantes des composants de stockage sont décrites dans la documentation, qui est
fournie par le fabriquant. Ces dernières sont typiquement:
• La taille de la mémoire (kilo bit ou kilo byte)
• Assignation des pins
• Organisation de la mémoire (bit, byte ou mot)
• Les caractéristiques DC (tension, consommation de courant ...)
• Les caractéristiques AC (temps d’accès ...)
• Table de vérité (logique de contrôle)

Version 3.1, juin 2008 Page 12


Informatique 3 Architecture d’un microordinateur standard

1.6 La hiérarchie de la mémoire


Chaque technologie de stockage possède ses avantages et ses désavantages. Par conséquent les composants de
stockage sont organisés de façon hiérarchique :

CPU Prix par bit Temps d’accès Capacité

Register Élevé Faible Faible

Cache

Mémoire de travail

Mémoire de masse Faible Élevé Élevé

Figure 17 : Hiérarchie des composants de stockage

Les registres :
Les registres sont des cases mémoire très rapide, destinées au stockage des opérandes et du résultat de l’ALU. La
CPU peut accéder directement aux registres, c’est à dire sans passer par le système de bus (voir également
chapitre 1.3).

La mémoire cache :
La mémoire cache est une mémoire intermédiaire, qui se situe entre les registres et la mémoire de travail. Cette
mémoire rapide est destinée au stockage des instructions (Instruction-Cache) et des données (Data-Cache) du
programme, qui doivent être utilisées souvent.
Les CPU actuelles sont en mesure de travailler à des fréquences d’horloge supérieures à celles de leurs systèmes
de bus. En d’autres thermes, le temps d’accès à la mémoire de travail est supérieur aux cycles d’horloge interne
du processeur, et représente souvent le talent d’Achille des systèmes à microprocesseur. Par conséquent, lorsque
la CPU lit les instructions ou les données à partir de la mémoire de travail, elle les dépose également dans la
mémoire cache. Si ces données doivent être réutilisées, elles seront chargées automatiquement à partie de la
mémoire cache au lieu de la mémoire de travail. Ce procédé est transparent plus l’utilisateur, c'est-à-dire que le
contrôle la mémoire cache est effectué par le hardware.
On parle d’un « Cache Miss », lorsque des données ne sont pas disponibles dans la mémoire cache. Ces données
seront alors lues à partir de la mémoire de travail et stockées dans un « Cache Line », dont la taille est
typiquement de quelques bytes. Lorsque la mémoire cache est pleine, les « lignes de cache » existantes doivent
être sur écrites.
On parle d’un « Cache Hit », lorsque des données à charger sont disponibles dans la mémoire cache. L’accès à
ces données est plus rapide que si elles devaient être lues à partir de la mémoire de travail.
Les mémoires cache possèdent typiquement une taille de 100 kilos bytes. Toutefois, seul les microprocesseurs
puissants possèdent une telle mémoire.
Les mémoires caches peuvent être échelonnées. Le premier échelon est alors une mémoire cache interne, plus
petite mais très rapide (L1). Le second échelon est une mémoire RAM externe, plus grande mais moins rapide
(L2).

La mémoire de travail :
La mémoire de travail est destinée au stockage des instructions (Flash) et des données (SRAM et SDRAM) du
programme (voir également chapitre 1.5).
Dans le monde des ordinateurs personnels (PC), le code est copié depuis la mémoire de masse dans la RAM, et il
est exécuté à partir de cette dernière.
Dans le monde des systèmes embarqués, le code est exécuté soit à partir de la Flash ou il est copié depuis la

Version 3.1, juin 2008 Page 13


Informatique 3 Architecture d’un microordinateur standard

Flash dans la RAM, durant le processus de démarrage (boot), et est exécuté ensuite à partir de cette dernière.

La mémoire de masse :
Les mémoires de masse, comme par exemple les disques dures ou les CD, ne sont pas utilisées dans les systèmes
embarqués. Par contre, ces dernières sont souvent employées dans les PC industriels. Toutefois, il ne faut pas
oublier les désavantages de la mécanique dans les environnements industriels (la température, les vibrations,
l’humidité, la poussière etc.). Par conséquent, on préfère utiliser ici les cartes CF, les cartes SD ou les mémoires
sticks en tant que mémoire de masse.

1.7 La MMU
Die MMU (Memory-Management Unit) est une unité hardware destinée à la gestion de la mémoire. Les
avantages du MMU apparaissent essentiellement avec les systèmes d’exploitation. Avec les processeurs 32 bits,
la MMU est souvent intégrée sur le même chip que celui de la CPU.

La MMU met à disposition les fonctionnalités suivantes :


1. Protection des segments de mémoire des différents programmes : Un système d’exploitation peut ainsi
exécuter plusieurs programmes simultanément. La MMU empêche qu’un programme puisse accéder au
segment de mémoire d’un autre programme. Cette fonctionnalité est très importante pour les systèmes
embarqués, car elle permet d’augmenter leur sécurité.
2. La mémoire de masse peut contenir plus de code que la mémoire de travail. Le code à exécuter est toujours
copié depuis la mémoire masse dans la mémoire de travail. Le code, qui n’est pas utilisé, sera ainsi sur écrit.
Par conséquent, les données, qui ne sont pas utilisées temporairement, doivent être sauvées sur la mémoire de
masse (swapping). Ces fonctionnalités sont importantes dans le domaine de la bureautique, ou de nombreux
programmes sont à disposition sur la mémoire de mass. Par contre, elles ne sont pas importantes dans les
systèmes embarqués.

1.7.1 Les adresses physiques et virtuelles


Les adresses virtuelles ou logiques désignent les adresses, qui sont attribuées au programme par le compilateur /
relieur et qui sont utilisées durant l’exécution du programme dans la CPU. Ainsi il est possible d’exécuter
plusieurs programmes en parallèle, qui possèdent tous une adresse virtuelle de base 0.
Les adresses physiques désignent les adresses, qui sont fournies sur le bus d’adresses durant l’exécution du
programme (adresses physiques des composants).

Æ Le programme et la CPU travaillent avec des adresses virtuelles. Les accès aux composants de
mémoire s’effectuent avec des adresses physiques.

Processeur

CPU
CPU fournit une
adresse virtuelle Mémoire Mémoire de Peripherie
de travail masse

MMU
MMU fournit une
adresse physique pour
accéder à la mémoire

Bus

Figure 18: La MMU entre la CPU et la mémoire

La tâche du MMU est de transformer l’adresse virtuelle en une adresse physique ou de réallocation (relocation).

Version 3.1, juin 2008 Page 14


Informatique 3 Architecture d’un microordinateur standard

Pour obtenir l’adresse physique, la MMU additionne l’adresse virtuelle à la valeur qui est contenue dans les
registres de réallocation (relocation register). Simultanément il contrôle si l’accès au segment est autorisé ou non,
à l’aide des registres de limitation.

Le fonctionnement du MMU peut être schématisé de la manière suivant :

Limit Relocation
register register

jes Work
CPU < + memory
Programm
Virtual Physical
address no address

Address error MMU


Trap

Figure 19 : Schéma bloc simplifié du MMU

Lorsque l’on passe d’un programme à un autre, il faut recharger les registres de réallocation et de limite. Ce qui
est la tâche du système d’exploitation. Chez les processeurs, qui ne possèdent pas de MMU, Les adresses
virtuelles correspondent aux adresses physiques.

1.7.2 Pages et trames, Tableau de pages


La zone de mémoire virtuelle est partagée en blocs de tailles identiques, qui sont appelé « pages ». La zone de
mémoire physique est également partagé en blocs de tailles identiques, qui sont appelé « trames ». La taille des
pages et des trames dépend des systèmes et se situe entre 512 bytes à 16 Méga bytes.

Des Tableaux de pages sont utilisés pour convertir les adresses virtuelles en adresses physiques. Les adresses
virtuelles sont composées des champs suivants :
1. Le numéro de la page, qui indique l’index du Tableau de pages. Le Tableau de pages contient l’adresse de
base de chaque trame (adresse physique).
2. Un offset de page, qui est additionné au contenu du Tableau de pages (adresse de base) pour construire
l’adresse physique.

Version 3.1, juin 2008 Page 15


Informatique 3 Architecture d’un microordinateur standard

Adresse physique

0 1 0 0 0 0 0 0 0 0 0 10 0 0 0

Numéro de trame = 2
obtenu du tableau de
page
15 000 0
14 000 0
13 000 1
12 000 0
11 111 1
Tableau 10 000 0
de page 9 101 1
8 000 0
7 100 1
6 000 0
5 011 1
4 010 1 010
Numéro de page = 4 3 110 1
correspond à 2 000 0
l’indexe du tableau
de page 1 001 1 Offset
bit de
0 000 0 validité

0 1 0 0 0 0 0 0 0 0 0 0 10 0 0 0

Adresse virtuelle

Figure 20 : MMU avec 16 pages de 4 k bytes

La Figure de l’exemple de ci-dessus montre, que les zones de mémoire virtuelles peuvent être plus grandes que
les zones de mémoire physiques. Le bit de validité indique si le contenu du Tableau de pages est valide ou pas.
Si ce n’est pas le cas, les données doivent d’abord être copiées depuis la mémoire de masse dans la mémoire de
travail.

1.7.3 Les tampons auxiliaires de traduction


Les Tableaux de pages peuvent devenir très grand, en fonction de la taille des pages et du volume de mémoire
qu’ils représentent. D’un autre côté, les programmes utilisent relativement peu ces Tableaux (boucle, Tableaux
etc.).

Le calcul des adresses physique peut être optimisé à l’aide des tampons auxiliaires de traduction (Translation
Look aside Buffers abrégé en TLB). Ces derniers sont également intégrés dans la MMU. Le TLB est un Tableau
contenant 8 à 64 entrées, qui correspondent aux entrées des Tableaux de pages.

Version 3.1, juin 2008 Page 16


Informatique 3 Architecture d’un microordinateur standard

Numéro de la Trames Validité modification protection


Page (virtuel) (physique)
36 22 1 0 rwx
18 54 1 1 r x
632 60 1 0 rw
320 52 1 0 rw
Tableau 2 : Exemple de demande pour le TLB

Le TLB contient des informations sur les pages : numéro de la page, trame, bit de validité, bit de modification
(montre si le contenu d’une trame a été modifié et, par conséquent, si ce contenu doit être sauvé avant son
élimination) et bits de protection (droit d’accès sur une trame donnée).

Le processus de la conversion de l’adresse virtuelle en une adresse physique est le suivant : D’abord la MMU
contrôle si la page recherché existe dans le TLB. Pour cela la demande est comparée avec les numéros de page
du TLB. Lorsqu’il y a correspondance (TLB hit), le numéro de la trame est lu directement à partir du TLB.
Lorsqu’il n’y a pas de correspondance (TLB miss), la MMU continue la recherche avec le Tableau de pages.
Finalement une demande est choisie dans le TLB et est remplacée avec le numéro de la page, contenu dans le
Tableau de pages. Le TLB contient par conséquent tous les numéros de pages, qui ont été utilisés récemment.

Adresse virtuelle

CPU Numéro Offset

Page Frame
Number Number

TLB hit

TLB

Numéro Offset Mémoire


Page Frame
Number Number Adresse physique
TLB miss

Page Table

Figure 21 : MMU avec un Tableau de pages et un TLB

1.8 DMA
L’accès direct à la mémoire (Direct Memory Access abrégé par DMA) est un procédé, qui permet de transférer
rapidement les données entre la mémoire de masse, ou les composants périphériques, et la mémoire de travail.
Un contrôleur DMA est nécessaire pour cela.

Sans le contrôleur DMA, les transferts des données entre la périphérie et la RAM doivent passer par la CPU.
Dans ce cas, ce dernier doit gérer les adresses source, les adresses de destination et les registres tampons. Ce
transfert doit bien entendu être programmé et nécessite, par exemple, plusieurs cycles de bus pour ne transférer

Version 3.1, juin 2008 Page 17


Informatique 3 Architecture d’un microordinateur standard

qu’un mot. Ce qui a tendance de fortement ralentir les transferts.

I/O I/O Mémoire

CPU

Figure 22 : Transfert de données à travers la CPU

Le contrôleur DMA permet de transférer les données sans que ces derniers passent par la CPU. La CPU est alors
découplé du bus, afin que contrôleur DMA puisse reprendre le contrôle de ce dernier. La tâche de la CPU se
limite dans ce cas à l’initialisation du contrôleur DMA (adresse source, adresse destination et quantité de
données).

I/O I/O Mémoire

CPU Contrôleur
DMA

Figure 23 : Transfert de donnée avec le DMA

1.9 La périphérie
Les composants suivant sont considérés comme périphériques :
a) Les composants qui permettent d’accéder aux données de l’environnement du système. Ces données sont lues
avec des senseurs ou d’autre type d’interfaces.
b) Les composants qui permettent de transmettre les données à l’environnement du système. Ces données sont
transmises avec des actuateurs ou d’autres types d’interface.

La périphérie représente l’interface entre le processeur et son environnement. Les composants périphériques sont
en général connectés au bus du processeur.

1.9.1 Les amplificateurs de sortie


Les signaux de sortie d’un chip, qui sont fournis à l’aide des pins, doivent être amplifiés. Il existe différents
types d’amplificateur de sortie, dont le choix dépend de l’application.

Version 3.1, juin 2008 Page 18


Informatique 3 Architecture d’un microordinateur standard

D
Port Port Port
Out Out Out

Totem-Pole Open Drain Tri state


Figure 24 : Amplificateur de sortie

Les étages totem pole


Les étages totem pole fournissent toujours un signal à leur sortie. Par conséquent, ils ne peuvent pas être
connectés en parallèle !
a) La logique low est représentée le plus souvent par « 0 »
b) La logique high est représentée le plus souvent par « 1 »

Open Drain
Les sorties Open Drain (avec la technologie FET) ou Open Collector (avec la technologie bipolaire) possèdent
un seul transistor, qui permet de tirer une résistance (Pull-up) contre la masse. Les résistances pull-up peuvent
être sois internes ou externes. Les sorties Open Drain et Open Collector peuvent être connectées en parallèle,
comme par exemple avec les sources d’interruption :

Source Source Source


Pull d’interrup. d’interrup. d’nterrup.
up 1 2 3

IRQx

Figure 25 : Source d’interruption avec des sorties Open Drain

Tri state
Les sorties tri state peuvent avoir un état à haute impédance. L’état de sortie active ou « tri state » est activée à
l’aide d’un signal de contrôle supplémentaire (G).
En générale les sorties, qui fournissent des signaux sur un bus, sont réalisées avec des tri states, comme par
exemple les entrées et sorties des données (I/O) d’une RAM.

1.9.2 Digital Input / Output


Les entrées et sorties digitales sont utilisées respectivement pour la lecture et l’écriture des signaux digitales. Il
existe deux possibilités pour fournir des entrées sorties digitales :

1) Utilisation de pins du microcontrôleur, appelés GPIO. Le nombre de ces pins varie en fonction de la famille
des microcontrôleurs. L’accès à ces derniers s’effectue à l’aide de registres.
2) Utilisation de composants périphériques supplémentaires (FPGA, PIO, …), qui mettent à disposions des I/O.
La communication avec ces composants s’effectue avec le système de bus.

Les entrées et sorties digitales sont utilisées pour connecter les éléments d’affichage (lampes, LED etc.), les
relais, les moteurs, les soupapes etc.

Les sorties digitales possèdent souvent un étage d’amplification, afin qu’elles puissent fournir le courant
nécessaire à la transmission (ex. contrôle des moteurs, des soupapes etc.). Les entrées digitales possèdent
souvent des filtrés (circuit RC et trigger de Schmitt). Elles sont également protégées contre les sur tensions

Version 3.1, juin 2008 Page 19


Informatique 3 Architecture d’un microordinateur standard

(comme par exemple à l’aide de diodes Transzorb et des varistances).

Contrôleur de
Microcontrôleur moteur

Motor

GPIO1
GPIO2
Interrupteur

Protection
d’entrée

Figure 26 : Exemple d’utilisation de GPIO

1.9.3 L’interface sérielle


Les interfaces sérielles sont utilisées pour transmettre des données de façon sérielle (ex. RS232, I2C, SPI,
FireWire, USB etc.). Un registre à décalage est nécessaire pour convertir les données, depuis le format parallèle
en séquence de bits, afin de pouvoir réaliser la transmission.

Les propriétés les plus important de la transmission sérielle sont les suivants :
• Le nombre de bit par seconde (baud rate)
• La tension
• Le protocole

TxD RxD Steuersignale

Sende-Schieberegister Empfangs-Schieberegister Control-Register

CPU

Figure 27: Principe de fonctionnement d’une interface sérielle

1.9.3.1 RS232
L’interface RS232 est très importante dans le domaine des systèmes embarqués. Cette interface permet par
exemple de gérer un affichage LCD ou une ligne de commande (Command Line Interface). La plupart des
microcontrôleurs possèdent déjà une interface RS232. Toutefois, les tensions de sortie de ces dernières
correspondent au niveau TTL. Par conséquent, un convertisseur de tension externe doit être ajouté au système.

Les interfaces RS232 sont accessibles à l’aide de registres.


• Les tampons de transmission et de réception, contiennent 1 byte. Les deux tampons possèdent souvent la
même adresse, car il n’est possible que d’écrire dans le tampon de transmission et de lire à partir du tampon
de réception.
• Les registres de contrôle, qui permettent de définir les modes de fonctionnement (la fréquence de

Version 3.1, juin 2008 Page 20


Informatique 3 Architecture d’un microordinateur standard

transmission (baud rate), le format des données, le bit de parité etc.) et les interruptions.

Les interfaces RS232 soutiennent différents modes de fonctionnement. Par exemple ils peuvent fonctionner soit
en mode synchrone ou en mode asynchrone. La fréquence de transmission est souvent définie avec un timer
standard. Certaine interface RS232 possèdent toutefois leur propre générateur de fréquence. Le timer peut ainsi
être utilisé pour d’autres applications.

Le schéma bloc de l’interface RS232 est typiquement le suivant :

Transmitter

Transmit FIFO

Transmit Holding Register

Transmit Shifter TxD


Internal Bus

Control Baudrate
Unit Generator

Receiver
Receive Shifter RxD

Receive Holding Register

Receive FIFO

Figure 28 : Schéma bloc de l’interface RS232 du microcontrôleur C515C


(Source: Manuel d’utilisation du C515C)

1.9.3.2 SPI
L’interface SPI (Serial Peripheral Interface) est un système de bus sériel à haut débit, destiné à la communication
entre le microcontrôleur et la périphérie. Ce dernier est souvent utilisé pour la communication avec des
extensions I/O, des affichages LCD ainsi que des convertisseurs A/D et D/A. Il peut également être utilisé pour
la communication entre microcontrôleurs.

La Figure 29 montre le principe de fonctionnement du SPI.

Version 3.1, juin 2008 Page 21


Informatique 3 Architecture d’un microordinateur standard

Entré des données Générateur de la Entré des données


en parallèle fréquence d’horloge en parallèle

7 0 7 0

Sortie des données Sortie des données


en parallèle en parallèle

Participant 1 Participant n

Figure 29 : Principe du SPI

L’interface SPI est toujours utilisée en mode maître esclave. Le maître est alors responsable de la génération de
la fréquence d’horloge. Le SPI peut travailler de façon duplexe à l’aide de deux lignes de transmission : MOSI
(Master Out Slave In) et MISO (Master In Slave Out). Les esclaves peuvent être connectés soit de façon
parallèle (c’est à dire que toutes les sorties des esclaves sont rassemblée et connectées à l’entré MISO du maître)
ou de façon sérielle (la sorite d’un esclave est connectée à l’entrée du prochain esclave et la sortie du dernier
esclave est connecté à l’entrée MISO du maître).
Le microcontrôleur écrit les données à transmettre dans un tampon de transmission. Ces dernières sont
sérialisées à l’aide d’un registre à décalage (comme une transmission RS232). Les données reçues sont
également converties à l’aide d’un registre à décalage. Le microcontrôleur peut alors lire ces données de façon
parallèle dans le tampon de réception. Du fait que les interfaces SPI ont une bande passante relativement élevé,
les tampons de transmission et de réception contiennent souvent plusieurs bytes.

Donnée Donnée

Registre à Registre à
décalage décalage

Esclave SPI 2 Esclave SPI 1

MOSI
MISO
SCK

Sélection Horloge Registre à


esclave décalage

FIFO de FIFO de
SPI maître réception tansmission

Figure 30 : SPI avec un maître de deux esclaves

Version 3.1, juin 2008 Page 22


Informatique 3 Architecture d’un microordinateur standard

1.9.3.3 I2C
Le bus I2C (Inter Integrated Circuit) a été développé par l’entreprise Philips. Ce bus est utilisé pour connecter
les composants périphériques comme l’ EEPROM, les affichages LCD ou RTC (Real Time Clock) au
microcontrôleur.
Le bus I2C est composé de deux fils, ce qui réduit la partie hardware de façon drastique. Ce bus comprend une
ligne d’horloge SCL (Serial Clock) et une ligne de donnée SDA (Serial Data). La communication est par
conséquent synchrone. Les modes d’utilisation du bus sont maître et esclave.

La Figure suivante illustre une application typique avec le bus I2C :

Figure 31 : Application avec un bus I2C

Le protocole est défini de la manière suivante:

Figure 32 : Le maître (transmetteur ) adresse l’esclave (récepteur) avec une adresse composé de 7 bits et envoi 2
bytes de données

Le transfert de données entre le maître et l’esclave s’effectue de la manière suivante :


1. Le maître démarre le transfert des données en envoyant le bit de démarrage. Tous les esclaves entrent
ainsi dans un état passif d’écoute.
2. Le maître envoie ensuite l’adresse de l’esclave, avec lequel il aimerait communiquer. Cette adresse est
composée de 7 bits.
3. Le maître envoi le bit R/W, qui fixe le sens de la communication : Ecriture depuis le maître à l’esclave ou
lecture depuis l’esclave au maître
4. Le protocole I2C exige des confirmations (acknowledge) après chaque transmission d’un byte. L’esclave
accrédite avec le premier bit de confirmation, qu’il est prêt pour la communication.
5. Le transfert de données a lieu entre le maître et l’esclave. Un bit de confirmation est également échangé ici
après chaque transmission d’un byte. Ce bit est fourni par le maître dans le mode lecture et par l’esclave
dans le mode écriture.
6. Le transfert se termine avec un bit d’arrêt.

Le nombre de bytes à transmettre et le sens de la transmission peuvent varier selon les composants utilisés. Ces
informations sont fournies par documentation de ces derniers. Par exemple : le maître n’écrit qu’un byte dans
un convertisseur D/A. Alors qu’avec une EEPROM, qui possède une zone de mémoire interne, le maître doit
d’abord envoyer l’offset de la case mémoire à accéder. Le transfert de données n’est effectué qu’ensuite,
jusqu'au bit d’arrêt.

Version 3.1, juin 2008 Page 23


Informatique 3 Architecture d’un microordinateur standard

Le Tableau suivant illustre quelques exemples de transmission de données avec l’interface I2C (le bit
confirmation n’est pas affiché) :

Composant Protocole
Convertisseur Démarrage Adresse Wr Données Arrêt
D/A de
l’esclave
Ecriture RAM Démarrage Adresse Wr Données Données Arrêt
de
l’esclave
Lecture RAM Démarrage Adresse Wr Données Arrêt Démarrage Adresse Rd Données Arrêt
de de
l’esclave l’esclave
Figure 33 : Exemple pour le protocole I2C

Le protocole I2C est défini au niveau électrique de la manière suivante :


Niveau de pause :
Le niveau de pause est high.
Condition de démarrage :
La condition de démarrage est définie par un flanc descendant sur SDA, suivi d’un flanc descendant sur SCL. Ce
signal est univoque et n’apparaître pas durant une transmission normale.
Condition d’arrêt:
La condition d’arrêt est définie par un flanc montant sur SCL, suivi d’un flanc montant sur SDA. Ce signal est
également univoque et n’apparaît par durant une transmission normale.

SDA

SCL

Start Stop

Figure 34 : Condition de démarrage et d’arrêt

Les bits de données :


La valeur du signal SDA est fixée en fonction du bit à transmettre : 0 = low, 1 = high. La validité est signalée
avec un flanc montant du signal SCL. La lecture et l’écriture des bits de données ont toujours lieu pendant que le
signal SCL est haut.
ACK :
Le bit de confirmation (Acknowledge) veut dire que la réception est a été bonne ou que le récepteur est prêt pour
des transmissions supplémentaires. Du point de vu du maître, l’esclave doit confirmer chaque byte écrit. Du
point de vu de l’esclave, le maître doit confirmer chaque byte lu. Si ces confirmations n’ont pas lieu, le processus
de transmission sera rompu avec le bit d’arrêt.
NACK :
Not Acknowledged signal une erreur de transmission ou la fin de la disposition à recevoir.

Version 3.1, juin 2008 Page 24


Informatique 3 Architecture d’un microordinateur standard

SDA 1 0 0 1 0 1 1 1

SCL

Start Slave-Adressse R/W ACK Stop

Figure 35: Transmission au niveau bit

Dans la Figure 35, le maître envoi en premier la condition de démarrage, ensuite il envoi l’adresse de l’esclave
(1001011) et pour finir le bit R/W. L’esclave doit signaler sa présence avec le bit de confirmation. Il est
important que le maître maintienne le SDA à un état haute impédance durant cette phase. Les données peuvent
être transmis après le bit de confirmation (cela n’est pas montré dans la Figure). La communication est
interrompue avec le bit d’arrêt.
Admettons que l’on veut connecter un émetteur à plusieurs participants avec un bus I2C. Dans ce cas tous les
participants doivent se mettent dans un état à haute impédance. Certain microcontrôleur peuvent conFigurer leurs
sorties en tri state. Si cela n’est pas possible, il faut conFigurer les pins SCL et SDA en entrée.

1.9.4 Le timer
Le timer est utilisé comme base de temps dans les processeurs (système d’exploitation, horloge etc.) ou pour les
composants externes (ex. signal PWM, horloge pour les interfaces sérielles ...).

Oscillateur

Timer
Mode Timer / Counter Overflow
Register Flag
Counter
Entrée
externe

Figure 36 : Principe de fonctionnement du timer

En générale des registres de 8 ou 16 bits sont utilisés dans les timers ou les compteurs. Dans le mode timer, ces
registres sont incrémentés périodiquement à l’aide de l’horloge interne du système. Dans le mode compteur,
cette incrémentation s’effectue en fonction de signaux externes.

Lorsqu’il y dépassement de capacité (c'est-à-dire au passage de 0xFFFF à 0 avec un registre de 16 bits), le


drapeau (flag) d’overflow est mis à un. Ce dernier peut être observé à l’aide d’une boucle software (polling) ou il
peut générer une interruption.

Le mode « de rechargement automatique» (auto reload) permet d’initialiser le registre du timer avec une valeur
prédéfinie, qui est contenue dans le « registre de rechargement » (reload register). Ce qui permet de générer des
signaux avec des périodes variables.

Version 3.1, juin 2008 Page 25


Informatique 3 Architecture d’un microordinateur standard

Oszillator Timer Overflow


Register Flag

Reload

Reload
Register

Figure 37: Timer dans le mode de rechargement automatique

Dans le mode de rechargement automatique, il n’y a pas seulement une mis à un du flag overflow, mais le
compteur du timer est également initialisé avec la valeur du registre de rechargement.

1.9.5 Les convertisseurs A/D


Les convertisseurs A/D mesurent une tension analogique à leur entrée, comparent cette tension avec des tensions
de référence, et en fournissent l’équivalent digital à leur sortie. Le microcontrôleur peut lire cette valeur soit avec
un système de bus ou avec un interface sériel (comme par exemple le SPI).
Les convertisseurs A/D possèdent souvent plusieurs entrées analogiques, qui peuvent être sélectionnées à l’aide
d’un multiplexeur.

Les caractéristiques les plus important pour un convertisseur A/D sont les suivants :
• Largeur de bit (les valeurs typiques sont 8, 10, 12 ou 16 bits)
• Temps de conversion

Analog Inputs VREF

MUX S&H A/D


Converter

Control-Register Data-Register

CPU

Figure 38 : Principe d’un convertisseur A/D

1.9.6 Les convertisseurs D/A


Les convertisseurs D/A lisent une valeur digitale à leur entrée, convertissent cette valeur en une tension
analogique et fournissent cette dernière à leur sortie.

Les caractéristiques les plus important pour un convertisseur D/A sont les suivants:
• Largeur de bit (les valeurs typiques sont 8, 10, 12 ou 16 bits)

Version 3.1, juin 2008 Page 26


Informatique 3 Architecture d’un microordinateur standard

• Temps de conversion

La conversion D/A peut être également effectuée avec une sortie PWM, qui est connectée à un filtre passe bas.

1.10 Les types de processeur


Un processeur est un chip qui contient au minimum un CPU. Il existe plusieurs sorte de processeurs : les
microprocesseur, les microcontrôleur et les DSP. Dans les chapitres suivants l’expression processeur représente
tous les types de processeur.

1.10.1 Les microprocesseurs


Un microprocesseur contient uniquement une unité de contrôle et une unité de calcul. Tous les composants de
stockage et périphériques sont externes. Par conséquent, ils ne sont accessibles qu’avec le système de bus.

1.10.2 Les microcontrôleurs


Les microcontrôleurs sont conçus essentiellement pour les applications de contrôle et sont, par conséquent,
optimisés au niveau du coût. En plus de la CPU, ils contiennent également de la mémoire interne, pour le
stockage des instructions et des données du programme, ainsi que des modules périphériques (en fonction de la
famille des microcontrôleurs).

1.10.3 Les DSP


Les DSP sont conçus pour les applications de traitement du signal digital, qui nécessitent des puissances de
calcul élevées. Ils sont utilisés pour l’exécution d’algorithmes complexes (ex filtrage, transformation de Fourier
etc.). Un DSP contient toujours un module pour la multiplication. Une opération de multiplication et d’addition
peut ainsi être effectuée simultanément, en un seul cycle d’horloge. L’architecture des DSP est normalement
celle de Harvard.

1.10.4 CISC / RISC


RISC et CISC sont des notions différentes pour définir les jeux d’instructions. Elles sont utilisées autant avec les
microprocesseurs qu’avec les microcontrôleurs.

Complex Instruction Set Computer (CISC): Les instructions peuvent être relativement complexes. Une seule
instruction assembleur est subdivisée en une séquence de micro instructions. L’exécution d’une instruction
nécessite donc plusieurs cycles d’horloge. Le micro programme est intégré par le fabricant. Par conséquent,
l’utilisateur n’y a pas d’accès.

Reduced Instruction Set Computer (RISC): Les instructions sont relativement simples. Il n’y a pas se micro
instructions et les instructions sont exécutées directement.

1.11 Exemple de famille de microcontrôleur


Les sections suivantes décrivent les familles de microcontrôleur les plus répandues.
Les microcontrôleurs se distinguent par leur puissance de calcul et par leurs modules périphériques tel que :
• Mémoire (ROM / Flash, RAM, EEPROM)
• GPIO
• Timer
• Interface sérielle
• Convertisseur A/D

Version 3.1, juin 2008 Page 27


Informatique 3 Architecture d’un microordinateur standard

• PWM
• CAN
• USB

Le Tableau suivant fournit un aperçu des familles de microcontrôleur.

Famille Description brève


8051 La famille 8051 est la famille la plus connue et la plus répandue des contrôleur 8 bits.
Plusieurs fabricants fournissent des dérivées de ce microcontrôleur, qui se distinguent par
leurs modules périphériques. Le 8031 de INTEL est considéré ici comme le précurseur.

PIC Le PIC est une famille de contrôleur de 8, 16 et 32 bits de Microchip. Il est utilisé avant tout
dans les applications à bas prix et à basse consommation.

68HCxx Les familles 8 bits de Motorola 68HC05, 68HC08 et 68HC11 sont très répandues dans
l’industrie et dans l’enseignement. Cependant, elles ne sont plus très utilisées dans les
nouvelles applications.

MC683xx Le contrôleur 32 bits de Motorola se base sur la CPU32. Les registres de la CPU ont une
largeur de 32 bits. En fonction du contrôleur, le bus de données peut contenir 16 à 32 bits et
le bus d’adresse 24 à 32 bits. Ces contrôleurs sont utilisés pour des applications, qui
nécessitent des puissances de calcul moyennes, comme la télécommunication et l’industrie
automobile. La famille est construite de façon modulaire et contient plusieurs membres.
Cette famille est remplacée dans les nouvelles applications par celle du ColdFire.

ColdFire La famille des ColdFires remplace celle des MC683xx de Motorola. ColdFire est un
processeur de 32 bits pur, c. à d. qu’il contient des bus d’adresse et de données de 32 bits.
Les processeurs ColdFire possèdent la même architecture que ceux 683xx. Toutefois, ils
sont plus puissants que leurs prédécesseurs.

ARM La société ARM propose des cœurs divers, qui sont fabriqués sous licence par différentes
compagnies. ARM est une abréviation pour Advanced RISC Machine. Actuellement les
familles ARM7 et ARM9 (tous deux à 32 bits) sont très répandues dans le domaine des
contrôleurs embarqués. Ces contrôleurs fournissent une bonne puissance de calcul pour une
consommation relativement basse.

MSP430 Le MSP40 est une famille de contrôleur du type RISC à 16 bits, produite par TI. Il est
utilisé avant tout dans les applications à consommation ultra basse (ex. les appareils à
batteries).

AVR, SAM Différentes familles de contrôleur de la compagnie Atmel comme AVR (processeur 8 bits
RISC), AVR32 (architecture 32 bits avec un DSP et la fonctionnalité SIMD) ou AT91SAM
(contrôleur très bon marché qui se base sur l’architecture ARM7). Ces contrôleurs ont une
grande croissance dans le domaine de l’électronique embarqué.

Tableau 3 : Différents familles de microcontrôleur

1.12 Les critères pour le choix d'un microcontrôleur


Plusieurs critères jouent un rôle plus ou moins important dans le choix d’un processeur. Le poids de ces critères
peut varier en fonction du projet :
• Puissance de calcul (MIPS, FLOPS)
• Largeur de bus (Bus de données et d’adresse, registres CPU)
• Consommation électrique
• Prix

Version 3.1, juin 2008 Page 28


Informatique 3 Architecture d’un microordinateur standard

• Disponibilité de deuxième source


• Composants périphériques (Timer, UART etc.)
• Carte d’évaluation et support du développement

L’expérience du développeur et la disponibilité d’environnement de développement et de test jouent souvent un


rôle non négligeable.

Version 3.1, juin 2008 Page 29


Informatique 3 Le microcontrôleur PXA270

2 Le microcontrôleur PXA270
La première partie de ce chapitre traite les différentes versions de l’architecture ARM. La seconde partie décrit le
digramme de block et le modèle des registres du microcontrôleur PXA270 de Intel. Ce chapitre se limite
toutefois aux tâches, qui sont prioritaires pour la programmation de ce dernier. Les tâches plus spécifiques sont
fournies dans les manuels d’utilisateur Intel [1] à [8] ou par la littérature spécialisée [10] ou [11].

2.1 L’architecture ARM


Les processeurs ARM ont été développés (entre 1983 et 1985) par la société Acorn Computers Limited à
Cambridge (Angleterre). C’était la première utilisation commerciale d’un processeur RISC. La société ARM
Limited (Advanced RISC Machines Limited) a été créée en 1990, afin de continuer de développer cette
technologie.

Les microprocesseurs, qui sont basés sur l’architecture ARM, sont actuellement très répondus. Les raisons en
sont multiples :
• Architecture commune
• Puissance de calcul élevée
• Faible consommation (typiquement moins d’un Watt)
• Coût réduit

Les domaines d’utilisation sont les suivants :


• Les systèmes embarqués (téléphone mobile, PDA, les tâches de contrôle)
• Les applications en relation avec la sécurité
• Plateforme pour différents systèmes d’exploitations

Les caractéristiques les plus importantes de l’architecture ARM sont les suivantes :
• Les caractéristiques typiques de l’architecture RISC :
− Un grand banc de registre à 32 bits
− Architecture « Load / Store », car les opérandes doivent être copiées dans les registres. La CPU ne peut
pas traiter les données, qui sont stockées dans de la mémoire.
− Les instructions sont orthogonales
− Adressage simple à l’aide des registres standard
− Trois modes d’adressage
− La longueur des instructions est fixe (32 bits). Ce qui simplifie le décodage des instructions.
• Les propriétés typiques de l’architecture ARM:
− Une instruction unique permet d’utiliser l’ALU avec le « barrel shifters » (shift left / right)
− Incrémentations et décrémentations automatiques des différents modes d’adressages
− Opérations « Load / Store » simultanées pour plusieurs registres
− Exécution conditionnelle des instructions (conditional execution)
− Les types de données byte (8 bits), halfword (16 bits) et word (32 bits)
− Les jeux d’instructions ARM à 32 bits, Thumb à 16 bits et Jazelle. Ce dernier est prévu pour l’exécution
du code byte Java
• L’ARM possède un système de traitement des interruptions simple et efficace, avec des bancs de registres
fantômes. Ces derniers sont mis à disposition pour les différents types d’exception, qui sont les suivants :
− Les interruptions rapides
− Les interruptions normales
− Memory abort (pour la MMU et la protection de la mémoire)
− Exécution d’une instruction non définie
− Les interruptions software

Version 3.1, juin 2008 Page 30


Informatique 3 Le microcontrôleur PXA270

• Les registres d’état : L’état actuel du processeur est stocké dans le registre « Current Program Status Register
(CPSR) » (voir chapitre 2.6):
− 4 bits d’état
− 2 bits pour la désactiver les interruptions
− 5 Bits pour le mode du processeur
− 1 bit pour le mode ARM ou Thumb

ARM propose plusieurs versions d’architecture. Les nouvelles versions sont compatibles avec les anciennes. Ces
dernières mettent à disposition de nouvelles instructions et de nouvelles fonctionnalités hardware. Chaque
version d’architecture est déclinée en différentes familles, qui à leur tour possèdent différents cœurs (Core). Le
Tableau suivant en fournit un aperçu :

Version 3.1, juin 2008 Page 31


Informatique 3 Le microcontrôleur PXA270

Architecture Brève description Famille / Coeur


ARM
v1 (1983) Première version de l’architecture ARM de Acorn Computers, ARM1
basée sur la CPU 6502.
Adressage à 26 bits
Pas de multiplication et de co-processeur
v2 Premier chip commercial, ARM2
Adressage à 26 bits, bus de données à 32 bits, multiplication
fournissant un résultat à 32 bits,
architecture simple : 30'000 transistors, basse consommation, v2
ne possède pas de mémoire cache, v2a est la première version
avec une mémoire cache,
soutient le co-processeur
v3 (1991) Première version de ARM Limited. ARM6, ARM600,
Processeur indépendant ou intégré dans un CPU en tant que ARM610,
cellule macro. ARM7, ARM700,
On-Chip-Cache, MMU, adressage à 32 bits, les registres CPS et ARM710
SPS sont séparés.
35'000 transistors.
La version V3M soutient les instructions « Multiply-
Accumulate », fournissant un résultat de 64 bits.
v4 La plus vieille architecture ARM, qui est encore soutenue StrongARM, ARMS,
aujourd’hui. ARM810
Nouvelle instructions pour charger et stocker des demi mots
signés et non signés (16 bits) ainsi que des bytes signés.
Introduction du mode système.
V4 possède pour la première fois d’une définition formelle.
v4T Nouveau format comprimé à 16 bits (Thumb) des jeux ARM7TDMI,
d’instruction. ARM710T, ARM740T,
ARM9TDMI,
ARM920T, ARM940T
v5TE (1999) Amélioration des instructions Thumb. XScale,
Nouvelles instructions, comme par exemple BLX, CLZ et BRK. ARM9E-S,
Extension du jeux d’instruction pour le traitement du signal ARM10TDMI,
(support DSP) de la version E, comme par exemple les instruction ARM1020E
à cycle unique 16*16 et 16*32 MAC.
v5TEJ (2000) Introduction de la technologie Jazelle, pour exécuter de façon ARM926EJ,
optimale le code byte Java. ARM1026EJ
Cela est plus rapide qu’une machine virtuelle Java (Java Virtual
Machine) implémenté en software.
v6 (2001) Soutient des environnements multiprocesseurs. Instruction ARM1136J,
multimédia qui soutiennent le SIMD, comme par exemple le ARM1156T2
MPEG4.
TrustZone : partage de l’espace d’adressage physique dans une
partie sure et un partie non sure.
6 nouveaux bits d’état (GE [3:0], bit E, bit A).
v7 Trois profiles de processeur sont soutenus : Coretex-M3, Coretex-R4,
A : Les applications pour utilisateur générales Coretex-A8
R : Système temps réel
M : Serial Wire Debug (SWD) pour les microcontrôleur et les
application bas coûts, afin de réduire le nombre de Pins.
Version améliorée du jeu d’instruction Thumb.
Tableau 4 : Aperçu des architectures ARM

Divers familles de processeur ARM sont proposées pour une version d’architecture donnée (Par exemple :
ARM7, ARM9, ARM10 etc.). Au sein d’un famille il existe plusieurs cœurs (Par exemple : ARM7TDMI,

Version 3.1, juin 2008 Page 32


Informatique 3 Le microcontrôleur PXA270

ARM740T). La nomenclature pour ces derniers est la suivante :

ARM{x}{y}{z}{T}{D}{M}{I}{E}{J}{F}{S}

x: Famille
y: Gestion de mémoire / unité de protection
z: Mémoire cache
T: Décodeur d’instruction Thumb à 16-bit
D: Débuggeur JTAG
M: Multiplication rapide
I: Embedded ICE Macrocell
E: Instruction améliorée
J: Jazelle (code byte Java)
F: Unité à virgule flottante vectorielle
S: Version synthétisable

Tous les cœurs, qui ont été développés après le ARM7TDMI, contiennent les fonctionnalités TDMI.

Aujourd’hui il existe beaucoup de fournisseur de technologie silicium, qui possèdent des licences du cœur ARM
et qui les implémentent dans leur microcontrôleur. Voici un aperçu de ces fabricants : Analog Device, Atmel,
Freescale, Infineon, Intel, NEC, Philips, Samsung, TI et Toshiba.

2.2 Intel XScale


2.2.1 L’architecture XScale
L’architecture XScale est basée sur l’architecture ARMv5TE, dont le schéma bloque est illustré à la Figure 39 :

Figure 39 : Architecture Intel XScale, référence source : [6]


L’architecture XScale possède en supplément du XScale Execution Core, qui sera décrit dans le chapitre 2.2.2 de
façon plus détaillée, les unités suivantes:

Version 3.1, juin 2008 Page 33


Informatique 3 Le microcontrôleur PXA270

• Une mémoire cache pour les instructions de 32 kilos bytes (Instruction Cache abrégé par I-Cache). Les
segments de codes, qui sont souvent exécutés, sont stockés momentanément dans l’I-Cache. Le cœur du
processeur peut accéder à ces instructions à la fréquence d’horloge interne. Le I-Cache travaille avec des
adresses virtuelles ! Il améliore la performance du processeur, mais il n’influence pas son comportement de
façon déterminante.
• Une mémoire cache pour les données de 32 kilos bytes (Data Cache abrégé par D-Cache), qui permet de
stocker momentanément les données. Le D-Cache contient les données, qui sont souvent utilisées comme Par
exemple : les Tableaux, les coefficients etc.
• Mini D-Cache : Mémoire intermédiaire supplémentaire de 2 kilos bytes pour des données, qui doivent être
modifiées rapidement comme les entrées vidéos MPEG. Ce qui empêche que les données, qui doivent être
souvent modifiées, ne remplissent la mémoire cache.
• Write Buffer: Mémoire intermédiaire de 8 fois 16 bytes pour les données, qui doivent être stockées dans la
mémoire externe.
• La MMU pour les instructions (abrégé en anglais par IMMU) : Le IMMU est responsable de la conversion
des adresses virtuelles des instructions en adresses physiques, des droits d’accès, de la gestion des domaines
de la mémoire et du contrôle des attributs de l’I-Cache. Le IMMU contient un TLB avec 32 entrées selon le
principe de Round-Robin.
• La MMU pour les données (abrégé en anglais par DMMU): le DMMU est responsable de la conversion des
adresses virtuelles des données en adresses physiques, des droits d’accès, de la gestion du domaine de la
mémoire et du contrôle des attributs du D-Cache ou du mini D-Cache. Le DMMU contient également un
TLB avec 32 entrées.
• Branch Target Buffer (BTB): Le BTB réalise des prévisions statistiques sur le déroulement des sauts de
programme conditionnels. Cela est important pour le pipeline des adresses des instructions (voire chapitre
2.2.3). Lorsque cette prévision est erronée, il faut vider le pipeline (pipeline flush) afin de le remplir avec des
nouvelles instructions. Les prévisions suivantes sont possibles :
− Strongly taken: Le saut de programme a toujours été réalisés jusqu’à présent. L’adresse de destination
sera stockée.
− Weakly taken: Le saut de programme a souvent été réalisé jusqu’à présent. L’adresse de destination sera
stockée.
− Weakly not taken: Le saut de programme n’a été réalisés que rarement. L’adresse de la prochaine
instruction sera stockée.
− Strongly not taken: Le saut de programme n’a jamais été réalisé. L’adresse de la prochaine instruction
sera stockée.
• Core Memory Bus: Ce bus interne de 64 bits possède une bande passante de 4.8 Gigas Bytes / sec. Ce bus est
capable de lire 32 bits et d’écrire 32 bits simultanément en une seule période d’horloge. La bande passante de
correspond donc à 2.4 Gigas Bytes / sec pour chaque sens.
• Coprocessor Interface: Transfert de données de 32 bits entre le coprocesseur et la mémoire cache des
données.
• Coprocessor 15 (CP15): Les registres de contrôle des mémoires cache, de la MMU et du TLB.
• Coprocessor 14 (CP14): Les registres de contrôle du moniteur de performance (Performance Monitoring), du
débuggeur software et du mode d’horloge / puissance. Le moniteur de performance permet d’analyser le
comportement de la mémoire cache, celui du TLB ou la précision des prévisions du Branch Target Buffer.
• Multiply-Accumulate Coprocessor (CP0): Ce coprocesseur permet de réaliser des multiplications 16*16 bits,
en mode standard ou en mode dual (SIMD), et des multiplications 16*32 bits avec un accumulation de 40
bits.
• JTAG : « Boundary Scan Interface » est un interface standard destine aux testes.
• Debug : Le Debug permet de déboguer le programme durant son exécution (break points pour les instructions
et les données, Trace Buffer), en utilisant l’interface JTAG.
• Trace Buffer: Pour le déroulement de l’exécution du programme.

2.2.2 Le coeur d’exécution du XScale


La Figure suivante montre le transfert des données au sein du coeur d’exécution :

Version 3.1, juin 2008 Page 34


Informatique 3 Le microcontrôleur PXA270

Data

Sign extend

Write Read

r15 (PC) Registerbank Rd


r0 – r15
Rn Rm B-Bus
A-Bus

Barrel shifter

A B Acc

ALU MAC

Result-Bus
Address register
Incrementer

Address

Figure 40: Le transfert des données au sein du XScale, référence: [10]

Le traitement des données au sein des ARM / XScale s’effectue toujours à l’aide de registres. Il n’existe pas
d’instruction, qui soit capable de traiter directement de contenu de la mémoire. Les données sont donc
transférées dans le banc de registres, qui est composé de 16 registres de 32 bits.
La plupart des instructions ARM interprètent le contenu des registres comme des valeurs entières 32 bits
(signées ou non signées). L’unité « Sign extend » permet de convertir les valeurs signées 8 et 16 bits, qui ont été
lues à partir de la mémoire externe, en des valeurs signées 32 bits.
La plupart des instructions ARM traite deux opérandes (Rn et Rm). Le contenu de ces registres est transférer
avec les bus internes A et B. Le second opérande Rm peut être également décalé, soit vers la gauche ou vers la
droite, avec le « Barrel Shifter ».
L’ALU (Arithmetic Logic Unit) ou le MAC (Multiply Accumulate Unit) traitent les opérandes Rn et Rm, et
écrivent le résultat dans le registre (Rd).
Les instructions Load / Store permettent de transférer les données, soit à partir de la mémoire externe dans un
registre, ou inversement à partir d’un registre dans la mémoire externe. L’adresse de la case mémoire à
sélectionner est calculée par l’ALU. Cette dernière est copiée dans le registre d’adresse, afin d’être fournie sur le
bus d’adresse. L’incrémenter (Incremented) permet d’incrémenter ou de décrémenter cette adresse, après chaque
opération d’écriture et de lecture.

2.2.3 Le super pipeline du XScale


Les instructions à exécuter sont stockées dans un pipeline dans la plupart des processeurs. Le pipeline permet
simultanément d’exécuter l’instruction courante et de charger l’instruction suivante. Toutefois le pipeline
présente un désavantage, qui apparaît avec les sauts de programme conditionnels. Dans ce cas, il faut
systématiquement vider le pipeline, lorsque le comportement du programme a été mal prédit.
Le comportement du pipeline peut être expliqué à l’aide du pipeline à trois nivaux de l’ARM7. Le pipeline du
XScale est plus complexe et sera décrit plus loin.

Les niveaux du pipeline à 3 niveaux sont les suivants :


1) Fetch: Lecture de l’instruction à partir de la mémoire programme.

Version 3.1, juin 2008 Page 35


Informatique 3 Le microcontrôleur PXA270

2) Decode: Identification de l’instruction à exécuter.


3) Execute : Exécution de l’instruction à exécuter

Les trois étages (stage) du pipeline doivent être exécutés pour chaque instruction. L’exécution de chaque étage
nécessite un cycle d’horloge. Par conséquent, l’exécution d’une instruction complète nécessite trois cycles
d’horloge. Ce système permet toutefois d’exécuter une instruction par cycle d’horloge, car le pipeline traite
simultanément plusieurs instructions. L’exemple suivant illustre ce procédé :

Fetch Decode Execute

Cycle 1 Instr. 1

Cycle 2 Instr. 2 Instr. 1


time

Cycle 3 Instr. 3 Instr. 2 Instr. 1

Figure 41 : Exemple de pipeline à 3 niveaux


Au premier cycle d’horloge, l’instruction 1 est lue à partir de la mémoire programme. Au second cycle
d’horloge, le code d’opération (Opcode) de cette instruction est décode, alors que la prochaine instruction est lue
simultanément. Au dernier cycle d’horloge, l’instruction 1 est exécutée, l’instruction 2 est décodée et
l’instruction est 3 lue.

Le super pipeline du XScale est composé de 3 sous pipelines distincts :


1) Un pipeline des entiers à 7 étages ou le pipeline d’exécution principale. Ce pipeline est destiné à l’exécution
des instructions qui traitent les données, mis à part la multiplication.
2) Un pipeline à 8 étages, qui reprend les 5 premiers étages du pipeline des entiers. Ce pipeline est destiné aux
instructions load / store.
3) Un pipeline MAC de 6 à 9 étages, qui reprend les 4 premiers étages du pipeline des entiers. Ce dernier est
destiné aux instructions MAC.

Le super pipeline du cœur XScale peut être représenté de la manière suivante :

PC PC+4 PC+8 PC+12 PC+16

Figure 42 : Le super pipeline du coeur RISC XScale, source : [3]

Tous les 3 pipelines sont en mesure d’exécuter leurs instructions en parallèle. Les tâches des différents étages
sont les suivantes :
• F1 / F2, Instruction Fetch: Livre au niveau ID la prochaine instruction à exécuter. Cette dernière est lue à
partir du cache d’instruction (I-Cache) en fonction du Programme Counter (PC). La différence de la valeur
du PC entre les niveaux F1 et X1, correspondant à 16 bytes, est définie intrinsèquement par le pipeline du
XScale. En présence de sauts de programme conditionnel, l’adresse de la prochaine instruction est définie par

Version 3.1, juin 2008 Page 36


Informatique 3 Le microcontrôleur PXA270

le tampon Branch Target.


• ID, Instruction Decode : Extraction du code d’opération (Opcode), des adresses des registres des opérandes et
du résultat à partir de l’instruction.
• RF, Register File / Shifter: Lit la valeur des registres définit par le niveau ID du banc de registre (opérandes),
exécute les éventuelles opérations de décalage (Barrel Shifter) et fournit les valeurs des opérandes à l’ALU
ou au MAC.
• X1, Execute : Exécute le traitement de donnée dans l’ALU. Tous le contenu du pipeline est vidée lorsque la
prévision du BTB, pour les sauts de programme conditionnels, s’est avérée comme étant fausse.
• X2, Execute 2 / State : Ce niveau actualise les registres d’état du programme (PSRs) et prépare les données
pour le niveau XWB (résultat de l’opération). L’état (instruction ARM ou Thumb) est définie en supplément.
• XWB, Write Back: Ecriture du résultat de l’opération dans le banc de registre. L’instruction se termine ainsi.
• D1 / D2, Data Cache : Les adresses pour les instructions load/store sont déterminées par le niveau X1.
L’accès au Data-Cache ou au mini D-Cache est réalisé au niveau D2.
• DWB, Data Write Back: Le données sont transférer dans la mémoire cache.
• M1 – Mx : ces niveaux traitent les instructions pour la multiplication et la multiplication avec accumulation
(coprocesseur)

2.3 Le PXA270 de XScale


2.3.1 Les propriétés
Les propriétés les plus importantes, héritées de la famille XScale, sont les suivantes :
• Processeur RISC 32 bits, qui est basé sur l’architecture ARMv5TE. Soutient toutes les instructions
ARMv5TE, en incluant les instructions Thumb et DSP (main pas de floating point).
• Un grand banc de registre, contenant 16 registres universels et 2 registres d’état. Les registres peuvent être
changés individuellement en fonction du contexte du processeur.
• Data et Memory Management Unit
• Super pipeline de 7 à 9 étages
• Mémoire cache de 32 kilos bytes pour les instructions, mémoire cache de 32 kilos bytes et un mini mémoire
cache de 2 kilos bytes pour les données
• Coprocesseur DSP (CP0) avec un accumulateur de 40 bits
• Coprocesseur 15 (CP15) pour la configuration du MMU, des mémoires Caches et des tampons

Les propriétés propres à la famille XScale sont les suivantes :


• Une fréquence d’horloge du coeur de 520 MHz et du bus de système de 208 MHz
• Gestion de la consommation avec différents modes d’économie de courant (idle, deep-idle, sleep, deep-
sleep). Les caractéristiques de consommation typiques sont de 747mW @ 520MHz (en mode actif) et
220mW @ 520MHz (en mode idle).

Version 3.1, juin 2008 Page 37


Informatique 3 Le microcontrôleur PXA270

2.3.2 Le diagramme de bloc

Figure 43 : Diagramme de bloc des PXA27x. Source : XScale PXA27x Family Developers Manual [2]

Le XScale PXA270 possède, en plus du cœur de XScale décrit au chapitre 2.2, les composants périphériques
suivants :
• Coeur XScale, dont les propriétés sont décrites au chapitre 2.2.
• Gestionnaire de consommation (Power-Management) flexible pour les applications à basse consommation
• SRAM interne de 4 * 64 kilos bytes
• Un contrôleur d’interruption (Interrupt-Controller) pour le masquage ou l’activation des interruptions. Ce
contrôleur est accessible à l’aide du plan de mémoire ou des registres du coprocesseur.
• Timer pour les systèmes d’opérations, un watchdog et 8 canaux timer supplémentaires.
• Unité PWM avec 4 canaux indépendants
• Real Time Clock (RTC) avec un conteur 32 bits pour le Timer, les interruptions périodiques etc.
• General Purpose I/O (GPIO): Beaucoup de pins du PXA27x sont multifonctionnels et peuvent être utilisés
comme entrées et sorties digitales.
• Memory Controller avec de nombreuses interfaces pour les composants de stockage internes et externes
(SDRAM, Flash, Card). Cette unité pilote le bus d’adressage, de données et de contrôle.
• Direct Memory Access Unit (DMA) pour les transferts de données de mémoire à mémoire, de périphérie à
mémoire et de mémoire à périphérie.
• De nombreuses interfaces sérielles
− 3 UART (Standard, Bluetooth, Full-Function)
− Port de communication infrarouge rapide
− Bus I2C
− AC '97 Codec Interface
− I2S Audio Codec Interface
− Contrôleur USB client et hôte

Version 3.1, juin 2008 Page 38


Informatique 3 Le microcontrôleur PXA270

− Port sériel synchrone (SSP)


• Un contrôleur de panneau LCD (LCD Panel) avec de nombreux mode de fonctionnement
• Contrôleur pour les cartes multimédia, cartes de mémoire SD (SD Memory Card) et cartes SDIO
• Memory Stick Host Controller (Sony Standard)
• Interface pour clavier
• Interface pour les camera à capture rapide
• Interface de Test / Debug

2.4 Les modes de fonctionnement


Le XScale (comme tous les autre processeur ARM) comprend 7 modes de fonctionnement. Ces derniers sont
décrits dans le Tableau suivant :

Mode Abréviation privilège Bit de mode [4:0] du registre CPSR


Utilisateur USR Non 10000
Requête d’interruption rapide FIQ Oui 10001
Requête d’interruption IRQ Oui 10010
Superviseur SVC Oui 10011
Abandon (abort) ABT Oui 10111
Non défini UND Oui 11011
Système SYS Oui 11111
Figure 44 : Modes d’utilisation
Tous les modes, excepté celui d’utilisateur, sont des modes privilégiées. Par conséquent, ils peuvent accéder à
toutes les ressources du processeur. Ils peuvent également modifier les drapeaux d’interruption (flag) et possède
des bancs de registres fantômes.

Les modes FIQ, IRQ, SVC, ABT et UND sont des modes destinés aux traitements des interruptions (voir
chapitre 7 : Les interruptions). Le processeur exécute toutes les applications standard dans le mode utilisateur.
Lorsque des deux requêtes d’interruption hardware (FIQ ou IRQ) apparaissent, le processeur entre dans le mode
d’interruption correspondant à la requête afin de la traiter. Le processeur se trouve dans le mode superviseur
après le reset. Les routines du système d’exploitation sont exécutées dans ce mode. Le processeur entre dans le
mode abandon (ABT), lorsque apparaissent des erreurs d’accès mémoire. Le mode non défini est choisi lorsque
le processeur doit exécuter des instructions, qui ne sont pas définies ou qui ne sont pas soutenues. Le mode
système est identique à celui utilisateur. Ce dernier permet toutefois d’accéder aux registres CPSR (voir chapitre
2.6).

2.5 Le modèle des registres


Les registres constituent l’interface entre le programmeur et le processeur. Le set des registres ARM comprend
les registres suivants :

R0 – r15 16 registres d’utilités générales de 32 bits (general purpose), destinées au stockage des données
et des adresses.
Les trois derniers registres de ce banc sont utilisés normalement pour des tâches spéciales :
r13 en tant que « stack pointer » (sp), contient l’adresse actuelle de la pile du mode momentané
r14 en tant que « link register » (lr), contient l’adresse de retour dans le cadre des appelles de
sous routine.
r15 en tant que « program counter » (pc), contient l’adresse de la prochaine instruction, qui
doit être lue (fetch)
CPSR Current Program Status Register, voir chapitre 2.6
SPSR Saved Program Status Register

Version 3.1, juin 2008 Page 39


Informatique 3 Le microcontrôleur PXA270

L’accès aux 16 registres d’utilité général est possible dans tous les modes de fonctionnement. Mis à part
quelques exceptions, ces registres peuvent être utilisés librement.

Fast
User und interrupt Interrupt
System Request Supervisor Abort Undefined
Request
r0 r0 r0 r0 r0 r0
r1 r1 r1 r1 r1 r1
r2 r2 r2 r2 r2 r2
r3 r3 r3 r3 r3 r3
r4 r4 r4 r4 r4 r4
r5 r5 r5 r5 r5 r5
r6 r6 r6 r6 r6 r6
r7 r7 r7 r7 r7 r7
r8 r8_fiq r8 r8 r8 r8
r9 r9_fiq r9 r9 r9 r9
r10 r10_fiq r10 r10 r10 r10
r11 r11_fiq r11 r11 r11 r11
r12 r12_fiq r12 r12 r12 r12
r13 sp r13_fiq r13_irq r13_svc r13_abt r13_und
r14 lr r14_fiq r14_irq r14_svc r14_abt r14_und
r15 pc r15 pc r15 pc r15 pc r15 pc r15 pc

cpsr cpsr cpsr cpsr cpsr cpsr


spsr_fiq spsr_irq spsr_svc spsr_abt spsr_und

Figure 45: Set des registres ARM

Les registres r0 à r8 sont communs pour tous les modes de fonctionnement. Ce ne sont donc pas des registres
fantômes.
Les registres r8 à r14 sont par contre des registres fantômes (banked register). Chaque mode de
fonctionnement possède son propre banc de ces registres (voir Figure 45). Les registres r8 à r12 ne sont pas
réservés pour des tâches spécifiques.
Le registre r13 est utilisé comme pointeur de pile (stack pointer abrégé par sp).
Le registre r14 est également appelé registre de reliage (link register abrégé par lr). L’adresse de retour est
copiée dans ce registre, lorsque le programme fait un saut dans une sous routine. Cette opération est également
exécutée avec les routines de service d’interruption. Toutefois, le registre du nouveau mode est utilisé dans ce
dernier cas.
Le registre r15 sert de compteur de programme (program counter abrégé par pc).
L’APCS (ARM Procedure Call Standard) spécifiée plus précisément l’utilisation des registres (voire chapitre
6 « Les sous routines »).
La Figure 45 montre que le mode d’interruption standard partage les registres r0 à r12 avec mode utilisateur.
Dans ce cas, seules les registres r13 et r14 sont des registres fantômes (banked register). C'est-à-dire que
uniquement ces deux registres diffèrent en fonction du mode de fonctionnement. L’avantage de cette technique
est que ces registres peuvent être modifiés dans un mode donné, sans que cela n’influence les autres modes. Ce
sujet est traités plus en détail dans les chapitre 6 « Les sous routines » et le chapitre 7 « Les interruptions ». Le
Saved Program Status Register (SPSR) contient la valeur du Saved Program Status Register (CPSR) du mode
précédent.

Version 3.1, juin 2008 Page 40


Informatique 3 Le microcontrôleur PXA270

2.6 CPSR Current Program Status Register


Ce registre permet de lire ou de modifier l’état actuel du processeur. Les bits et les drapeaux (flags) sont définis
de la manière suivante:
• Les bits d’état (Condition flags): N, Z, C, V, Q
• Les bits de masquage des interruptions (Interrupt Mask) : I (Interrupt Request) et F (Fast Interrupt Request)
• Etat du processeur (T) : distinction entre les états 32-Bit ARM ou 16-Bit Thumb
• Mode: Mode d’utilisation en fonction de la Figure 44

Flags Status Extension Control


Fields

Bit 31 30 29 28 7 6 5 4 0

N Z C V Q not used I F T Mode

Function Condition Interrupt Processor


Flags Mask Mode
Thumb
State

Figure 46: Current Program Status Register

2.7 Les bits d’état


Les bits d’état (Condition Flags) sont modifiés par l’ALU en fonction des opérations de comparaisons ou
d’arithmétiques. Une soustraction (instruction SUBS) met par exemple le bit Z (Zero) a un, lorsque le résultat de
l’opération et nul.

Les sauts de programme conditionnels sont toujours réalisés en fonction des bits d’état. Si le programme contient
par exemple l’instruction « if (A == 0) », il exécutera un saut sera en fonction du bit Z. Les processeurs
ARM possèdent en supplément des instructions conditionnelles, qui sont également exécutées en fonction des
bits d’état (Conditional Execution).

Le Tableau suivant contient les bits d’états du registre CPSR ainsi que leur description :

Version 3.1, juin 2008 Page 41


Informatique 3 Le microcontrôleur PXA270

Drapeau Nom du drapeau Description


(flag)
N Negative Le bit N est considéré comme le signe des nombres signés. Ce dernier est mis à
un (1) avec les nombres négatifs, et il est mise à zéro (0) avec les nombres
positifs.
Z Zero Le bit Z est mis à un lorsque le résultat de l’opération ALU est nul. Cela est
également valable pour les comparaisons de nombres : Le bit Z est mis à un
lorsque deux nombre sont égaux.
C Carry Avec les additions, le bit C est mis à 1 lorsqu’il y a un dépassement de capacité
non signé, sinon il reste à 0 (voir Figure 47).
Avec les soustractions, le bit C est mis à 0 lorsqu’il y a un dépassement de
capacité non signé, sinon il reste à 1 (voir Figure 47).
Avec les opérations de décalage, le bit C contient la valeur du dernier bit de
l’opérande.
V oVerflow Avec les additions et les soustractions, le bit V est mis à un lorsqu’il y a un
dépassement de capacité signé (voir Figure 48).
Q saturation Ce bit est mis à 1 par les instructions pour empêcher les dépassements de
capacité (saturation). Ce dernier n’est disponible que dans certains cœurs (ex.
v5TE).
Tableau 5 : Les bits d’état

Do maine des nombres


0 232 - 1

Dépassement avec Nulle Dépassement avec


Soustraction addition
C=0 C=1
32 0 1
(2 ) -1
32 2
(2 )

SUB ADD

231

Figure 47 : Cercle de nombres binaires non signée

Version 3.1, juin 2008 Page 42


Informatique 3 Le microcontrôleur PXA270

Domaine des nombres


- 231 231 -1

Nulle
0
-1 1
2

N=1 N=0
SUB Négatif Positif ADD

- 231 - 1 231
V=1 V=1
Dépassement avec Dépassement avec
addition soustraction

Figure 48 : Cercle de nombres binaires signés

2.8 Les modèles de mémoire et les format de


données
Dans les processeurs de la famille ARM, le stockage des données s’effectue par défaut avec le format petit
boutiste (little-endian). Les bytes de poids plus faible des variables sont ainsi stockés en premier, suivis par les
bytes de poids plus fort. Mais les processeurs ARM peuvent être configurés, afin que les données soient stockées
avec le format gros boutiste (big-endian). Nous nous limiterons dans ce chapitre au format petit boutiste.

Les processeurs ARM - à partir de la version v4 - soutiennent les formats de données suivants :
• Byte signés et non signés (8 bits, char)
• Demi mot (halfword) signés et non signés (16 bits, short int)
• Mot (word) signés et non signés (32 bits, long int)

Les processeurs ARM sont basés sur l’architecture Load/Store. C'est-à-dire que les opérandes de l’ALU doivent
toujours être stockées dans des registres. Les opérateurs de l’ALU traitent ainsi les données sous formant mot
(32 bits). Les seules instructions, qui sont capables de transférer des données entre la mémoire et les registres,
sont les instructions de transfert de donnée (Load et Store). Ces instructions sont capables de transférer des
données du type byte, demi-mot et mot. Lorsqu’une donnée du type byte ou demi-mot est lue à partir de la
mémoire, elle est étendue à 32 bits avec l’unité d’extension de signe « Sign Extend » (voir Figure 40).

Certaine conditions doivent être respectées pour le stockage des données dans la mémoire. Les Figures suivantes
illustres le stockage des bytes, des demi mots et des mots dans la mémoire :

Model de mémoire avec un adressage du type byte :

Adresse
N Byte 0
n+1 Byte 1
n+2 Byte 2
n+3 Byte 3
Figure 49: Model de mémoire du type byte

Version 3.1, juin 2008 Page 43


Informatique 3 Le microcontrôleur PXA270

Model de mémoire avec un adressage du type demi mot :

Adresse
n Demi mot 0 Byte de poids plus faible du demi mot 0
Byte de poids plus fort du demi mot 0
n+2 Demi mot 1 Byte de poids plus faible du demi mot 1
Byte de poids plus fort du demi mot 1
Figure 50: Model de mémoire du type demi mot

Un demi mot est toujours stocké a une adresse paire (frontière 2 bytes). Le byte de poids plus faibles sera stocké
à l’adresse inférieure (paire), et le byte de poids plus for à l’adresse supérieur (impaire). Le bit de poids le plus
faible de l’adresse de base A0 est donc nul.

Model de mémoire avec un adressage du type mot :

Adresse
n Mot 0 Byte de poids le plus faible du mot 0

Byte de poids le plus fort du mot 0


n+4 Mot 1 Byte de poids le plus faible du mot 1

Byte de poids le plus fort du mot 1


Figure 51: Model de mémoire du type mot

Un mot est toujours stocké à une adresse, qui est divisible par 4. Le byte de poids le plus faible du mot est stocké
à l’adresse n, alors que le byte de poids le plus fort à l’adresse n+3. Les deux bits de poids les plus faibles de
l’adresse de base (A0 et A1) sont donc nuls.

2.9 Le plan de mémoire du PXA270


Les registres r0 à r15 et le registre CPSR sont accessibles directement. C'est-à-dire que les instructions
assembleur peuvent utiliser ces registres comme opérande. Tous les autre registres (comme par exemple ceux du
GPIO, de l’USB etc.) ne sont accessibles qu’à l’aide du système de bus interne (adresse et données). Chacun de
ces registres possèdent donc sa propre adresse. Le plan de mémoire (Memory map) du processeur illustre les
espaces d’adressage pour les différents groupes de registres.

Le plan de mémoire du PXA27x est le suivant :

Version 3.1, juin 2008 Page 44


Informatique 3 Le microcontrôleur PXA270

Figure 52 : Le plan de mémoire du PXA27x, source : XSCALE_PXA27x_Family_Developers_Manual [2]

2.10 Le plan de mémoire du CARME


Les espaces d’adressage des composants périphériques et de stockage externe (Flash et SDRAM) du kit de
développement CARME ont été inclus dans le plan de mémoire de la Figure 52. Certains espaces d’adressage du
kit sont donc identiques à ceux du PX270 ; comme par exemple celui du slot Compact Flash. Le contrôleur
CAN, qui est sélectionnable avec CS1 dans CARME, possèdent l’adresse de base 0x0400’0000.

Version 3.1, juin 2008 Page 45


Informatique 3 Le microcontrôleur PXA270

0xFFFF_0800 Réservé
0xFFFF_0000 High Vector Debug Handler
0xA400_0000 Réservé
0xA000_0000 64 M bytes SDRAM
0x5800_0000 Réservé
0x4000_0000 Périphérie
0x3000_0000 Compact Flash 1
0x2000_0000 Compact Flash 0
0x1800_0000 Réservé
0x1400_0000 nCS5
0x1000_0000 nCS4
0x0C00_0000 CPLD, MIN3IO (nCS3), Extension 1 bis 4
0x0800_0000 Ethernet-Controller (nCS2)
0x0400_0000 CAN-Controller (nCS1)
0x0200_0000 Réservé
0x0000_0000 32 M byte Flash (Vector Table)
Figure 53 : Le plan de mémoire du kit de développement CARME

2.11 Le schéma des pins


Le PXA270 est produit avec différents boîtiers BGA. Par conséquent, les connexions peuvent varier en fonction
du boîtier. Les pins sont répartis selon leur fonctionnalité dans différents blocks. La Figure suivante illustre un
exemple de répartition des pins :

Figure 54: Le schéma des pins du PXA270 (23mm/360 Ball Grid),


Source : Intel PXA27x Processor Family Design Guide [7]

2.12 Connexion des composants Flash et SDRAM


Le PXA270 possède un bus d’adresse et de données de 32 bits. De nombreux composants de stockage possèdent
toutefois une organisation de 8 ou 16 bits. Deux ou quatre composants doivent donc être utilisés en parallèle,
afin de pouvoir réaliser une connexion à 32 bits. Des signaux de contrôle sont également nécessaires, afin de

Version 3.1, juin 2008 Page 46


Informatique 3 Le microcontrôleur PXA270

pouvoir gérer la communication. Les Figures suivantes illustrent des connexions typiques des composants Flash
et SDRAM, qui possèdent une organisation de 16 bits.

Flash de 4 Méga * 16 bits


Le schéma bloque de la connexion est le suivant :
nCS
nWE
nOE
nSDCAS
nSDCLK<0>
MA<23:0>
MD<31:0>

4M*16 Flash 4M*16 Flash

nCS nCS
nWE nWE
nOE nOE

nADV nADV
CLK CLK
MA<23:2> MA<23:2>
A<21:0> A<21:0>
MD<15:0> MD<31:16>
DQ<15:0> DQ<15:0>

Figure 55: Schéma bloque de la connexion des composants flash avec une organisation de 16 bits
Source: Intel PXA27x Processor Family Developer's Manual [2]

Les signaux suivants interviennent dans la connexion :

Signal Description
CS Chip-Select : Sélectionne un banc de composants de stockage. Un banc représente un certain
nombre de composants, qui mis ensemble sont en mesure de traiter des données de 32 bits.
Le banc dans l’exemple de ci-dessus est composé de 2 composants avec une organisation de
16 bits.
WE Write Enable : Signal d’écriture, avec lequel les données peuvent être écrites dans la flash.
OE Output Enable : Signal de lecture avec lequel les données peuvent être lues à partir du flash.
Ce signal active les amplificateurs de sortie pour le bus de données.
ADV Address Valid : Ce signal indique que les adresses, qui sont fournies par le processeur sur le
bus d’adresse, sont valables. Correspond au signal de sortie du processeur nSDCAS.
CLK Horloge pour tous les composants statiques comme les flashs ou les SDRAM
A Bus d’adresse : Seul les données du type mots sont lues dans cet exemple (32 bits). Par
conséquent les bits d’adresse A0 et A1 n’y sont pas utilisés.
DQ Bus de données : Les composants de stockage possèdent une organisation de 16 bits. Par
conséquent, le composant de gauche est connecté aux 16 bits de données de poids plus
faibles (low halfword) et celui de droite aux 16 bits de données de poids plus fort (high
halfword).
Tableau 6 : Signaux de contrôle destinés au composant flash

SDRAM de 4 Méga * 16 bits


Le schéma bloque de la connexion est le suivant :

Version 3.1, juin 2008 Page 47


Informatique 3 Le microcontrôleur PXA270

nCS
nWE
nSDRAS, nSDCAS
nSDCKE, nSDCLK<2:1>
MA<24:10>
DQM<3:0>
MD<31:0>

4M*16 SDRAM 4M*16 SDRAM

nCS nCS
nWE nWE
nRAS nRAS
nCAS nCAS

CKE CKE
CLK CLK
MA<21:10> MA<21:10>
A<11:0> A<11:0>
MA<23:22> MA<23:22>
BA<1:0> BA<1:0>
DQM0 DQM2
DQML DQML
DQM1 DQM3
DQMH DQMH
MD<15:0> MD<31:16>
DQ<15:0> DQ<15:0>

Figure 56 : Schéma bloque de la connexion des composants SDRAM avec une organisation de 16 bits
Source : Intel PXA27x Processor Family Developer's Manual [2]

Les signaux suivants interviennent dans la connexion :

Signal Description
CS Chip-Select : Sélectionne un banc de composants SDRAM
WE Write Enable : Signal d’écriture, avec lequel les données peuvent être écrites dans la
SDRAM.
RAS Row Address Strobe
CAS Column Address Strobe
CKE Clock Enable
CLK Clock
A Adresses pour row et column
BA De nombreux SDRAM proposent des bancs de mémoire internes. Ces derniers peuvent être
sélectionnés à l’aide des signaux « Bank Address ». Ces signaux sont connectés côté
processeur aux bits d’adresses.
DQML/DQMH Data byte mask control. Ces quatre lignes de contrôle du processeur permettent de transférer
les données de façon byte ou demi mot : DQM<0> correspond au byte de poids le plus faible
(bit 0 – 7), DQM<3> au byte de poids le plus fort (bit 24 - 31).
DQ Bus de données : Les deux composants SDRAM possèdent une organisation de 16 bits. Par
conséquent, le composant de gauche est connecté aux 16 bits de données de poids plus
faibles (low halfword) et celui de droite aux 16 bits de données de poids plus fort (high
halfword).
Tableau 7 : Signaux de contrôle destinés au composant flash

2.13 Schéma hardware avec le PXA270 & la mémoire


Le document « PXA27x Processor Developer's Kit » d’Intel [8] contient un schéma bloque d’un système à
microcontrôleur contenant le PXA270, des SDRAM et des flashs. Les schéma de la carte Colibri de Toradex, qui
est utilisé dans le kit de développement CARME, n’est malheureusement pas disponible.

Version 3.1, juin 2008 Page 48


Informatique 3 La programmation en assembleur

3 La programmation en assembleur

3.1 Introduction
Ce chapitre traite la programmation en assembleur de façon générale. Toutefois, les exemples d’assembleur y
sont définis avec le jeu d’instruction ARMV5TE des processeurs XScale. La syntaxe de l’assembleur s’oriente à
celle de GNU. Cette dernière diffère dans un certain nombre de point par rapport à celles des autres fournisseurs.

L’assembleur est un langage de programmation proche du hardware. Il dépend par conséquent du hardware, c’est
à dire qu’il a été développé pour une famille de processeur bien définie.
Avantage : l’assembleur est optimisé pour le hardware (registre, architecture etc.)
Désavantage : l’assembleur n’est pas portable, c. à d. qu’il ne peur pas être utilisé avec un autre CPU.

Ce chapitre traite les équivalences entre les différents assembleurs.

3.2 Les niveaux des langages de programmation


Un processeur ne comprend que le code machine, qui est toutefois incompréhensible pour l’homme. L’homme
utilise donc des langages de programmation, qui sont plus compréhensible pour lui. Ces derniers sont traduits par
des assembleurs ou des compilateurs en code machine.

La Figure suivante montre les niveaux de langage de programmation possible :

Prend une bouteille de bière dans le Langue naturelle


réfrigérateur
Bière – 1 Pseudo code
Proche du hardware

Bière = Bière – 1; Langage de programmation haut


niveau

Abstraction
LDR r4,beer Assembler
SUB r4,#1
STR r4,beer
0xe59f4020 Code machine
1110’0101’1001’1111’0100’0000’0010’0000
0xe2444001
1110’0010’0100’0100’0100’0000’0000’0001
0xe0802001
1110’0000’1000’0000’0010’0000’0000’0001

Figure 57 : Niveau des langages de programmation

a) La langue naturelle est la plus compréhensive pour l’homme. Elle est malheureusement trop floue et trop
redondante. Elle ne convient donc pas pour la programmation.
b) Le pseudo code est souvent utilisé dans la phase de design. Son niveau d’abstraction est très élevé et il n’est
pas standardisé.
c) Les langages de programmation haut niveau possèdent également un niveau d’abstraction élevé. Les
compilateurs traduisent ces langages dans des codes machine, dont l’efficacité dépend du langage de
programmation et du compilateur. Les langages de programmation les plus répondus pour les
microprocesseurs sont le C et C++. Les langages de programmation haut niveau sont standardisés (ex. ANSI-
C). Ce qui permet de porter les programmes d’un processeur à un autre, avec plus ou mois d’efforts.
d) Les programmes en assembleur sont très difficilement compréhensible pour l’homme. Toutefois, les
programmes en assembleur sont plus performants et utilisent mieux les ressources que les programmes haut
niveau.

Version 3.1, juin 2008 Page 49


Informatique 3 La programmation en assembleur

3.3 La structure d’un fichier en assembleur


Les points suivants influence la structure d’un fichier assembleur :
• La syntaxe de l’assembleur, qui dépend du processeur
• Les directives de l’assembleur, qui dépendent de l’assembleur
• Les lignes directives de programmation, qui dépendent du fabricant

La Figure suivante montre une éventuelle construction d’un fichier assembleur.

/*************************************************************************
* *
* Projet : NomProjet *
* *
* *
**************************************************************************
* Programme/Module : NomModule *
* Nom du fichier : NomFichier.68k *
* Version : 1.00 *
* Définition : dd.mm.yyyy * Entête (header)
* Auteur(s) : NomAuteur * (en option)
* -----------------------------------------------------------------------*
* Description : Description brève du module *
* *
**************************************************************************
* Modification: *
* Auteur Date de la modification *
* m.n dd.mm.yyyy *
*************************************************************************/

/************************************************************************* Interface du
* PUBLIC DECLARATIONS * module
*************************************************************************/
(en option)
.global mysub @ exported subroutines

/************************************************************************* Symbole importé


* EXTERNAL DECLARATIONS (optional) *
(en option)
*************************************************************************/
.extern extsuB @ imported subroutines

/************************************************************************* Fichier à inclure


* include DEFINITIONS *
(en option)
*************************************************************************/
.include ″pxa270.h″ @ include controller registers

/************************************************************************* Définition EQU


* EQUATE DEFINITIONS *
(en option)
*************************************************************************/
.equ MAX,0x1000 @ maximum allowable size

/************************************************************************* Définition des


* VARIABLE AND CONSTANT DEFINITIONS * variables et des
*************************************************************************/ constantes
.data
(en option)
myvar: .space 4 @ space for 1 Word (32-Bit)

/************************************************************************* Code
* CODE *
*************************************************************************/
.text

Version 3.1, juin 2008 Page 50


Informatique 3 La programmation en assembleur

mysub: ADR r0, myvar @ Load the address of myvar


MOV r1, #MAX @ Load the constant value MAX
STR r1, [r0] @ Copy the MAX value in to myvar
BL Extsub @ Call the subroutine Extsub
MOV pc, lr @ Return to the calling function of mysub

.end

Figure 58 : Construction possible d’un fichier assembleur

Les entêtes (Header) dépendent de la société. Il existe normalement dans les sociétés des lignes directives pour la
programmation, qui définissent l’aspect de l’entête. L’entête devrait toutefois contenir au minimum les
informations suivantes
• Nom du projet
• Brève description du module
• Historique

La partie « PUBLIC DECLARATIONS » contient tous les noms de sous-routines et de variables, qui sont
définies dans le module courant et doivent être exportées dans les autres modules.

La partie « EXTERNAL DECLARATIONS » contient tous les noms de sous-routines et de variables, qui doivent
être importées depuis les autres modules.

Les fichiers, qui contiennent la description des registres du contrôleur, peuvent être importés dans la partie
« include DEFINITIONS ». include copie tout le contenu du fichier en question dans le module.

La partie « EQUATE DEFINITIONS » contient les définitions EQUATE (correspond à la directive #define
de C).

La partie « VARIABLE AND CONSTANT DEFINITIONS » contient les définitions des variables et des
constantes.

La partie « CODE » contient les instructions du programme. Cette partie est divisée en 4 colonnes (voir chapitre
4.3.1).

3.4 La syntaxe assembleur


3.4.1 La structure d’une ligne assembleur
La syntaxe de l’assembleur, qui également nommé mnémonique, est orientée ligne. Chaque ligne du code source
correspond donc à une instruction assembleur. La Figure suivante illustre un exemple d’instruction assembleur :

Etiquette Opérations / instructions Opérandes Commentaire


main: LDR R0, #MAX @ Max value

Figure 59 : Une ligne d’instruction assembleur

Etiquette :
Le champ des étiquettes commence à la première colonne et se termine avec « : ». L’étiquette peut contenir le
nom d’une variable, d’une sous-routine ou d’un label. Un label est une sorte de marque, qui est utilisé pour les
sauts de programme.

Opération / instructions :
Le champ des opérations / instructions contient les instructions pour la CPU ou les directives pour l’assembleur.
Dans l’exemple ci-dessus « LDR » est une instruction, qui commande à la CPU de copier la valeur constante
« MAX » dans le registre « R0 ».
Toutes les instructions d’un processeur sont définies dans son jeu d’instruction (voir chapitre 4, qui traite le jeu

Version 3.1, juin 2008 Page 51


Informatique 3 La programmation en assembleur

d’instruction de l’ARM V5)

Toutes les opérations peuvent être exécutées de façon conditionnelle.

Exemple :

CMP r0, #0 @ if (a==0 || b==1)


CMPNE r1, #1
ADDEQ r2,r3,r4 @ c = d + e;

Figure 60 : Instruction assembleur conditionnelle

Ce concept permet d’économiser de nombreux sauts de programme en comparaison avec d’autre famille
d’assembleur. La condition est définie avec un suffixe ou un code de condition à la fin de l’instruction. Par
exemple, le suffixe « NE » de la deuxième comparaison a pour conséquence que cette instruction n’est exécutée
que si le résultat de l’opération précédente est différent de zéro. De la même façon, l’addition n’est exécutée que
si le résultat de l’opération précédente est égal à zéro (EQ).

L’instruction, qui vient d’être exécutée, fixe la condition. Cette dernière est évaluée l’aide des bits d’état courant
du programme (flags), qui se situent dans le registre du même nom (Current Program Status Register abrégé par
CPSR). Dans l’exemple de ci-dessus les conditions sont fixées par les deux opérations de comparaisons.

Toutes les opérations arithmétiques, qui sont exécutées par l’ALU, influencent les bits d’état N, Z, C et V. Les
opérations logiques ne modifient que N, Z et C.

Les opérandes :
Les opérandes des instructions ou des directives assembleur sont définis dans le champ des opérandes. Dans
l’exemple de ci-dessus les opérandes de l’instruction « LDR » sont la constante « MAX » et le registre « r0 ».

Le processeur ARM travail fondamentalement avec trois opérandes. Certaines instruction, comme par exemple
les sauts de programme, se limitent à un ou deux opérandes. Le jeu d’instruction ARM ne contient pas
d’instruction sans opérande.

Instruction avec un opérande :


Ce type d’instruction ne possède qu’une adresse de destination. Cette dernière est définie de façon symbolique
avec les ramifications ou les sauts de programme.

Exemple :
B start
SWI 0x10

Instruction avec deux opérandes :


Cette catégorie contient la plupart des instructions de transfert de donnée. Ces dernières stockent / chargent les
données depuis la mémoire de travail dans les registres du processeur

Exemple :
MOV pc,lr
LDR r0,waleur

Les instructions avec trois opérandes :


La plupart des instructions, qui traitent les données, nécessitent trois opérandes. Elles possèdent le formant
suivant :

mnemonic dest, src, shift

Dans cette expression « dest » représente le registre de destination et « src » celui de source. Les registres r0
à r15 peuvent être utilisés pour cela. L’opérande « shift » permet de traiter un opérande à l’aide du « barrel
shifter » avant l’exécution de l’opération. Il permet également de définit un valeur constante de 8 bits.

Version 3.1, juin 2008 Page 52


Informatique 3 La programmation en assembleur

Chez les processeurs RISC, les instructions de traitement de données ne se limitent en générale à des opérations
entre registres. Les opérations entre des registres et la mémoire de travail sont exclusivement des opérations de
transfert de données.

Les commentaires :
Les commentaires du champ de commentaire sont définis pour améliorer la compréhension du code.
L’assembleur GNU prévoit trois types de commentaires : les commentaire en bloc, les commentaire en ligne et
les commentaire de fin de ligne.
Les commentaires en bloc sont formulés entre « /* » et « */ », comme en ANSI-C. Les commentaires en ligne
sont définis uniquement sur une ligne et ils sont introduits avec un dièse « # ». Les commentaires de fin de ligne
sont défini à la fin de la ligne et ils sont introduits avec un « @ ». Il est très important de bien commenter les
programmes assembleur. Toutefois, le commentaire ne devrait pas décrire l’instruction, mais améliorer la
compréhension du déroulement du programme.

Exemple :
/* Commentaire de bloc

*/

# Commentaire en ligne
LDR r0,=operand1 @ Commentaire fin de ligne

Figure 61: Les trois formes des commentaires assembleur

3.4.2 Les symboles


Les symboles sont des noms de variables, de sous-routines, de labels etc. Les caractères autorisés pour les
définir sont les suivants :
• Les lettres a à z et A à Z (pas d’accent)
• Les chiffres 0 à 9
• Le caractère de soulignement « _ »
• Le point « . »
• Le caractère dollars « $ »

Les règles suivantes régissent la définition des symboles :


• Le premier caractère ne doit pas être un chiffre.
• Un symbole peut être aussi long que possible, tous les caractères sont significatifs.
• Distinction entre les majuscules et les minuscules.

L’assembleur GNU soutient également les symboles locaux.


Le point unique, en tant que symbole prédéfini, possède une signification précise : Il représente la valeur du
compteur de programme courant. Par exemple « .=.+4 » est équivalent à « .space 4 ».

3.4.3 Les constantes


Les règles suivantes régissent la définition des constantes :

Version 3.1, juin 2008 Page 53


Informatique 3 La programmation en assembleur

Type Description Préfix Exemple


Chaîne de caractère String " "Bonjour"
Caractère Char ' 'A'
Numérique Hexadécimal 0x 0x7FF
Numérique Binaire 0b 0b0111011
Numérique Octal 0 0124
Numérique Décimal Pas de préfix 123

Tableau 8 : Règle qui régissent la définition des constantes

Les constantes peuvent être spécifié avec le caractère « = ». Cela est valable pour les valeurs numériques et les
adresses, qui sont représentées à l’aide de symbole.

Les valeurs, qui ne peuvent pas être chargées par les instructions « MOV », sont automatiquement adressées de
façon relative avec compteur de programme (ici [pc, #4]). Dans l’exemple suivant, la constante
0x12345678 est chargé de la mémoire programme de cette façon. Par contre, la valeur un est directement
chargée avec l’instruction MOV.

Exemple :
start: LDR r0,=1 @ Charger la valeur constante 1
loop: LDR r1,=0x12345678 @ Charger la valeur 0x12345678
ADD r0,r0,r1 @ Additionner les deux valeurs
B loop

0xa00004e8 <start>: MOV r0, #1 ; 0x1


0xa00004ec <loop>: LDR r1, [pc, #4] @ la valeur est chargé de la mémoire 0xa00004f8
<loop+12>
0xa00004f0 <loop+4>: ADD r0, r0, r1
0xa00004f4 <loop+8>: B 0xa00004ec <loop>

Figure 62 : Le code objet généré pour le chargement de la constante 0x12345678

Remarque :
La valeur constant est stockée à l’adresse 0xA00004F8. Le compteur de programme adresse la prochaine
instruction à exécuter, qui est stockée sous 0xA00004EC. Le chargement des instructions relatif au compteur de
programme, s’effectue toujours avec un décalage préalable de - 8. Ce qui fournit le décalage à noter dans le code
suivant : 0xA00004F8 - 0xA00004EC – 8 = 4.

3.4.4 Les opérateurs et les opérandes


Des calculs peuvent être effectués en dehors de jeu des instructions durant le processus d’assemblage. Ces
calculs sont surtout utilisés pour la détermination des tailles de la mémoire ou des distances des sauts de
programme.

Le Tableau suivant contient les opérateurs, qui sont autorisées dans les expressions assembleur. Des espaces
vides ne sont pas autorisés avant ou après ces opérateurs :

Version 3.1, juin 2008 Page 54


Informatique 3 La programmation en assembleur

+ Addition
- Soustraction
* Multiplication signée
/ Division signée
% Reste de la division signée (Modulo)
& Opération binaire et
| Opération binaire ou
^ Opération binaire ou exclusive
&& Opération logique et
|| Opération logique ou
==, <> Egalité et inégalité
>, >= Plus grand que, plus grand que ou égale à
<, <= Plus petit que, plus petit que ou égale à
<< Opération de décalage vers la gauche
>> Opération de décalage vers la gauche
- Négation par complément à deux
~ Inversion binaire, complément à un
Tableau 9 : les opérateurs pour les expressions assembleur

La priorité des opérateurs dans les expressions est la suivante :

Négation, complément Priorité maximale


Multiplication, division, modulo
Décalage vers la gauche, décalage vers la droite
Opérations logiques et, ou et ou exclusive
Addition, soustraction
Egalité et inégalité
Opération de comparaison
Opérations booléennes et ou Priorité minimale
Tableau 10 : la priorité entre les différents opérateurs

Le résultat d’une opération de comparaison est toujours un nombre entier dans l’assembleur GNU. La valeur 0
représente faut et la valeur -1 vrai. Les opérations booléenne && et || fournissent par contre une valeur +1,
lorsque le résultat est vrai. Cette différence ne joue aucun rôle pour l’évaluation des conditions, En effet tous ce
qui est différent de 0 est considéré comme vrai.

Exemple:
Les bits 3 et 11 du registre r0 doivent être effacés.
BIC r0, r0, #(1 << 3) | (1 << 11)
L’instruction BIC efface les bits dans le registre r0. Les bits à traiter sont spécifiés avec le paramètre
« #(1 << 3) | (1 << 11) ». La position du bit y est définie avec l’opérande « << », alors que l’opérande « | »
permet d’associer ces derniers.

3.5 L’environnement de développement


Les programmes proche du hardware (Firmware) sont généralement développés sur des PC avec des
environnements de développement intégrés (Integrated Development Environment, IDE). Ces derniers peuvent
être soit simulés ou testés directement sur le hardware (débuggeur). La plupart des environnements de
développement moderne proposent les fonctionnalités suivantes :
• Editeur
• Assembleur, Compilateur et relieur (Linker / Locator)
• Débuggeur

Version 3.1, juin 2008 Page 55


Informatique 3 La programmation en assembleur

• Gestion de projet

La Figure suivante illustre une vue d’ensemble des fichiers, qui sont générés durant la phase de développement :

Editor

Source Source
assembler
Source C / Source
C++
*.s
assembler *.c
C / C++
*.asm *.s *.cpp*.c
*.asm *.cpp

Assembler Compiler

Listing Fichier Listing Fichier


assembleur
Listing objet
Fichier compilateur
Listing objet
Fichier
*.lst
assembleur *.oobjet *.lst
compilateur *.oobjet
*.lst *.ltx*.o *.prn
*.lst *.ltx*.o

Linker/Locator

Listing du Fichier Fichier


relieur binaire débuggeur
*.map *.bin *.elf

Figure 63 : Procédure de développement

3.5.1 L’éditeur
L’éditeur permet de définir le code source en assembleur ou avec un langage de programmation évolué. La
plupart des éditeurs sont sensible à la syntaxe et mettent en évidence les mots clés.
Exemple :
Le code en assembleur suivant a été défini à l’aide d’un éditeur.

.arm
.global start

.text
start: LDR r0,=1 @ Load constant value 1
loop: LDR r1,=0x12345678 @ Load constant value 0x12345678
ADD r0,r0,r1 @ ADD both values
B loop

.end

Figure 64 : Exemple d’un code en assembleur

Version 3.1, juin 2008 Page 56


Informatique 3 La programmation en assembleur

3.5.2 L’assembler
L’assembleur est toujours spécifique à la famille des processeurs. Si vous voulez développer du code pour des
processeurs différents, vous devez également utiliser des assembleurs différents. On parle de « Cross
Assembler », lorsque le code en assembleur est développé sur un ordinateur différent de celui, qui doit exécuter
le programme (ex. l’assembleur fonctionne sur un PC et le code généré sur le microcontrôleur d’une machine à
café).

L’assembleur traduit le code source assembleur, qui est contenu dans un fichier ASCII avec une terminaison
« .s » ou « .asm », en un fichier objet (.o). Des fichiers supplémentaires peuvent être générés, en fonction des
options de l’EDI (ex. fichier de listing : List-File avec une terminaison « .lis »). Le listing de l’assembleur pour
l’exemple ci-dessus a été illustré dans la Figure suivante :

1 2 3
ARM GAS EditionExample.s page 1
1 .arm
2. .global start
3
4 .text
5 0000 0000A0E3 start: LDR r0,=1
6 0004 04109FE5 loop: LDR r1,=0x12345678 @ ADD 0x12345678
7 0008 010080E0 ADD r0,r0,r1
8 000c FCFFFFEA B loop
9
10 0010 78563412 .end

ARM GAS EditionExample.s page 2

DEFINED SYMBOLS
EditionExample.s:1 .text:00000000 $a
EditionExample.s:5 .text:00000000 start
EditionExample.s:6 .text:00000004 loop
EditionExample.s:10 .text:00000010 $d

NO UNDEFINED SYMBOLS

Figure 65 : Le listing assembleur

Les colonnes du fichier listing contiennent les informations suivantes :

Nr. de Contenu
colonne
1 Numéro de ligne du code source
2 Adresse relative de départ du code
3 Code machine, par exemple "0000A0E3" veut dire que le registre r0 doit être chargé avec la
valeur 0. "0100080E0" veut dire que le contenu du registre r1 doit être additionné au registre
r0. Toutes les instructions nécessitent 4 bytes (1 mot) de stockage. Elles sont donc stockées à des
adresses mot (divisibles par 4).
reste Code original en assembleur
Tableau 11 : Colonnes du fichier listing

3.5.3 Le compilateur
Comme l’assembleur, le compilateur traduit le programme haut niveau, qui est défini dans un fichier source, en
un fichier objet. Les compilateurs C ou C++ sont utilisés généralement pour les applications embarqués.

Version 3.1, juin 2008 Page 57


Informatique 3 La programmation en assembleur

3.5.4 Le relieur / locateur


Le relieur (Linker) assemble tous les fichiers objet d’un programme, alors que le localisateur (Locator) attribue
des adresses définitives aux instructions et aux données du programme.
Le relieur / localisateur génère les fichiers suivants :
a) Pour le chargement du code dans la mémoire (.bin) ou
b) Pour le débuggeur (.elf)
c) Fichier de listing et de mappage (.map)

« elf » est une abréviation pour « Executable and Linking Format ». Ce format est un standard pour la gestion
des exécutables, des codes objets des bibliothèques, du mappage de la mémoire et des informations nécessaires
au débuggeur. Le format elf est entre temps très répandu et il a remplacé conceptuellement le COFF et de
nombreux autres formats de débuggeur.

Le contenu de ce fichier ne devrait pas intéresser le programmeur. Il ne peut pas être lu avec l’éditeur, mais par
contre, il peut être exploité avec les applications « objdump.exe » ou « elfdump.exe ».

Figure 66 : Les informations contenues dans le fichier elf exploitées avec OBJDUMP.EXE

3.5.5 Le débuggeur
Le débuggeur permet de tester le code, en représentant le contenu des registres, des variables et du code sur
l’écran du PC. L’insertion de points d’arrêt (break points) dans le code source et son exécution contrôlée, pas par
pas, font partie des exigences minimales pour un débuggeur.

On parle de « target debugging » lorsque le débogage est exécuté directement sur le système en développement.
Dans ce cas le débuggeur, qui est exécuté sur le PC, est responsable du téléchargement du code de débogage sur
le système en développement et de la communication avec ce dernier. Alors que le processeur du système en
développement n’est responsable que de l’exécution de ce code.

3.5.6 La gestion du projet


La gestion de projet permet de gérer les données de manière centralisée :
• Gestion de tous les fichiers du projet (les fichiers sources mais également ceux des bibliothèques et ceux
générés par le projet).
• Définition des chemins du projet (library path)
• Le mappage des segments du programme et des données à des adresses absolues
• Définition des options pour l’assembleur, le compilateur et le relieur

Version 3.1, juin 2008 Page 58


Informatique 3 La programmation en assembleur

Les environnements de développement modernes (IDE), comme Eclipse ou MS Visual Studio, proposent ces
fonctionnalités.

Version 3.1, juin 2008 Page 59


Informtique 3 Jeu d’instruction du processeur ARM V5

4 Jeu d’instruction du processeur ARM V5


Ce chapitre traite le jeu d’instruction du processeur ARM (c. à d. les instructions, qui peuvent être exécutées par
la CPU). Les instructions ont été partagées dans différents groupes selon leur fonctionnalité. Une description
plus détaillée de ces instructions est fournie dans [1] ou [2]. Tous les exemples concernent le processeur
PXA270 de XScale. Ce dernier implémente je jeu d’instruction ARMV5TE, sans les instructions à virgule
flottante.

Les chapitres suivants traitent uniquement le jeu d’instruction. La description de l’architecture ARM et des ses
registres est fournie par les chapitres 2.4 et 2.5.

4.1 Les instructions


Toutes les 25 instructions de base du processeur sont définies avec des mnemonics (abréviation d’instruction).
Elles sont obtenues systématiquement des lettres initiales des mots, qui décrivent ces instructions en anglais.

Ex. : ADD, ADd with Carry, Reverse SuBtract, Exclusive OR, BIt Clear,

Toutes les instructions possèdent un format unique de 32 bits. Cela génère un certain nombre de limitations, qui
ne sont pas très graves :
• Il n’est pas possible de charger des valeurs directes de 32 bits. Mis à part si ces dernières peuvent être
construite avec une valeur (mantisse) de 8 bits et 4 bits de décalage. Toutes les autres valeurs doivent être
chargées à partir de la mémoire programme.
• Les instructions saut de programme ne possèdent qu’un déplacement de 24 bits (offset). Les sauts de
programme relatifs sont ainsi limités à un espace de ± 32 Mégas bytes, par rapport à l’adresse courante. Des
vrais sauts de programme de 32 bits sont réalisés avec le chargement d’une valeur de 32 bits, dans le registre
du compteur de programme.
• Les instructions Load/Store ne peuvent fonctionner qu’avec un offset de 12 bits. Les accès aux variables
relatifs sont ainsi limités à un espace de 4 kilos bytes, par rapport à l’adresse courante.

Tableau 12 illustre le jeu d’instruction du processeur ARM :

Version 3.1, juin 2008 Page 60


Informatique 3 Jeu d’instruction du processeur ARM V5

Instruction Fonction
ADC Addition de deux valeurs de 32 bits avec la retenue
ADD Addition de deux valeurs de 32 bits
AND Opération logique ET entre deux valeurs à 32 bits
B Saut relatif ± 32 Mégas bytes
BIC Effacer les bits d’une valeur 32 bits
BKPT Point d’arrêt software (break point)
BL Saut avec stockage de l’adresse de retour (appel de sous-routine)
BLX Saut avec stockage de l’adresse de retour et changement de registre
BX Saut avec changement de registre
CDP CDP2 Opération coprocesseur
CLZ Compter les zéros, qui précèdent
CMN Comparaison inversée de deux valeurs 32 bits
CMP Comparaison de deux valeurs 32 bits
EOR Opération logique OU exclusive entre deux valeurs 32 bits
LDC LDC2 Charger le coprocesseur avec une ou plusieurs valeurs 32 bits
LDM Charger plusieurs valeurs de 32 bits depuis la mémoire dans les registres ARM
LDR Charger la valeur avec une adresse virtuelle dans un registre ARM
MCR MCR2 MCRR Charger une ou plusieurs registres ARM dans le coprocesseur
MLA Multiplication et accumulation d’une valeur 32 bits
MOV Charger la valeur 32 bits dans un registre
MRC MRC2 MRRC Charger depuis le processeur dans un ou plusieurs registres
MRS Copier le registre de statut (CPSR ou SPSR) dans un registre ARM
MSR Copier depuis le registre ARM dans un registre d’état (CPSR ou SPSR)
MUL Multiplier deux valeurs de 32 bits
MVN Charger une valeur 32 bits, préalablement inversée, dans un registre
ORR Opération logique OU entre deux valeurs 32 bits
PLD Indique l’adresse de la case mémoire, qui est en train d’être chargée
QADD Addition signée de deux valeurs 32 bits avec limitation du dépassement de capacité
QDADD Addition signée double de deux valeurs 32 bits et limitation du dépassement de capacité
QDSUB Soustraction signée double de deux valeurs 32 bits et limitation du dépassement de
capacité
QSUB Soustraction signée de deux valeurs 32 bits avec limitation du dépassement de capacité
RSB Soustraction inverse de deux valeurs 32 bits
RSC Soustraction inverse de deux valeurs 32 bits avec la retenu
SBC Soustraction de deux valeurs 32 bits avec retenu
SMLAxy Multiplication/addition signées (16x16)+32 = 32 Bit
SMLAL Multiplication/addition larges signées (32x32)+64 = 64 Bit
SMLALxy Multiplication/addition larges signées (16x16)+64 = 64 Bit
SMLAWxy Multiplication/addition signées ((32x16)>>16)+32 = 32 Bit
SMULxy Multiplication signée (16x16) = 32 Bit
SMULWy Multiplication/addition signées ((32x16)>>16)+32 = 32 Bit
STC STC2 Stocker une ou plusieurs valeurs depuis le processeur dans la mémoire
STM Stocker plusieurs registres ARM dans le processeur
STR Stocker des registres à des adresses virtuelles
SUB Soustraire deux valeurs à 32 bits
SWI Interruption software
SWP Echanger les registres ARM avec la mémoire de façon byte ou mot
TEQ Comparer deux valeurs 32 bits
TST Tester un bit dans un registre 32 bits
UMLAL Multiplication/addition larges non singées (32x32)+64 = 64 Bit
UMUL Multiplication large non signée (32x32) = 64 Bit
Tableau 12 : Jeu d’instruction du processeur ARM à partir de la version V5E.

Version 3.1, juin 2008 Page 61


Informatique 3 Jeu d’instruction du processeur ARM V5

4.1.1 La syntaxe des instructions ARM


Le processeur ARM est une machine avec trois opérandes. Toutes les instructions, qui traitent les données, ne
travaillent qu’avec des registres.

Syntaxe :

Opcode Rd, Rn {,N}

Le code d’opération est une des instructions du Tableau 12.

Tous les registres de r0 à r15 peuvent être utilisés pour Rd et Rn. L’opérande N permet de pré traiter
facultativement un des opérandes avec le décalage à barilier (Barrel Shifter). N peut être une valeur constante, un
registre ou un registre décalé. L’opération de décalage ne modifie pas le contenu du registre source. Toutes les
valeurs constantes ne sont toutefois pas admises, car ces dernières ne peuvent être composées que de valeurs 8
bits décalées dans un registre 32 bits. Des informations plus détaillées concernant les opérations de décalage sont
fournit au chapitre 4.3.2.

Exemple :
Avant :
r5 = 5
r7 = 8

MOV r7, r5, LSL #2 @ r7 = r5*4 = (r5 << 2)

Après :
r5 = 5
r7 = 20

4.1.2 La syntaxe de la notation


Les descriptions des instructions suivantes utilisent la notation du Tableau 13. Les éléments de la syntaxe, qui
sont souvent utilisé, sont traités plus en détails dans les chapitres suivants.

[ ] Accès indirect, indexation


{ } Elément facultatif
< > Un élément parmi d’autres éléments
| Choix parmi une liste (ou)
Tableau 13 : Les éléments de la syntaxe pour la description formelle des instructions.

Accès indirect, indexation []


L’accès s’effectue à l’élément, qui est indexé entre parenthèses. L’indexation peut être soit l’adresse d’une case
mémoire ou une position de bit. Ainsi [Rn] représente la valeur de la variable, qui est adressée par l’adresse
stockée dans Rn.

Choix parmi une liste|


Cette notation permet de choisir un élément parmi une liste. LDR | LDR B est par exemple une autre
formulation pour LDR {B}.

Un élément parmi une liste <>


La notation <> représente exactement un élément parmi une liste. La liste est en générale soit une collection de
valeur ou un espace d’adressage.

Les éléments facultatifs {}


Les éléments facultatifs dans une expression sont définies entres accolades. La notation LDR{B} est par
exemple une abréviation pour LDR | LDRB.

Les noms de registre


Rd, Rm, Rn, Rs, RdHi & RdLo sont des registres ARM r0-r15.
Ld, Lm, Ln & Ls représentent les registres ARM inférieur r0-r7.
Hd, Hm, Hn & Hs représentent les registres ARM supérieurs r8-r15.
Cd, Cm & Cn sont des registres du coprocesseur dans la zone c0-c15

Version 3.1, juin 2008 Page 62


Informatique 3 Jeu d’instruction du processeur ARM V5

sp, lr et pc sont des synonymes pour r13, r14 et r15.


Rn[a] représente le bit a de la valeurs, qui est stockée dans le registre Rn.
Rn[a:b] représente la suite des bits depuis la position a jusqu’à b du contenu du registres Rn.
RdHi:RdLo représente une valeur 64 bits. RdHi est ainsi le mot de poids le plus fort et RdLo le mot de poids
le plus faible.

Les valeurs constantes


<immedN> représente une valeur entière, qui est représentée avec N bits. Ainsi <immed8> représente une
valeur dans le domaine 0..255.
<immedN>*size représente une suite de nombres, avec des pas successifs size. Ainsi <immed5>*4
représente une valeur parmi 0, 4, 8, …, 124.
<AddressN> est une adresse de case mémoire, représenté avec un déplacement (offset) relatif. L’adresse doit
se situer dans la zone pc-2N <= adresse < pc+2N.
<A-B> représente une valeur entière dans la zone A à B.
<rotated_immed> est une valeur 32 bits, qui est représentée par une valeur 8 bits non signées et qui peut être
déplacé vers la gauche ou vers la droite par pas de deux bits. C'est-à-dire que par exemple <rotated_immed>
est équivalent à <immed8> ROR (<immed4>*2).

Le code d’état du programme


<cond> représente tous les bits du registres d’état du processeur ARM selon le Tableau 14.

Les opérations de décalage


<imm_shift> représente l’argument de décalage, qui est une constante. Le domaine de validité de cette
constante dépend naturellement du type de l’opération de décalage, comme Par exemple : LSR: #<1-31>,
ASR: #<1-32>.
<reg_shift> est l’argument de décalage, qui est représenté par le contenu d’un registre.
<shift> comprend à la fois <imm_shift> et <reg_shift>.

4.1.3 Exécution d’instruction conditionnelle


Presque toutes les instructions peuvent être exécutées de façon conditionnelle. Les sauts conditionnels peuvent
ainsi être évités dans la plupart des procédures. Les sauts nécessitent une vidange du pipeline des instructions. Ce
qui engendre des temps d’attente supplémentaires.

Les conditions, qui doivent être évaluées pour l’exécution des instructions conditionnelles, sont lues à partir des
bits du registre d’état courant du programme (CPSR). Ces derniers sont normalement fixés par l’instruction, qui
a été exécutée en dernier par le processeur (en générale des opérations de comparaison). La condition est notée
comme suffixe (ou code de condition) après l’instruction. Le Tableau 14 contient les différentes conditions.

Les opérations non comparatives, qui sont exécutées par l’unité arithmétique (ALU), peuvent également
influencer les bits d’état. Dans ce cas il faut ajouter un S au code d’opération. Les opérations arithmétiques
peuvent influencer les bits N, Z, C et V ; les opérations logiques les bits N et Z ; et le décalage à barillet (barrel-
shifter) uniquement le bit C.

Version 3.1, juin 2008 Page 63


Informatique 3 Jeu d’instruction du processeur ARM V5

Condition Drapeau (flag) Description


EQ Z Egalité
NE !Z Inégalité
CS,HS C Plus grand que ou égalité (non signé)
CC,LO !C Plus petit (non signé)
MI N Minus, négatif
PL !N Positif ou nul
VS V Dépassement de capacité (Overflow)
VC !V Pas de dépassement de capacité
HI C && !Z Plus grand que (non signé)
LS !C && Z Plus petit que ou égalité (non signé)
GE (N == V) Plus grand que ou égalité (signé)
LT (N != V) Plus petit que (signé)
GT !Z et (N == V) Plus grand que (signé)
LE Z ou (N != V) Plus petit que ou égalité (signé)
Tableau 14 : Les conditions (condition code) pour les instructions conditionnelles

Les instructions LO ou HS peuvent être utilisées au lieu de CC ou CS. Ces dernières, comme les instructions LS
et HI, se réfèrent à des opérations de comparaison non signée. Par contre LT, GE, LE et GT se réfèrent à des
opérations de comparaison signée. Le suffixe AL (always) doit être mentionné pour des raisons d’intégralité. Ce
dernier existe de façon formelle et représente la condition standard en absence de suffixe. Toutefois l’assembleur
gcc ne l’admet pas comme suffixe en présence d’instructions.

Exemple :
Définition du GGT (a, b), qui peut être défini dans un langage de programmation évoluée à l’aide d’une
division en chaîne de la manière suivante :

while (a != b)
if (a > b)
a -= b;
else
b -= a;

Un première implémentation en assembleur ARM avec les registres r1 et r2 pour le stockage respectif de a et
b:

ggt: CMP r1, r2


BEQ endIf
BLT aIsSmaller
SUB r1, r1, r2
B ggt
aIsSmaller:
SUB r2, r2, r1
B ggt
endIf:

Cette solution est basée sur des sauts de programme. A chaque saut il faut vider le pipeline des instructions, ce
qui ralenti fortement le temps d’exécution du programme. Les instructions conditionnelles permettent de réduire
ce temps d’exécution. De plus le programme devient plus court.

ggt: CMP r1, r2


SUBGT r1, r1, r2
SUBLT r2, r2, r1
BNE ggt
endIf:

Le registre de compteur de programme peut être utilisé comme registre de destination avec toutes les opérations
ALU. Les processeurs ARM soutiennent les formats petit et gros boutiste (little and big endian). Le standard est
cependant petit boutiste.

4.1.4 Le jeu d’instruction Thumb


Le jeu d’instruction Thumb est un jeu d’instruction à 16 bits. Ce dernier est pratiquement équivalent au jeu
d’instruction ARM à 32 bits. Il permet de densifier le code (souvent à plus de 50%). Ce qui entraîne une
amélioration de la performance dans de nombreux cas. Le jeu d’instruction Thumb n’est cependant pas aussi

Version 3.1, juin 2008 Page 64


Informatique 3 Jeu d’instruction du processeur ARM V5

clairement structuré que celui d’ARM. Le chapitre 6 traite ce sujet plus en détails.

4.1.5 Les coprocesseurs


La plupart des processeurs ARM sont implémentés en tant que cœur de processeur. Souvent ils contiennent des
coprocesseurs pour les opérations de calcul vectoriel à virgule flottante (en anglais Vector Floating Point et
abrégé par VFP), la gestion de la mémoire (MMU) et le traitement du signal (DSP).

Le coprocesseur CP15 est destiné au contrôle du système. Il permet de gérer la mémoire cache, la mémoire
externe (MMU), les opérations d’écriture et de lecture à l’aide de tampon et d’autre option du système.

Les processeurs, qui soutiennent le VFP, contiennent le CP10 pour les opérations arithmétique à virgule flottante
de précision simple et le CP11 pour les opérations de précision double. L’ARM V5TE, qui est utilisé avec la
carte de développement CARME, ne possède pas de coprocesseur à virgule flottante.

4.2 La vue d’ensemble du jeu d’instructions


Les opérations du jeu d’instruction ARM peuvent être réparties dans les groupes suivants :
• Les transferts de données
• Les instructions arithmétique et logiques
- L’arithmétique des entiers
- Les instructions logiques
- Les instructions de décalage et de rotation
- Les manipulations de bit
• Sauts de programme
- Sauts non conditionnels
- Sauts conditionnels
• System Control

Les chapitres suivants traitent ces groupes d’instructions.

4.3 Les transferts de données


Le processeur ARM, de par son architecture RISC, ne connaît que les opérations de transfert de données entres
registres (MOV), depuis la mémoire externes aux registres (LDR ) et depuis les registres à la mémoire externes
(STR). Les transferts de données entres mémoires externes ne sont pas possibles. Ils peuvent être réalisés de
façon byte (8 bits), demi mot (16 bits) et mot (32 bits). Cependant, l’accès mot ne peut être réalisée qu’avec
adressage mot, c'est-à-dire modulo 4 (.align 4).

Version 3.1, juin 2008 Page 65


Informatique 3 Jeu d’instruction du processeur ARM V5

Instruction Opérande Opération Description


SWP Reg1,Reg2,Reg3 Reg2 -> [Reg3], Echange le contenu du registre avec la
Reg1 <- [Reg3] mémoire
MOV Reg,Op2 Reg := Op2 Copier le contenu d’un registre ou une
valeur constante dans un registre
MVN Reg,Op2 Reg := ~OP2 Copier le complément à un du contenu
d’un registre ou d’une valeur constante
dans un registre
LDR Reg, Address Reg := [address] Charger le contenu de la mémoire dans
un registre
STR Reg, Address [address] := Reg Stocker le contenu d’un registre dans la
mémoire
MSR Reg PSR := Reg Copier le contenu du registre dans le
registre d’état du programme PSR
(Status/Flags)
MRS Reg Reg := PSR Copier le contenu du registre PSR
(Status/Flags) dans un registre
MCR p#, op, cReg, cReg := Reg1 {op Reg2} Exécuter l’opération op à l’aide du
Reg1, Reg2 coprocesseur p# et stocker le résultat
dans le registre du coprocesseur.
MRC p#, op, Reg1, Reg := cReg1 {op cReg2} Exécuter l’opération op à l’aide du
Reg2 coprocesseur p# et stocker le résultat
dans le registre Reg2.
LDC p#, cReg, cReg := [Address] Charger le registre du coprocesseur
Address avec le contenu de la mémoire
STC p#, cReg, [Address] := cReg Charger le registre du coprocesseur
Address avec le contenu de la mémoire
LDM Rbase,{Rlist} [Rbase] -> {Rlist} Charger plusieurs registres avec le
contenu de la mémoire (pile pop)
STM Rbase,{Rlist} {Rlist} -> [Rbase] Stocker le contenu de plusieurs dans la
mémoire (pile push)
Tableau 15 : Les instructions de transfert de données, entre registres et depuis les registres à la mémoire
externe.

4.3.1 Les instruction de transfert de données entre registres MOV,


MVN
Ces instructions permettent de transférer les données entre registres mais, également, de charger les registres
avec des valeurs constantes.

La syntaxe générale est la suivante :

<MOV|MVN>{<cond>}{S} Rd, N

Le code d’opération MOV charge une valeur alors que MVN en charge le complément. Un suffise <cond>, qui
correspond au code de condition fourni au Tableau 14, peut être ajouté pour des réalisations conditionnelles.
Quand au suffixe S, il permet à l’opération de changer les bits d’état courant du processeur. L’opérande Rd
représente toujours le registre de destination, alors que l’opérande N peut représenter soit le contenu d’un registre
(éventuellement décalé) ou une valeur constante.

Exemple :

MOV r0, r1 @ r0 := r1
MOVS r0, #10 @ r0 := 10, fixe les bit d’état courant du programme
MVN r1, r0 @ r1 := ~r0
MOV pc, lr @ retour depuis la sous-routine

4.3.2 Le décalage à barilier (Barrel Shifter)


Les opérandes, qui sont contenus dans des registres (Rm), peuvent être prés décalés à l’aide du décalage à

Version 3.1, juin 2008 Page 66


Informatique 3 Jeu d’instruction du processeur ARM V5

barilier. La valeur de cet opérande peut ainsi être déplacée de 0 à 32 bits vers la gauche ou vers la droite, en
fonction de l’instruction. L’opération de décalage est toujours réalisée en un seul cycle d’horloge,
indépendamment du nombre de bits du décalage. La valeur originale du registre Rm n’est pas changée.

L’ALU traite effectivement la valeur contenue dans le registre Rn et celle fournie par le décalage à barilier N.

Rn Rm

Barrel-Shifter

Zwischenresultat N

ALU

Rd

Figure 67 : ALU avec le décalage à barilier

Certaines instructions de traitement de données comme MUL, CLZ ou QADD ne sont pas en mesure d’utiliser le
décalage à barilier. Dans ces cas, la valeur du registre Rm ne peut être utilisé que de façon directe.

Exemple :
Avant l’opération arithmétique, le contenu du registre Rm est décalé de deux bits vers la droite (LSR). Ce qui
correspond à une division par 4 de la valeur du registre. L’opération de décalage est équivalent à l’opérateur >>
du langage de programmation C.

Avant :
r0 = 0x11
r1 = 0x22

MOV r0, r1, LSR #2 @ r0 = r1 / 4

Après :
r0 = 0x8
r1 = 0x22

Le décalage à barilier connaît 5 sortes d’opération de décalage. Ces derniers sont fournis dans le Tableau 16 :

Instruction Effet Opération Résultat Domaine de


décalage
LSL Décalage logique vers la gauche x LSL y x << y #0-31 ou Rs
LSR Décalage logique vers la droite x LSR y (non signé) x >> y #1-31 ou Rs
ASR Décalage arithmétique vers la x ASR y (signé) x >> y #1-31 ou Rs
droite
ROR Rotation vers la droite x ROR y ((non signé) x>>y) | (x << (32-y)) #1-31 ou Rs
RRX Extension de la rotation vers la x RRX (cflag << 31)|((non signé) >> 1) 1 (fixe)
droite
Tableau 16 : Les opérations du décalage à barilier,
ou x représente la valeur à décaler et y le nombre de bit du décalage.

La syntaxe du décalage permet de définir le nombre de bit à décaler soit sous forme direct #shift ou à l’aide
d’un registre Rs, qui contient le nombre de bit du décalage. Le Tableau 17 illustre pratiquement toutes les
formulations possibles.

Version 3.1, juin 2008 Page 67


Informatique 3 Jeu d’instruction du processeur ARM V5

Opération de décalage pour N Syntaxe


Décaler selon la valeur constante #shift #shift
La valeur du registre Rm
Décalage logique vers la gauche en fonction de la valeur constante #shift Rm, LSL #shift
Décalage logique vers la gauche en fonction du registre Rs Rm, LSL Rs
Décalage logique vers la droite en fonction de la valeur constante #shift Rm, LSR #shift
Décalage logique vers la droite en fonction du registre Rs Rm, LSR Rs
Décalage arithmétique vers la droite en fonction de la valeur constante #shift Rm, ASR #shift
Décalage arithmétique vers la droite en fonction registre Rs Rm, ASR Rs
Rotation vers la droite en fonction de la valeur constante #shift Rm, ROR #shift
Rotation vers la droite en fonction du registre Rs Rm, ROR Rs
Rotation vers la droite étendue (33-Bit Rotation) Rm, RRX

Tableau 17 : La syntaxe des différentes opérations du décalage à barilier.

Exemple :
L’opération MOVS copie le contenu du registre r1, préalablement décalé de un bit vers la gauche, dans le
registre r0. Du fait que l’instruction contient le suffixe S, elle est en mesure de changer le contenu du registre
d’état courant du programme. Le bit 31 du registre r1 est ainsi copié dans le bit de carry.

Avant :
CPSR = nzcvqift_USER (Majuscule: mise à un, minuscule: mise à zéro)
r0 = 0x00000000
r1 = 0x80008001

MOVS r0, r1, LSL #1

Après :
CPSR = nzCvqift_USER
r0 = 0x00010002
r1 = 0x80008001

n z c v 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1

cpsr r1

r0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
n z c v 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Werden gesetzt bei einer


Instruktion mit S-Suffix

Figure 68 : L’instruction MOVS avec une opération de décalage LSR #1. Le bit 31 est copié dans le bit de carry
du registre d’état courant du processeur, car l’instruction MOV a été définie avec le suffixe S.

4.3.3 Les instructions de chargement de données LDR et STR


Les instructions de chargement de données permettent de transférer les données depuis la mémoire aux registres,
ou inversement. Le chargement d’une valeur constante dans un registre, qui ne peut pas être réalisé directement
avec les instructions MOV ou MVN, est également réalisé avec l’instruction LDR . Toutes les instructions de
chargement, mis à part LDRD et STRD, peuvent être exécutées pour des types de données mot, demi mot ou
byte. Le Tableau 18 fournit une vue d’aperçu de ces instructions.

Version 3.1, juin 2008 Page 68


Informatique 3 Jeu d’instruction du processeur ARM V5

Instruction Description Effet


LDR Charger un mot dans un registre Rd := mem32[Adresse]
STR Stocker un mot à partir d’un registre Mem32[Adresse] := Rd
LDRB Charger un byte dans un registre Rd := mem8[Adresse]
STRB Stocker un byte à partir d’un registre mem8[Adresse]:= Rd
LDRH Charger un demi mot dans un registre Rd := mem16[Adresse]
STRH Stocker un demi mot à partir d’un registre mem16[Adresse] := Rd
LDRSB Charger un byte signé dans un registre Rd := (signExtend) mem8[Adresse]
LDRSH Charger un demi mot signé dans un registre Rd := (signExtend)
mem16[Adresse]
STRD Stocker deux mots à partir de registres (DSP) Mem32[Adresse] := Rd
Mem32[Adresse+4] := R(d+1)
LDRD Stocker deux mots dans des registres (DSP) Rd=Mem32[Adresse]
R(d+1)=Mem32[Adresse+4]
Tableau 18 : Les opérations de chargement. Le bit de signe est dupliqué avec les transferts de données signées.

La syntaxe des instructions LDR et STR est la suivante :

<LDR|STR>{<cond>}{B|H|D} Rd, <Address>


LDR{<cond>}{SB|SH} Rd, <Address>

L’adresse de la case mémoire peut être définie de plusieurs manières. Dans les cas les plus simples, cette
dernière peut être une constante ou un registre. Les modes d’adressage sont traités plus en détails dans le chapitre
suivant.

Les instructions LDR D et STRD sont des extensions du jeu d’instruction DSP. Ces dernières permettent
respectivement de charger et de stocker le contenu de deux registres juxtaposés. La condition pour Rd est un
registre avec un numéro paire. Par exemple, l’instruction STRD avec Rd = r2 stockent le contenu des registres
r3 et r4 dans la mémoire.

Exemple :
Les instructions LDR et STR permettent respectivement de charger et de stocker les données dans la mémoire.
La condition pour l’adressage de la case mémoire est son alignement avec les types de données à transférer.
C'est-à-dire que cette dernière doit être modulo 4 pour les accès mot et paires pour les accès demi mot.

/* Charge le registre r0 avec la valeur contenu par la case mémoire,


qui est adressée par le registre r5. */

LDR r0, [r5]

/* Stocker le contenu du registre r0 dans la case mémoire,


qui est adressée par le registre r5. */
STR r0, [r5]

/* Charge le registre r0 avec la valeur contenu par la case mémoire,


qui est adressée par le symbole myvar
(myvar doit être définie dans le même segment). */

STR r0, myvar

4.3.4 Modes d’adressage pour les instructions de chargement et de


stockage
L’architecture ARM prévoit de nombreux modes d’adressage. L’adresse de la case mémoire à accéder est
toujours composée d’une adresse de base et d’un indexe (c. à d. un déplacement). La base est contenue dans
n’importe quel registre, mis à part celui du compteur de programme pc.

Selon la formule de lecture ARM, les modes d’adressage sont qualifiés de « méthode d’indexation ». Il existe
fondamentalement trois méthodes d’indexations. Ces dernières peuvent être complétés avec des nombreuses
variantes de calcul du déplacement (offset).

Version 3.1, juin 2008 Page 69


Informatique 3 Jeu d’instruction du processeur ARM V5

Méthode d’indexation Données Registre contenant Exemple


l’adresse de base
Pré indexation avec retour mem[Basis+Offset] Basis+Offset LDR r0,[r1,#2]!
Pré indexation mem[Basis+Offset] Basis+Offset LDR r0,[r1,#2]
Post indexation mem[Basis+Offset] Basis+Offset LDR r0,[r1],#2
Tableau 19 : Les méthodes d’adressage (d’indexation) pour l’accès à la mémoire. Le déplacement est toujours
une grandeur signée. Par exemple, ce dernier peut être défini comme une valeur ± 12 bits.

Dans la méthode pré indexation, l’adresse de la case mémoire est obtenue par addition du contenu du registre de
base avec le déplacement. Le contenu du registre de base reste constant durant toute l’opération de transfert.
Cependant, si l’on défini une récriture en retour (write back) avec « ! », la nouvelle adresse est copié dans le
registre de base avant le transfert de données.

La méthode post indexation reprend également la nouvelle adresse, mais après le transfert de données.

Les méthodes post et pré indexation avec write back sont surtout utilisées pour les accès aux Tableaux (array).
Quant à la méthode pré indexation, elle est souvent utilisée pour accéder aux structures de données.

Exemple :
L’exemple suivant montre les accès avec les modes d’adressage selon le Tableau 19, avec les valeurs des
registres avant et après l’exécution du transfert de données. Toutes les instructions possèdent la même situation
initiale.

Avant :
r0 = 0x000000000
r1 = 0x000100000
mem32[0x00010000]=0x10101010
mem32[0x00010004]=0x20202020

Pré indexation avec write back

LDR r0, [r1, #4]!

Après :
r0 = 0x20202020
r1 = 0x00010004

Pré indexation :
LDR r0,[r1,#4]

Après :
r0 = 0x20202020
r1 = 0x00010000

Post indexation :

LDR r0,[r1],#4

Après :
r0 = 0x10101010
r1 = 0x00010004

Il existe de nombreuses variantes pour le calcul du déplacement (offset) : des valeurs direct, des contenus de
registre ou des contenus de registre décalés. Tableau 20 fournit une vue d’aperçu des modes d’adressage pour les
accès du type mot ou byte non signés.

Version 3.1, juin 2008 Page 70


Informatique 3 Jeu d’instruction du processeur ARM V5

Mode d’adressage Syntaxe


Pré indexation avec un offset constant [Rn, #±<offset12>]
Pré indexation avec un offset registre [Rn, ±Rm]
Pré indexation avec un décalage de l’offset registre [Rn, ±Rm, shift #<shift_value>]
Pré indexation avec write back et un offset constant [Rn, #±offset12]!
Pré indexation avec write back et un offset registre [Rn, ±Rm]!
Pré indexation avec write back et un décalage de l’offset [Rn, ±Rm, shift #<shift_value>]!
registre
Post indexation avec un offset constant [Rn], #±<offset12>
Post indexation avec un offset registre [Rn], ±Rm
Post indexation avec un décalage de l’offset registre [Rn], ±Rm, shift #<shift_value>
Tableau 20 : La syntaxe des modes d’adressage pour les accès simple de type mot

Des limitations existent pour les autres instructions. Par exemple, les instructions STRSB, STRSH, STRH et
STRB ne peuvent pas utiliser le décalage à barilier (barrel-shifter). De plus le déplacement est limité à +/- 8 bits
autour de l’adresse de base.

Mode d’adressage Syntaxe


Pré indexation avec un offset constant [Rn, #±<offset8>]
Pré indexation avec un offset registre [Rn, ±Rm]
Pré indexation avec write back et un offset constant [Rn, #±<offset8>]!
Pré indexation avec write back et un offset registre [Rn, ±Rm]!
Post indexation avec un offset constant [Rn], #±<offset8>
Post indexation avec un offset registre [Rn], ±Rm
Tableau 21 : Les méthodes d’adressage autorisées pour les types de données signés et non signés.

Exemple en conclusion :
str r1, [r2, r4]! @ stock r1 in [r2+r4] and copy the base address r2+r4 in r2

str r1, [r2], r4 @ stock r1 in [r2] and copy the base address r2+r4 in r2

str r1, place @ stock r1 pc relative in place

ldr r1, [r2, #16] @ load r1 with [r2+16]. r2 will not change

ldr r1, [r2, r3, LSL#2] @ load r1 with [r2+r3*4] laden

ldreqb r1,[r2,#5] @ conditional load the byte of r1 with [r2+5].


@ the bits D8 up to D31 will be full with zero.

4.3.5 L’instruction SWP


L’instruction SWP permute le contenu d’un registre avec celui d’une case mémoire. Elle représente ainsi une
combinaison des instructions STR et LDR . Elle est exécuté comme une instruction atomique à l’aide du
système de bus, et ne peut ainsi pas être interrompue par une interruption jusqu’à ce que le transfert de données
ne soit terminé.

La syntaxe est la suivante :

SWP{<cond>}{B} Rd, Rm, [Rn]

Instruction Description Déroulement interne


SWP Echange de mot entre le registre et tmp = mem32[Rn]
la mémoire mem32[Rn] = Rm
Rd = tmp
SWPB Echange de byte entre le registre et tmp = mem8[Rn]
la mémoire mem8[Rn] = Rm
Rd=tmp
Tableau 22 : Effet des instruction SWP et SWPB

Version 3.1, juin 2008 Page 71


Informatique 3 Jeu d’instruction du processeur ARM V5

Exemple :
L’instruction SWP charge la donnée depuis la case mémoire 0x0001A000 dans le registre r0 et copie le
contenu du registre r1 dans la case mémoire 0x0001A000.

Avant :
r0 = 0x555555555
r1 = 0xAAAAAAAAA
r2 = 0x0001A0000
mem32[0x0001A000]=0x10101010

SWP r0, r1, [r2]

Après :
r0 = 0x10101010
r1 = 0xAAAAAAAAA
r2 = 0x0001A0000
mem32[0x0001A000]=0xAAAAAAAA

ARM- Prozessorregister Arbeitsspeicher (RAM)

r0 0x55555555
0x10101010
r1 0xAAAAAAAA
0x19FFC
r2 0x0001A000
0x10101010
0xAAAAAAAA
r3
0x1A004
r4
0x1A008
r5
0x1A00C
r6
0x1A010
r7
0x1A014

r15

4.3.6 Chargement et stockage multiple LDM et STM


Les opérations de chargement et de stockage multiple LDM et STM permettent de transférer le contenu d’un bloc
de registres ou de mémoire avec une seule instruction. Ce type de transfert est plus efficace que celui avec
plusieurs instructions de transfert simples.
L’exécution des instructions LDM et STM nécessite 2+N*t cycles d’horloge ; ou N représente le nombre de
registres à transférer et t le nombre de cycle d’horloge nécessaire pour accéder à la mémoire externe. Ces
instructions sont également atomiques, c'est-à-dire qu’elles ne peuvent pas être interrompues par des
interruptions. L’utilisation des instructions LDM et STM peut par conséquent détériorer le temps de latence du
traitement des interruptions.

La syntaxe des instructions LDM et STM est la suivante :

<LDM|STM>{<cond>}<AddressMode> Rn{!}, <RegisterBloc>{^}

Le mode d’adressage définit l’accès mémoire selon le Tableau 23. Il est possible de travailler avec des adresses
croissantes (incrémentation) ou décroissantes (décrémentation). De plus, le calcul de la nouvelle adresse peut
être effectué avant ou après le transfert des données. La nouvelle adresse peut également être écrite dans le
registre Rn, comme la pré indexation avec l’écriture en retour (write back) !

Mode d’adressage Description Adresse de départ Adresse d’arrivée Rn!


IA Incrémenter après Rn Rn+4*N-4 Rn+4*N
IB Incrémenter avant Rn+4 Rn+4*N Rn+4*N
DA Décrémenter après Rn-4*N+4 Rn Rn-4*N
DB Décrémenter avant Rn-4*N Rn-4 Rn-4*N
Tableau 23 : Les modes d’adressage pour les instructions LDM et STM.
Ces derniers définissent la méthode de calcul de l’adresse de la case mémoire.

Le registre Rn contient l’adresse mémoire, ou les données ont été lues ou déposées dans la mémoire. Si le
registre a été défini avec un opérateur d’écriture en retour (!), la nouvelle adresse sera écrite dans le registre,

Version 3.1, juin 2008 Page 72


Informatique 3 Jeu d’instruction du processeur ARM V5

comme avec les instruction LDR et STR. Le bloc de registre est défini entre accolades. Ce dernier contient tous
les registres, dont le contenu doit être transféré, soit par énumération avec des virgules ({r0, r3, r6}) ou
sous forme de domaine avec un trait d’union ({r0-r3}). Il n’y a pas de règle concernant la définition par
énumération des registres. Cependant, les registres avec les numéros les plus bas sont transportés en premier.

Lorsque cette instruction est exécutée dans un mode privilégié, l’opérateur « ^ » permet d’accéder aux registres
appartenant au mode utilisateur. La condition pour cela est de ne pas mentionner le registre pc et le bloc des
registres.

Exemple :
Les exemples suivants montrent l’effet des quatre modes d’adressage du Tableau 23, pour le stockage des
registres r0, r4 et r1 dans la mémoire à partir de l’adresse 0x00010000.

STMIA r9!,{r0,r1,r4} STMIB r9!,{r0,r1,r4}

r9start r0 0x00010000 r9start 0x00010000


r1 r0
r4 r1
r9end r9end r4
0x00010010 0x00010010

STMDA r9!,{r0,r1,r4} STMDB r9!,{r0,r1,r4}

0x0000FFF0 0x0000FFF0
r9end r9end r0
r0 r1
r1 r4
r9start r4 0x00010000 r9start 0x00010000

Exercice :
Le bloc des registres r0 à r4 doit être stocké dans la mémoire à partir de l’adresse 0x0001A000, dans un
ordre croissant. Le registre r6 doit être utilisé comme pointeur et il doit contenir, à la fin de l’instruction, la
dernière adresse mémoire. C'est-à-dire qu’il doit adresser le contenu du registre r4.

Solution :
Premièrement, il faut utiliser l’opérateur d’écriture en retour (!), afin que r6 contienne la dernière adresse après
l’exécution de l’instruction. Ensuite, il faut choisir le mode incrémenter avant, pour que r6 adresse le dernier
élément. Finalement, il faut soustraire 4 à l’adresse mémoire, afin que le programme écrive le contenu du
premier registre à l’adresse 0x0001A000.

ARM- Prozessorregister Arbeitsspeicher (RAM)

r0
r1
LDR r6,0x0001A000-4 0x00019FFC r6 start
STMIB r6!,{r0-r4} r2
0x0001A000 r0
r3
0x0001A004 r1
r6start 0x0001A000-4 r4
0x0001A008 r2
r0 0x0001A000 r5
0x0001A00C r3
r1 r6 0x0001A000-4
0x0001A010
0x0001A010 r4 r6end
r2 r7
0x0001A014
r3
r6end r4 0x0001A010 r15

4.3.7 Les instructions de la pile


Le processeur ARM ne connaît pas d’instruction pour la pile, contrairement aux autres processeurs. Les accès
pile sont réalisés avec les instructions LDM et STM. La gestion de la pile s’effectue à l’aide du pointeur de pile
sp. Ce dernier est associé de façon conventionnelle au registre r13.

Les architectures ARM permettent de conFigurer librement le fonctionnement de la pile. Par exemple, la pile

Version 3.1, juin 2008 Page 73


Informatique 3 Jeu d’instruction du processeur ARM V5

peut croître soit de façon ascendante (vers les adresses les plus hautes) ou de façon descendante (vers les
adresses les plus bas). Le mode d’adressage du pointeur de pile est également configurable. Ce dernier peut
adresser soit le dernier élément stocké, en mode plein (Full), ou la prochaine case libre, en mode vide (Empty).

La pile devrait être configurée soit de façon conventionnelle ou en fonction de codes déjà existants. Le standard
d’appel de procédure ARM-Thumb (ARM-Thumb Procedure Call Standard ≡ ATPCS) recommande d’utiliser la
pile en modes décroissant et plein (Full Descending). Les opérations « push » sont ainsi réalisées avec STMFD et
celles « pop » avec LDMFD (voir Tableau 24).

Le Tableau 24 illustre les différentes opérations push et pop en fonction des modes de configuration introduit ci-
dessus :

Mode Description pop =LDM push =STM


d’adressage
FA Full Ascending LDMFA LDMDA STMFA STMIB
FD Full Descending LDMFD LDMIA STMFD STMDB
EA Empty Ascending LDMEA LDMDB STMEA STMIA
ED Empty Descending LDMED LDMIB STMED STMDA
Tableau 24 : Les modes d’adressage pour les accès pile push et pop,
avec leur réalisation à l’aide des instructions LDM et STM.
Exemple :
Selon ATPCS, les opérations avec la pile doivent être réalisées en mode FD. La pile croît ainsi de façon
descendante et le pointeur de pile adresse son dernier élément.

STMFD sp!,{r1,r2}
Vorher: r1=0x00000005 Nachher: r1=0x00000005
r2=0x00000006 r2=0x00000006
sp=0x00020014 sp=0x0002000C

leer (undefiniert) sp 0x00000005 0x0002000C


leer (undefiniert) 0x00000006
sp 0x00000002 0x00020014 0x00000002
0x00000001 0x00000001

L’ajout du caractère « ^ » après les accolades a les conséquences suivantes :


1. Lorsque le registre pc fait parti de la liste des registres de l’instruction LDM, le contenu du registre CPSR
sera également rechargé. Avec l’instruction STM, ce dernier sera toujours stocké.
2. Avec les modes privilégiés, lorsque le registre pc n’est pas mentionnés dans la liste des instructions LDM et
STM, l’accès est réalisé sur les registres d’origine du mode utilisateur et sur les copies (Par exemple : r8 à
r12 dans le mode FIQ) de r13 et r14.

Exemple :
L’opération push avec STMED a pour conséquence, que le pointeur de pile adresse la prochaine case vide de la
pile.

STMED sp!,{r1,r2}
Vorher: r1=0x00000005 Nachher: r1=0x00000005
r2=0x00000006 r2=0x00000006
sp=0x00020014 sp=0x0002000C

leer (undefiniert) sp leer (undefiniert) 0x0002000C


leer (undefiniert) 0x00000005
sp leer (undefiniert) 0x00020014 0x00000006
0x00000002 0x00000002
0x00000001 0x00000001

4.3.8 Les instructions d’état MRS et MSR


Les instructions d’état permettent de transférer des données dans le registre d’état du programme (Program

Version 3.1, juin 2008 Page 74


Informatique 3 Jeu d’instruction du processeur ARM V5

Status Register ≡ PSR). L’instruction MSR permet d’écrire dans les registres CPSR (current program status
register) et SPSR (saved program status register). Inversement l’instruction MRS permet d’écrire le contenu des
registres CPSR et SPSR dans la mémoire.

La syntaxe des instruction MRS et MSR et la suivante :


MRS{<cond>} Rd, <CPSR|SPSR>
MSR{<cond>} <CPSR|SPSR>_<field>,Rm
MSR{<cond>} <CPSR|SPSR>_<field>,#Directvalue

L’étiquette « field » définie la zone du registre CPSR, dans laquelle if faut écrire (voir Figure 69). field
peut être une combinaison des caractère suivants : Control (c), Extension (x), Status (s) et Flags (f). Donc Par
exemple : CPSR_c ou CPSR_cf.

Flags [24:31] Status [16-23] Extension [8:15] Control [0:7]


Fields

Bit 31 30 29 28 27 7 6 5 4 0

N Z C V Q not used I F T Mode

Figure 69 : Organisation des bits d’état dans le registre CPSR

Exemple :
Contrairement aux nombreux autres types de processeurs, les processeurs ARM ne possèdent pas d’instructions
pour libérer ou masquer les interruptions. Cela est réalisé avec la mis à un ou à zéro du bit 6 pour le FIQ et du bit
7 pour le IRQ. La mise à zéro du drapeau I dans le champ de contrôle permet de libérer les interruptions IRQ.
Pour cela il faut d’abord sauver le contenu du registre CPSR dans un registre de travail (dans cet exemple r1).
Ensuite il faut effacer le bit 7. Et finalement il faut transférer le nouvel état dans le registre CPSR.

Avant :
CPSR = nzcvqIFt_SYS

@ Enable IRQ interruption


MRS r1, CPSR
BIC r1, r1, #x80 @ Clear bit 7
MSR CPSR_c, r1

Après :
CPSR = nzcvqiFt_SYS

Cet exemple part du principe que le processeur se trouve dans un mode privilégié (dans cet exemple le mode
SYS). Dans le mode utilisateur, le processeur est capable de lire le contenu du registre CPSR, mais il ne peut
changer que les bits du champ des drapeaux (les bits 24 à 31).

4.3.9 Les instructions du coprocesseur LDC, STC, MRC, MCR et CDP


Les instructions LDC, STC, MRC et MCR permettent de transférer les données depuis et au coprocesseur selon le
Tableau 25. Ces instructions fonctionnent de la même manière que celles LDR et STR. Les instructions
coprocesseur représentent une extension du jeu d’instruction de base du processeur. Dans l’architecture ARM, la
gestion de la mémoire (MMU, cache) et les autres ajustements du système sont réalisés par le coprocesseur. Le
calcul effectif est démarré dans le processeur principal avec CDP.

La syntaxe des instructions coprocesseur est la suivante :

<LDC | STC>{<cond>} cp, cd, AddressMode


<MRC | MCR>{<cond>} cp, opcode1, rd, cd, cm {, opcode2}
CDP{<cond>} cp, opcode1, cd, cn {,opcode2}
CDP2 cp, opcode1, cd, cn {,opcode2}
<MRC2 | MCR2> cp, opcode1, rd, cd, cm {, opcode2}
<LDC2 | STC2> cp, cd, AddressMode

Version 3.1, juin 2008 Page 75


Informatique 3 Jeu d’instruction du processeur ARM V5

cp représente le numéro du coprocesseur. Ce dernier se situe entre cp0 et cp15. Le coprocesseur 15 (CP15) est
réservé pour la configuration du système. Ce qui comprend la gestion de la mémoire et du cache. Les registres
cn, cm et cd sont les registres internes du coprocesseur. L’opération effective du coprocesseur est définie avec
le code d’opération opcode. Ce dernier est spécifique au coprocesseur.

Instruction Description
LDC STC LDC2 STC2 Transfert de données entre le coprocesseur et la mémoire
MRC MCR MCR2 MRC2 Transfert de données entre le coprocesseur et les registres
CDP CDP2 Exécution de l’instruction coprocesseur
Tableau 25 : Aperçu des instructions coprocesseur destinées aux transferts de données
et à démarrer les actions du coprocesseur.

Il existe quatre modes d’adressage, avec lesquels le coprocesseur peut accéder à la mémoire. Ces derniers sont
fournis dans le Tableau 26.

Mode d’adressage Syntaxe


Pré indexation avec un offset constant [Rn,#+/-offset8]
Pré indexation avec écriture en retour et un offset constant [Rn,#+/-offset8]!
Post indexation avec un offset constant [Rn], #+/-offset8
Sans indexe mais avec une option spécifique au coprocesseur [Rn], <option>
Tableau 26: Un aperçu des modes d’adressage du coprocesseur.

Exemple
Le registre c0 du CP15 contient le numéro d’identification du coprocesseur. Ce dernier est transféré depuis le
CP15 dans le registre de travail r0.

Avant :
r0=0x00000000
MRC p15,0,r0,c0,0

Après :
r0 = 0x69054117

Interprétation du résultat pour les bord de développement CARME : Les bit [24:31]=0x69 spécifient le
fabriquant Intel. Les bits [16:23]=0x05 représente l’architecture et la variante 5TE. Les bits [4:15]=0x411
correspondent au numéro d’article (Implemented Defined Part Number) et les bits [0:3]=0x7 le numéro de la
révision (Implemented Defined Revision Number). Référence : ARM Architecture Reference Manual, p. B2-7:
Main ID Register – Post ARM7 Processors.

4.4 Les instructions arithmétiques et logiques


Les instructions arithmétiques et logiques constituent la plus grande partie des opérations de traitement de
données. Comme chez la plupart des processeurs RISC, ces dernières ne peuvent s’exécuter qu’avec des
registres. Les instructions, qui traitent directement les données de la mémoire, ne sont donc pas possibles. Les
opérandes et le résultat des opérations arithmétiques et logiques possèdent un format unique de 32 bits.
Toutefois, certaines opérations peuvent livrer un résultat de 64 bits, qui sera alors stocké dans deux registres.

Les instructions de comparaison et de test représentent des cas spéciaux d’opérations logiques. Ces derniers
modifient les bits d’état du registre CPSR. Les bits d’état constituent les bases de décision pour l’exécution des
instructions conditionnelles.

La spécialité des processeurs ARM est que leurs instructions arithmétiques et logiques ne modifient pas ses bits
d’état courant. Toutefois, cela peut être forcé avec le suffixe « S », qu’il faut ajouter à la fin de l’instruction. Les
opérations étendues, comme par exemple les instructions DSP (QADD, SMLA etc.) qui ne font pas partie du jeu
d’instruction du noyau, ne peuvent pas être complétées avec ce suffixe. Elles ne sont donc pas en mesure de
modifier les bits d’état.

Les instructions du Tableau 27 seront décrites dans les chapitres suivants :

Version 3.1, juin 2008 Page 76


Informatique 3 Jeu d’instruction du processeur ARM V5

Instruction Description
ADD Adition 32 bits
ADC Adition 32 bits avec report de la retenu
AND Opération logique ET
BIC Effacer un bit (NICHT UND)
CMP Comparaison
CMN Comparaison inverse
EOR Opération logique OU exclusive
MUL Multiplication 32 bits
MLA Multiplication et addition 32 bits
ORR Opération logique OU
QADD Addition 32 bits avec protection contre les dépassements de capacité (DSP)
QDADD Addition 32 bits avec protection contre les dépassements de capacité (DSP)
QDSUB Soustraction 32 bits avec protection contre les dépassements de capacité (DSP)
QSUB Soustraction 32 bits avec protection contre les dépassements de capacité (DSP)
RSB Soustraction 32 bits inverser
RSC Soustraction 32 bits inverser avec report de la retenu
SMLA Multiplication 16 bits / addition 32 bits signées (DSP)
SMLAL Multiplication 16 bits / addition 64 bits signées (DSP)
SMLAW Multiplication 32x16 bits / addition signées (DSP)
SMUL Multiplication 16 bits signée (DSP)
SMULW Multiplication 32x16 bits signée (DSP)
SUB Soustraction 32 bits
UMLULL Multiplication 32 bits non signée
Tableau 27 : Aperçu des instructions arithmétiques et logiques.
Cette famille comprend également celles de comparaison et de test.

4.4.1 L’arithmétique des entiers


Ces instructions comportent les opérations de calcul de base et les comparaisons arithmétiques.

Version 3.1, juin 2008 Page 77


Informatique 3 Jeu d’instruction du processeur ARM V5

Instruction Opérande Description Opération


ADD Rd, Rn, N Addition 32 bits Rd=(Rn+N)

ADC Rd, Rn, N Addition 32 bits avec report Rd=Rn+N+Carryflag


MUL Rd, Rn, Rs Multiplication 32 bits Rd=Rn*Rs
MLA Rd, Rn, Rs, Multiplication / Addition 32 bits Rd=Rn*Rs+Rm
Rm
SMLA<x><y> Rd, Rm, Rs, Multiplication 32 bits / Addition Rd= Rn+Rm*Rs
Rn 32 bits signées
SMLAL Rd, Rm, Rs, Multiplication 16 bits / Addition Rd= Rn+(Rm.<x>*Rs.<y>)
Rn 32 bits signées
SMLAL<x><y> RdLo, RdHi, Multiplication 32 bits / Addition [RdHi,RdLo]=
Rm, Rs 64 bits signées [RdHi,RdLo]+Rm.<x>*Rs.<y>
SMLAW<y> RdLo, RdHi, Multiplication 32x16 bits / Rd=Rn+(((signed)Rm*Rs.<y>)>>16)
Rm, Rs Addition signées
SMUL<x><y> RdLo, RdHi, Multiplication 16 bits signée Rd= Rm.<x>* Rs.<y>
Rm, Rs
SMULW RdLo, RdHi, Multiplication 32x16 bits signée Rd= (Rm* Rs.<y>)>>16
Rm, Rs
SMULL RdLo, RdHi, Multiplication longue signée [RdHi,RdLo]= Rm*Rs
Rm, Rs
UMLAL RdLo, RdHi, Multiplication longue / addition [RdHi,RdLo]= [RdHi,RdLo]+Rm*Rs
Rm, Rs non signées
UMULL RdLo, RdHi, Multiplication longue non [RdHi,RdLo]= Rm*Rs
Rm, Rs signées
QADD Rd, Rm, Rn Addition 32 bits avec protection Rd=sat32(Rm+Rn)
anti-dépassement de capacité
QDADD Rd, Rm, Rn Addition 32 bits avec protection Rd=sat32(Rm+sat32(2*Rn))
anti-dépassement de capacité
QDSUB Rd, Rm, Rn Soustraction 32 bits avec Rd=sat32(Rm-sat32(2*Rn))
protection anti-dépassement de
capacité
QSUB Rd, Rm, Rn Soustraction 32 bits avec Rd=sat32(Rm-Rn)
protection anti-dépassement de
capacité
SBC Rd, Rn, N Soustraction 32 bits avec report Rd=Rn-N-!(Carryflag)
SUB Rd, Rn, N Soustraction 32 bits Rd=Rn-N
RSB Rd, Rn, N Soustraction 32 bits inverse Rd=N-Rn
RSC Rd, Rn, N Soustraction 32 bits inverse Rd=N1-Rn-!(Carryflag)
avec report
CMP Rn,N Comparaison Drapeau en fonction de Rn-N
CMN Rn,N Comparaison inverse Drapeau en fonction de Rn+N
TEQ Rn,N Tester l’égalité Drapeau en fonction de Rn^N
TST Rn,N Tester un bit Drapeau en fonction de Rn&N
Tableau 28 : Instructions arithmétiques sur des entiers et de comparaisons

L’opérande N peut être une valeur direct (constante avec #), le valeur d’un registre ou le contenu d’un registre
décalé. Les résultats 64 bits sont toujours déposés dans une paire de registres.

Les suffixes <x> et <y> peuvent être soi B ou T. Ces suffixes limitent les bits à traiter du registre : B au 16 bits
de poids plus faibles [0 - 15] et T au 16 bits de poids plus fort [16-31]. Ici <x> se réfère au registre Rm et <y> au
registre Rs.

Certaines instructions DSP possèdent un préfixe Q, qui spécifie un traitement avec de l’arithmétique saturée. Ce
qui permet d’éviter les dépassements de capacité. Dans ce cas, lorsqu’il y a dépassement de capacité, le résultat
est la valeur maximale ou minimale qui peut être représentée avec 32 bits.

Du fait que l’opérande N peut avoir plusieurs formes, il est logique de pouvoir réaliser la soustraction également
à l’envers. Les instructions de soustraction à l’envers RSB et RSC sont à disposition pour cela. Les instruction

Version 3.1, juin 2008 Page 78


Informatique 3 Jeu d’instruction du processeur ARM V5

CMP, CMN, TEQ, TST réalisent respectivement les opérations SUB, ADD, EOR et AND, mais elles n’en stockent
pas le résultat dans un registre. Les instructions MUL et MLA ont la limitation suivante : le registre Rd ne peut pas
être pc ou Rn.

Seules les opérations de comparaison sont en mesure de modifier les bits d’état courant du programme, contenus
dans le registre CPSR. Les opérations arithmétique ne peuvent donc par modifier ces bits par défaut. Toutefois,
si cela devait être le cas, il faudrait leur ajouter un suffixe « S » à la fin.

Le jeu d’instruction ARM ne prévoit pas d’opérations de division. Ces dernières doivent donc être implémentées
avec des opérations de décalage et de soustraction. L’arithmétique BCD n’est également pas soutenue de façon
directe par le processeur.

Exemple :
L’instruction SUB permet de réaliser une simple soustraction. Le code suivant soustrait la valeur du registre r2
à celle du registre r1 et stocke le résultat dans le registre r0

Avant :
r0 = 0x00000000
r1 = 0x00000005
r2 = 0x00000002

SUB r0, r1, r2

Après :
r0 = 0x00000003

Exemple :
Le jeu d’instruction ARM ne comprend pas les instructions d’inversion. Cela peut être réalisé avec une
soustraction inversée, en soustrayant la valeur 0 de la manière suivante : –z=0-z.

Avant :
r0 = 0x00000002

RSB 0, r0, #0

Après :
r0 = 0xFFFFFFFE

Exemple :
Une boucle de compteur peut être réalisée facilement avec l’instruction SUBS. Le code suivant décrémente la
valeur du registre r1. Le résultat, dans ce cas nulle, est stocké dans le registre r1. Parallèlement, Le drapeau Z du
registre d’état CPSR est mis à un. Ce qui pourrait être la base pour un saut conditionnel.

Avant :
CPSR = nzcvqIFt_USR
r1 = 0x00000001

SUBS r1, r1, #1

Après :
CPSR = nZcvqIFt_USR
r1 = 0x00000000

Exemple :
Les processeurs ARM V5 avec l’extension E possèdent de nombreuses instructions DSP. Cela concerne
également des opérations, qui ne traitent qu’une partie de l’opérande. Le suffixe B permet dans ces cas de
spécifier le demi mot inférieur (bits 0-15) et le suffixe T le demi mot supérieur (bits 16-31).

Avant :
r0 = 0x11111111
r1 = 0x22222222
r2 = 0x33334444
r3 = 0x11112222

SMLALBT r0, r1, r2, r3 @ [r0,r1]=[r0,r1]+Lo(r2)*Hi(r3)

Version 3.1, juin 2008 Page 79


Informatique 3 Jeu d’instruction du processeur ARM V5

Après :
r0 = 0x159E1D95
r1 = 0x22222222
r2 = 0x33334444
r3 = 0x11112222

4.4.2 Les instruction logiques


Ces instructions réalisent les opérations logiques ET, OU, OU exclusive et NON. Ces opérations permettent de
manipuler les bits (par exemple effacer, mettre à un ou compléter un bit) ou de créer les condition pour les saut
de programme.

Instruction Opérande Description Opération


AND Rd, Rn, N Opération logique ET entre deux valeurs 32 bits Rd=Rn & N
ORR Rd, Rn, N Opération logique OU entre deux valeurs 32 bits Rd=Rn | N
EOR Rd, Rn, N Opération logique OU exclusive entre deux valeurs Rd=Rn ^ N
32 bits
BIC Rd, Rn, N Effacer le bit (AND NOT) Rd=Rn & ~N
Tableau 29: Les instructions logiques

La syntaxe de instructions logiques est la suivante :

<Instruction>{<cond>}{S} Rd, Rn, N

L’opérande N peut être une valeur direct (constante avec #), la contenu d’un registre ou le contenu d’un registre
décalé. Contrairement aux nombreux autres processeurs, les opérations logiques n’influencent pas par défaut les
drapeaux du registre d’état courant CPSR. Si toutefois cela devrait être le cas, il faut ajouter un suffixe S à la fin
du code d’opération.

Exemple :
L’instruction BIC permet d’effacer certains bits dans un mot, sans en influencer les autres. Dans l’exemple
suivant, tous les bits de r2, dont la valeur correspond à « 1 », sont effacés dans le registre r1, et le résultat est
stocké dans r0.

Avant :
r1=0b1111
r2=0b0101

BIC r0, r1, r2

Après :
r0 =0b1010

Exemple :
L’instruction ORR réalise une opération logique OU. Dans l’exemple suivante, cette opération est réalisée entre
les valeurs des registres r1 et r2, et le résultat est stocké dans r0.

Avant :
r0=0x00000000
r1=0x10305070
r2=0x02040608

ORR r0, r1, r2

Après :
r0=0x12345678

4.4.3 Les instructions de décalage et de rotation


Les instructions de décalage et de rotation permettent de réaliser des opérations de déplacement binaire. Les
processeurs ARM ne soutiennent pas directement ce type d’opération. Toutefois, ces dernières peuvent être
réalisée indirectement à l’aide du décalage à barillet.

Version 3.1, juin 2008 Page 80


Informatique 3 Jeu d’instruction du processeur ARM V5

Le jeu d’instruction Thumb possède par contre ses propres instructions de décalage et de rotation. La raison est
que ce jeu d’instruction n’a pas accès au décalage à barillet.

Exemple :
Le contenu du registre r0 doit être déplacé de un bit vers la gauche. Ce qui correspond à une multiplication par
2. L’instruction MOV est la solution la plus simple pour ce problème.

Avant :
r0 = 0x00004321
CPSR = nzCvqIFt_SYS

MOVS r0, r0, LSL #1

Après :
r0 = 0x00008642
CPSR = nzcvqIFt_SYS

n z c v 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 0 0 1 0 0 0 0 1

cpsr r0

r0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 0 0 1 0 0 0 0 1 0 0
n z c v 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Werden gesetzt bei einer


Instruktion mit S-Suffix

4.5 Saut de programme


4.5.1 Généralité
Les sauts de programme peuvent être répartis selon les critères suivants :
a) Saut conditionnel ou inconditionnel
b) Saut absolu ou relatif

Un saut de programme conditionnel n’est exécuté que si certaines conditions (bit d’état courant) sont réalisées.
Par contre, un saut de programme inconditionnel est toujours exécuté.

Les sauts de programme absolus engendrent des sauts à des adresses fixes. Ce type de sauts n’est pas soutenu par
les processeurs ARM. Les sauts de programme relatifs engendrent des sauts relatifs, c'est-à-dire avec un certain
déplacement (offset) par rapport à l’adresse courante. Ce déplacement est calculé automatiquement par
l’assembleur. Les processeurs ARM soutiennent uniquement les sauts relatifs.

Saut absolu (par exemple Intel x86, Motorola 68x mais pas ARM!)

Départ du programme à l’adresse 0x0000 : Le même programme est démarré à l’adresse 0x2000 :

0x0000
0x0000 prog. Start
...
...
JMP 0x6000 0x2000 prog. Start
... ...
... ...
JMP 0x6000
...
0x6000 instruktion 1
0x6000 instruktion x

0x8000 instruktion 1

Version 3.1, juin 2008 Page 81


Informatique 3 Jeu d’instruction du processeur ARM V5

Le programme de gauche, qui est exécuté à partir de l’adresse 0x0000 (Figure de gauche), saute à l’adresse
0x6000 après l’instruction « JMP 0x6000 ». Ce qui est juste. Si ce même programme est exécuté à partir de
l’adresse 0x2000 (Figure de droite), le programme saute toujours à l’adresse 0x6000 après l’instruction
« JMP 0x6000 ». Ce qui est faux.

Æ Les programmes, qui contiennent des sauts absolus, ne peuvent pas être déplacés dans la mémoire.

Saut de programme relatif

Départ du programme à l’adresse 0x0000 : Le même programme est démarré à l’adresse 0x2000 :

0x0000
0x0000 prog. Start
...
...
B label1 Offset 0x2000 prog. Start
... ...
... ...
B label1 Offset
label1: ...
0x6000
0x6000 instruktion x

0x8000 label1:

Le programme, qui est exécuté à partir de l’adresse 0x0000 (Figure de gauche), exécute un saut relatif (Branch)
d’une certaine distance (offset) à l’étiquette label1. Si ce programme est déplacé dans la mémoire (image de
droite), alors il continuera de fonctionner correctement. Car la distance entre l’instruction « B lable1 » et
l’étiquette lable1 reste constante.

Les programmes, qui contiennent des sauts relatifs, peuvent être déplacés dans la mémoire.

4.5.2 Les sauts de programme inconditionnels


Les sauts de programme inconditionnel sont des instructions, qui permettent d’interrompre le déroulement
séquentiel du programme. Certain de ces instructions sont utilisées pour les appelles de sous-routines ou les
changements de mode ARM → Thumb.

La syntaxe du saut de programme inconditionnel est la suivante :

<B | BL> <label>


BX Rm
BLX <label> | Rm

L’étiquette (label) représente, en tant que constante symbolique, l’adresse à laquelle le programme doit sauter.
L’assembleur calcul le déplacement (offset), par rapport au contenu du registre compteur de programme pc.
C’est à dire en tenant compte de l’adresse de l’instruction courante. La destination doit se situer dans une zone
de ± 32 Méga bytes, par rapport à l’instruction courante. Alors que les instruction B et BL nécessitent une
constante symbolique comme adresse de destination ; les instruction BX et BLX peuvent réaliser un saut en se
basant sur le contenu d’un registre. Cela est spécialement utile, lorsque l’adresse de destination est calculée
durant le déroulement du programme ou lue à partir d’un Tableau.

Le Tableau 30 illustre les quatre instructions destinées aux sauts de programme ARM.

Version 3.1, juin 2008 Page 82


Informatique 3 Jeu d’instruction du processeur ARM V5

Instruction Distance de Description Effet


saut (offset)
B ± 32MB Saut de programme général pc = offset (label)
BL ± 32MB Appel de sous-routine. pc = offset (label)
Saut de programme avec sauvegarde de l’adresse lr = Adresse de l’instruction
de retour dans le registre du relieur lr qui suit BL
BX ± 32MB Identique à B, mais possibilité de passage dans le pc = Rm & 0xfffffffe
mode Thumb T = Rm &1
BLX ± 32MB Identique à BL, mais possibilité de passage dans pc = Rm & 0xfffffffe
le mode Thumb. T = Rm &1
lr = Adresse de l’instruction
qui suit BL
Tableau 30 : Les instructions de saut de programme

L’appelle d’une sous routine (sous programme) est réalisé avec l’instruction BL. BL stocke également l’adresse
de l’instruction, qui suit celle du saut, dans le registre de reliage lr (r14). Cette dernière sert d’adresse de
retour depuis la sous-routine.
La distance de saut maximale est limitée aux 24 bits de codage pour l’offset. Ce qui correspond à environ ± 32
Méga bytes.

Au changement dans le mode Thumb, avec une adresse de destination dans le registre Rm, l’adresse de
destination doit être incrémentée (+1). Les processeurs ARM ignorent le bit de poids plus faible, car ils réalisent
le saut selon RM & 0xFFFF’FFFE. Ainsi il n’y a pas de changement de mode, lorsque le registre Rm contient
une adresse paire.
Lorsque l’instruction BLX est utilisée avec une adresse directe, le processeur entre dans le mode Thumb sans que
cette dernière ne doive être incrémentée (+1).

Exemple :
Les sauts de programme peuvent être réalisés soit en avant ou en arrière. Le calcul de l’offset est effectué
automatiquement par l’assembleur. L’exemple suivant illustre des sauts non conditionnels. Le premier saut
franchit les trois opérations d’addition et arrive directement à la première soustraction. Le deuxième saut réalise
un retour en arrière et produit ainsi une boucle infinie.

B ahead
ADD r1,r2,#4
ADD r0,r6,#2
ADD r3,r7,#4

ahead:
SUB r1,r2,#4

back:
ADD r1,r2,#4
SUB r1,r2,#4
ADD r4,r6,r7
B back

Exemple :
Les sous-routines sont appelées normalement avec l’instruction BL. Le retour s’effectue avec l’adresse de retour,
qui a été stockée avec BL dans r14. L’exemple suivant illustre le principe des appelles de sous-routines et le
retour à partir de ces dernières.

...
BL subroutine
ADD r0, r1, r2
...
subroutine:
<Subroutine code >
MOV pc, lr @ Return from subroutine

L’assembleur ARM ne prévoit pas d’instruction spécifique pour le retour à partir des sous-routines. Cette

Version 3.1, juin 2008 Page 83


Informatique 3 Jeu d’instruction du processeur ARM V5

dernières est toujours réalisée soit avec l’instruction « MOV pc, lr », ou avec la lecture de l’adresse de
retour depuis la pile.

4.5.3 Les sauts de programmes conditionnels


Le concept d’exécution conditionnelle des instructions de ARM permet d’exécuter toutes les opérations de façon
conditionnelle. Cella concerne également les sauts de programme. Tous les sauts de programme du Tableau 30
peuvent ainsi être complété avec un suffixe.

La syntaxe pour les sauts de programme conditionnels est la suivante :

<B|BL>{<cond>} label
BX{<cond>} Rm
BLX{<cond>} Rm

L’expression <cond> est le code condition sous forme de suffise selon le Tableau 31. Le reste est identique au
chapitre 4.5.2.

Condition Description Drapeau


EQ Equal Z
NE Not Equal !Z
CS,HS Unsigned higher or same C
CC,LO Unsigned lower !C
MI Minus, Negative N
PL Positive or zero !N
VS Overflow V
VC No overflow !V
HI Unsigned higher C && !Z
LS Unsigned lower or same !C && Z
GE Signed greater or equal (N == V)
LT Signed less than (N != V)
GT Signed greater than !Z && (N == V)
LE Less or equal Z || (N != V)
Tableau 31 : Les codes de condition pour l’exécution conditionnelle des instructions.

Exemple :
Une sous-routine doit calculer la faculté d’un nombre entier positif. Ce dernier est transmis à la sous-routine
avec le registre r0. La sous-routine doit ensuite enchaîner les multiplications et retourner le résultat avec le
registre r0.

start:
MOV r0, #5 @ Example 5!
BL FacSuB @ Compute (r0!)
B start

// Subroutine for the faculty computation


// n! = 1 * n * (n-1) * (n-2) * ... * 3 * 2
// Input r0: Argument n
// Output r0: Resultat n!
// Used register: r1
FacSub:
MOVS r1, r0 @ Counter registre
MOVLE r0, #0 @ If n<=0,then result=0
BLE endFac
MOV r0, #1

Version 3.1, juin 2008 Page 84


Informatique 3 Jeu d’instruction du processeur ARM V5

loop:
MUL r0, r1, r0 @ multiplication n*(n-1)*(n-2)*...*3*2
SUB r1, r1, #1
CMP r1, #1
BGT loop

endFac:
MOV pc,lr @ return to the calling subroutine

4.6 Les autres instructions ARM


Ce chapitre décrit des instructions, qui seront traitées de façon plus détaillées dans les chapitres suivants. Ce qui
comprend les instructions break points et interruption software, ou les instruction qui n’ont pas de rapport
thématiques avec les chapitres précédents.

4.6.1 Les interruptions software SWI


Les interruptions SWI sont des outils, qui sont mis à disposition pour appeler des routines de services. Dans un
mode non privilégié, ces instructions permettent d’appeler les fonctions du système d’exploitation, qui doivent
être exécuté dans un mode privilégié. Le Tableau 32 traite plus de détail sur le déroulement des interruptions
software. Les exceptions et les interruptions sont traitées plus en détail dans le chapitre 7.

L’instruction SWI engendre un saut de programme à l’adresse 0x00000008, dans le Tableau des vecteurs
d’interruption.

la syntaxe de l’instruction SWI est la suivante :

SWI{<cond>} SWI_Number

Le numéro SWI est une valeur entre 0x000000 et 0xFFFFFF. Ce dernier ne concerne pas le processeur mais
le traiteur des interruptions software SWI.

Instruction Opérande Description Effet


SWI Numéro Interruption lr_SVC = Adresse de l’instruction, qui suit SWI
SWI software SPSR_SVC = CPSR
pc = vector base + 0x8
CPSR_mode = SVC
CPSR_I = 1 (masquer IRQ)
Tableau 32 : Description du déroulement des interruptions software

Exemple :
Le code suivante illustre génère un SWI avec le numéro 0x123456, qui est utilisé par le débuggeur.

Avant :
CPSR = nzcvqift_USR
pc = 0x00008000
lr = r14= 0x003FFFFF
r0 = 0x12

SWI 0x123456

Après :
CPSR = nzcvqIft_SVC
SPSR = nzcvqift_USR
pc = 0x00000008
lr = r14= 0x0008004
r0 = 0x12

4.6.2 Les points d’arrêt BKPT


L’instruction BKPT génère une exception du type « prefetch data abort », si elle n’est pas traitée par le hardware
du débuggeur. L’opérande <immed16> permet de transmettre une valeur 16 bits à l’instruction BKPT. Le

Version 3.1, juin 2008 Page 85


Informatique 3 Jeu d’instruction du processeur ARM V5

débuggeur peut traiter cette information et identifier le point d’arrêt avec ce numéro.

La syntaxe de l’instruction BKPT est la suivante :

BKPT {<immed16>}

La valeur nulle est utilisé par défaut, en absence de la spécification <immed16>.

4.6.3 Le comptage des zéros CLZ


Cette instruction compte le nombre de bits zéro, qui précèdent dans une valeur binaire.

La syntaxe de l’instruction CLZ est la suivante :

CLZ{<cond>} Rd, Rm

Le registre Rm ne peut pas être le registre du compteur de programme pc. L’instruction CLZ retourne la valeur
32 lorsque Rm = 0.

Exemple :
Le nombre de bits zéro, qui précèdent dans une valeur binaire, indique de combien une valeur peut être décalée
vers la gauche, sans qu’il n’y ait un dépassement de capacité.

Avant :
r0 = 0x12
r1 = 0x1234

CLZ r0, r1

Après :
r0 = 0x13
r1 = 0x1234

Exemple :
La séquence d’instruction suivante normalise la valeur contenue dans le registre r0. Le premier bit, qui est
différent de zéro, se trouvera ainsi dans D31. L’exemple admet que la valeur à normaliser est différente de 0.

Avant :
r0 = 0x8421

CLZ r1, r0 @ Nombre de déplacement vers la gauche pour la normalisation


MOV r0, r0, LSL r1 @ Normalisation, afin que le bit 31 soit mis à un

Après :
r0 = 0x84210000
r1 = 0x10

Version 3.1, juin 2008 Page 86


Informtique 3 Les directives de l’assembleur

5 Les directives de l’assembleur

5.1 Introduction
Les directives de l’assembleur sont des pseudo instructions, qui permettent de gérer l’assemblage du programme.
Contrairement aux instructions réelles, ces dernières ne sont pas traduites en code machine.
Les directives de l’assembleur dépendent de l’assembleur. En générales les fonctionnalités suivantes sont mises à
disposition :
• Contrôle de l’assembleur
• Contrôle du relieur (Sections et leurs adresses de départ)
• Définition des variables et des constantes
• Formatage de fichiers

5.2 Aperçu
Le Tableau suivant fournit un aperçu des directives les plus importantes de l’assembleur :

Champ des noms Champ des Champ des opérateurs Description


instructions
.arm Définition du jeu d’instruction ARM (32-Bit)
.thumb Définition du jeu d’instruction Thumb (16-Bit)
.global Nom de symbole Exporter un symbole
.extern Nom de symbole Importer un symbole
.align Alignement, valeur Alignement de l’adressage de la mémoire
.balign
.p2align
Nom de symbole .ascii, .asciz Chaînes de caractères Définition de chaînes de caractères constantes
Nom de symbole .byte Valeurs Définition de constantes de type byte, demi mot
.2byte, .hword et mot
.4byte, .word
Nom de symbole .space Nombre, valeur Réserver de l’espace mémoire avec initialisation
du bloc en question
.include {chemin} nom de fichier Insérer le contenu d’un fichier
.equ, .set, = Nom de symbole, valeur Attribuer une valeur à un symbole
.org Adresse Attribuer une adresse absolue
.section Nom de symbole Définition de segments de mémoire
{, drapeau}
.text, .data, Les sections standard
.bss
.end Fin du code source
.if Condition Assemblage conditionnel du programme
.ifdef
.ifndef
.else
.macro Nom de symbole Définition d’une macro
{Paramètre}
.rep Nombre Répétition des blocs de code
.irp Paramètre
.endm Fin d’une macro ou d’une structure de contrôle
.endr
.endif

Tableau 33: Les directives de l’assembleur

Version 3.1, juin 2008 Page 87


Informtique 3 Les directives de l’assembleur

5.3 .arm, .thumb


La directive .arm introduit un segment de code, qui est programmé avec le jeu d’instruction ARM. Alors que la
directive .thumb indique un segment de code, programmé avec le jeu d’instruction Thumb. La syntaxe du
mode Thumb est légèrement différente de celle d’ARM. Il ne comprend que les instructions et les registres
Thumb. Les deux directives possèdent respectivement les synonymes suivants : .code32 et .code16.

Exemple :
.arm
... @ 32-Bit ARM Instruction
.thumb
... @ 16-Bit Thumb Instruction

5.4 .global, .extern


Un symbole (sous-routine, variable etc.) peut être rendu publique avec les directives .global et .extern.
Ces symboles peuvent ainsi être utilisés (exportés) dans les autres modules.
La directive .extern est acceptée pour des raisons de compatibilité avec les autres langages de programmation
assembleurs. Cependant elle n’a pas d’effet, car l’assembleur considère tous les symboles comme étant externes.
La directive .extern peut toutefois être utilisée pour la documentation de l’interface du module.

Exemple:

main.s lcd.s

.extern InitDisplay .global InitDisplay


... ...
... ...
...
... InitDisplay:
bl InitDisplay ...
...
mov pc,lr

La sous routine InitDisplay est appelée dans le fichier main.s (le chapitre 6 traite les sous-routines de
façon plus détaillée). La sous-routine InitDisplay est définie et exportée avec la directive .global dans le
fichier lcd.s. L’oubli de la directive .global génère des erreurs de relieur.

Pour des raisons de documentation, la directive .extern permet de montrer que le symbole InitDisplay a
été défini dans un autre module. La directive .extern n’est pas nécessaire pour le relieur (linker).

Contrairement au langage de programmation C, les informations concernant la transmission des paramètres et la


restitution du résultat ne sont pas disponibles en assembleur. En C ces informations sont fournies par la
déclaration de la fonction : extern void func (int). En assembleur c’est le programmeur, qui est
responsable de la programmation correcte du transfert des arguments et de la restitution du résultat des sous
routines.

Exemple :
Un programme minimal en assembleur, qui exécute une boucle infinie, a été défini dans le segment .text. Le
code de démarrage doit effectuer un saut à l’étiquette start, après avoir initialisé le hardware.

Version 3.1, juin 2008 Page 88


Informtique 3 Les directives de l’assembleur

.arm
.global start

.text
start: B start

5.5 .align
La directive .align permet de s’aligner sur une adresse 32 bits (modulo 4). Cette directive insère par
conséquent zéro à trois bytes. Les processeurs ARM exigent que les instructions et les données du type mot
(word) du programme soient déposées à des adresses 32 bits.
Exemple :
0000 AA55 .byte 0xaa, 0x55
0002 0000 .align @ 2 bytes 0x00 vont être inseres a cet endroi
0004 48616C6C .asciz "Hallo"
6F00

La syntaxe suivante est valable pour cette directive :

.align AL {, FB}

L’opérande AL permet de spécifier le déplacement. Ce dernier dépend de la plateforme. Par exemple, la directive
« .align 3 » n’a pas la même signification chez les processeurs ARM et i386. Cette dernière correspond
respectivement à un déplacement de huit et zéro bytes. L’opérande FB permet de définir les bytes de
remplissage.

Exemple :
Le code suivant illustre les effets des directives .align. Dans cet exemple, la directive .align 3 permet de
s’aligner sur la prochaine adresse, qui est un modulo de 23 = 8.

0000 AA .byte 0xaa


0001 FFFFFFFF .align 3, 0xFF @ alignement modulo 2^3=8 et remplissage avec 0xFF
FFFFFF
0008 48616C6C .asciz ″Hello″
6F00
000e 0000

Du fait que la directive .align dépend des plateformes, deux nouvelles directives d’alignement ont été
spécifiées par le standard GNU : balign et .p2align. Ces dernières ne dépendent plus des plateformes.

Exemple :
La directive .align 8 engendre un alignement à la prochaine adresse modulo 28 = 256:

.data
0000 55 .byte 0x55
0001 11111111 .align 8, 0x11
11111111
11111111
11111111
11111111
0100 FF .byte 0xff
0101 00000000

5.5.1 .balign
La directive .balign (byte align) fonctionne comme .align, mis à part que le paramètre d’alignement AL
est toujours défini en byte. Ce dernier décrit la valeur modulo, sur laquelle l’alignement doit avoir lieu. La

Version 3.1, juin 2008 Page 89


Informtique 3 Les directives de l’assembleur

directive .balign 8 engendre, indépendamment de la plateforme, un alignement sur une adresse modulo 8
bytes.

Les directives .balignw et .balignl sont des cas particuliers de .balign. En effet, ces derniers
considèrent le byte de remplissage comme un demi mot (2 bytes) ou un mot (4 bytes).

Exemple :
La directive .balign peut être utilisée de façon universelle. Le paramètre d’alignement doit toujours être
défini en byte et doit être une puissance de 2. Les autres valeurs engendrent un message d’erreur.

.data
0000 FF .byte 0xFF
.balign
0001 FF .byte 0xFF
.balign 2
0002 FF .byte 0xFF
0003 00 .balign 4
0004 FF .byte 0xFF
0005 000000 .balign 8
0008 FF .byte 0xFF

Exemple :
La directive « .balignw 4,0x1234 » exécute un alignement à une adresse modulo 4. Si un déplacement de
2 bytes a lieu, il sera rempli avec la valeur 0x1234. La déposition des bytes dans la mémoire dépend du mode
boutiste du processeur. Les déplacements de un ou trois bytes engendrent des messages d’erreurs.

.data
0000 FFFFFFFF b1: .byte 0xFF, 0xFF, 0xFF, 0xFF
0004 .balignw 4, 0x1234
0004 FFFF b2: .byte 0xFF, 0xFF
0006 3412 .balignw 4, 0x1234

5.5.2 .p2align
La directive .p2align (power of 2 align) fonctionne comme .align, mis à part que le paramètre de
déplacement AL y est défini sous la forme exponentielle. Cette dernière fournit la valeur modulo, sur laquelle il
faut s’aligner. La directive « .p2align 3 » engendre, indépendamment de la plateforme, un alignement sur
une adresse modulo 8 bytes.

Les cas particulier sont ici .p2alignw et .p2alignl. Ces derniers considèrent les bytes de remplissage
respectivement comme des demi mots et des mots.

Exemple :
La directive « .p2align 3 » se réfère toujours sur des adresses, qui sont des multiples de 8. Les espace de
déplacement sont remplis avec des valeurs nulles.

.data
0000 10 b1: .byte 0x10
0001 00000000 .p2align 3
00000
0008 33 b2: .byte 0x33

Exemple :

Les directives « .p2alignw 2, 0x1234 » génèrent des déplacements sur des adresses, qui sont des
multiples de 4. Les espaces de déplacement du type mot sont remplis avec la valeur 0x1234. La suite des bytes
dépend du mode boutiste du processeur. Les déplacements de un ou trois bytes engendrent des messages

Version 3.1, juin 2008 Page 90


Informtique 3 Les directives de l’assembleur

d’erreurs.

.data
0000 FF b1: .byte 0xFF
0001 565656 .p2align 2, 0x56
0004 FFFF b2: .byte 0xFF, 0xFF
0006 3412 .p2alignw 2, 0x1234

5.6 .ascii, .asciz


Les directives .ascii et .asciz permettent d’insérer des chaînes de caractères constantes dans le code.
Plusieurs chaînes de caractères peuvent être définies avec une seule directive. Ces dernières doivent toutefois
être séparées par des virgules. Les valeurs ASCII des différents caractères sont directement déposées dans la
mémoire. La directive .asciz termine automatiquement la chaîne de caractère avec le byte de fin de chaîne
(byte nul).

La syntaxe de .ascii et .asciz est la suivante :


{Label :} <.ascii|.asciz> {,<string>} ...

Exemple :
0000 48616C6C .ascii ″Hello″
6F
0005 57656C74 .asciz "World!"
2100

5.7 .byte
La directive .byte permet d’insérer des constantes et des variables du type byte dans le code. Plusieurs valeurs
séparées par des virgules peuvent être définies. Ces dernières sont déposées dans le même ordre dans la
mémoire.
La syntaxe de .byte est la suivante :

{label:} .byte <byte1> {,<byte2>} . . .

L’étiquette (label) représente le nom de la constante. Cette dernière est utilisée comme adresse symbolique afin
de pouvoir accéder à la constante. Les valeurs négatives sont stockées en complément à deux. Les valeurs hexa
décimales commencent avec 0x ou 0X, les valeurs octales avec un 0 et les valeurs binaires avec 0b ou 0B. Les
valeurs décimales ne commencent avec un chiffre différent de zéro.

Exemple :
0000 416225 .byte 'A', 'b', 37
0003 20D0 .byte 0x20, -0x30
0005 F608 .byte -10, 010
0007 0A .byte 0B1010

5.7.1 .2byte, .hword


Les directives .2byte et .hword permettent d’insérer des constantes et des variables du type demi mot (16
bits) dans le code. Ces directives fonctionnent de la même manière que .byte.

La syntaxe de .2byte et .hword est la suivante :

{label:} <.2byte|.hword> <short1> {, <short2>} ...

Version 3.1, juin 2008 Page 91


Informtique 3 Les directives de l’assembleur

Exemple :
Les directives .2byte et .hword sont des synonymes. Elles déposent les constantes à 16 bits en respectant
l’ordre de leurs énumérations.

.data
0000 1100 h1: .2byte 0x11
0002 33224400 h2: .2byte 0x2233, 0x44
0006 1100 h3: .hword 0x11
0008 33224400 h4: .hword 0x2233, 0x44

5.7.2 .word, .4byte


Les directives .word et .4byte permettent d’insérer des constantes et des variables du type mot (32 bits). Ces
directives fonctionnent de la même manière que .byte et .2byte.

La syntaxe de .word et .4byte est la suivante :

{label:} <.4byte|.word> <word1> {, <word2>} . . .

Exemple :
Les directives .4byte et .word sont des synonymes. Elles déposent les constantes à 32 bits en respectant
l’ordre de leurs énumérations.

.data
0000 11000000 w1: .4byte 0x11
0004 55443322 w2: .4byte 0x22334455, 0x66
66000000
000c 11000000 w3: .word 0x11
0010 55443322 w4: .word 0x22334455, 0x66
66000000

5.8 .space
La directive .space réserve de l’espace mémoire pour un bloc, contenant un certain nombre de bytes. Ce
dernier est normalement utilisé pour le stockage de données.

La syntaxe de .space est la suivante :

{label:} .space <AB> {, <FB>} ...

Le paramètre AB spécifie le nombre de bytes, qui doivent être réservés pour le bloc. Le paramètre en option FB
défini le byte de remplissage, qui sera utilisé pour tout le bloc.

Exemple :
Les blocs de données sont des bytes, qui sont stockés successivement dans la mémoire. Ces derniers peuvent
également être initialisés. Dans les applications embarquées, l’initialisation de cette zone de mémoire est la tâche
du chargeur de démarrage (boot loader).

Version 3.1, juin 2008 Page 92


Informtique 3 Les directives de l’assembleur

.data
00000 00000000 .space 0x10
00000000
00000000
00000000
00010 AAAAAAAA .space 0x10000, 0xAA
AAAAAAAA
AAAAAAAA
AAAAAAAA
AAAAAAAA
10010 00000000 .space 0x1234
00000000
00000000
00000000
00000000

5.9 .include
La directive .include copie du code le contenu du fichier à inclure dans le code source. Cette opération est
effectuée durant le processus d’assemblage du programme. Le fichier à inclure doit se trouver dans le répertoire
courant du projet. C'est-à-dire celui, qui contient les fichiers objets. L’option –I de la ligne de commande permet
de spécifier le chemin d’accès aux fichiers à inclure.

La syntaxe de .include est la suivante :


.include "NomFichier"

Exemple :
.include "pxa270.s"

La ligne .include "pxa270.s" sera remplacée par le contenu du fichier « pxa270 ».

5.10 .equ, .set, =


Les directives .equ, .set et = attribuent une valeur à un symbole. Ces directives sont des synonymes et
fonctionnent toutes de la même manière.

Exemple :
1 .text
2 .equ newline, 0xa
3 .set bitmask, 0b10010111
4 TAB = 011
5
6 0000 0A00A0E3 MOV r0, #newline
7 0004 9710A0E3 MOV r1, #bitmask
8 0008 011000E0 and r1, r0, r1
9 000c 0930A0E3 MOV r3, #TAB
10
11 .equ newline, 100 /* Redefinion of newlin */
12
13 0010 6400A0E3 MOV r0, #newline

Les symboles newline, bitmask et TAB sont dotés de valeurs numériques. La programmation peut être
effectuée avec ces symboles au lieu de leurs valeurs numériques. Cette définition centrale augment la lisibilité du
code et facilite son entretient. La définition directe de valeurs numérique dans le code devrait constituer une
exception.

Version 3.1, juin 2008 Page 93


Informtique 3 Les directives de l’assembleur

5.11 .org
La directive .org défini une adresse absolue, à partir de laquelle les instructions (ou les données) du programme
doivent être déposées dans la mémoire. La définition des segments avec .org constitue une exception, avec les
processeurs ARM. Cela provient du fait que les sauts de programme y sont toujours réalisés de façon relative.

Exemple :
.org 0xa0000800
mysub: ...
MOV pc,lr

Dans l’exemple de ci-dessus l’adresse de départ de la sous-routine « mysub » est fixée à 0xa0000800. En
règle générale, l’utilisation de la directive .section est beaucoup plus élégante.

5.12 .section
L’espace mémoire des instructions et des données du programme peut être partagé en plusieurs blocs (segments
ou sections). On distingue fondamentalement le segment du code et celui des données. Le segment du code
(.text) contient les instructions du programme, qui sont stockées en générale dans une ROM. Le segment des
données est composé de variables, de la pile (stack) et d’autres types de grandeurs. On distingue ici l’espace
mémoire à initialiser (.data) et celui à ne pas initialiser (.bss). Le gestionnaire d’amorçage (boot loader) est
responsable de l’initialisation de l’espace .data. Dans les programmes C, ce gestionnaire est appelé par le code
de démarrage du module crt0.s.

Plusieurs segments peuvent être regroupés dans une classe. Les classes les plus importantes sont les suivantes :
.text, .data et .bss. Dans ces classes il est possible de définir des sous classes (segments).

Des nouveaux segments ne doivent en générales pas être définis dans des petits programmes. En générale les
classes prédéfinies, .text, .data et .bss, sont suffisent pour ces derniers. La définition des nouveaux
segments est en revanche nécessaire avec les programmes plus complexes, qui utilisent des modules étrangers.

La directive .section permet de définir des nouveaux segments, ou de modifier ceux qui existent déjà. Toutes
les instructions, qui suivent la directive .section, sont affectées à ce dernier. Contrairement à .org,
l’attribution de l’adresse de départ au segment n’est pas absolue. Cette dernière est réalisée par le processus de
reliage (linker).

Dans l’environnement de développement CARME, l’attribution des adresses absolues aux segments .section
s’effectue avec le script de reliage « ldscript_ram ».

La syntaxe de .section est la suivante :

.section <NomSection> {,"flags"}

Le symbole <NomSection> permet de définir un nouveau segment. Le drapeau "flag" permet de spécifier
les droits d’accès sur le segment. Le Tableau 34 contient les différents drapeaux et leur signification. Les droits
d’accès des classes de bases restent valables en absence de spécification.

Flag Signification
A Segment pour l’allocation de mémoire
W Segment en écriture
X Segment contenant du code exécutable
Tableau 34 : Droit d’accès des segments

Version 3.1, juin 2008 Page 94


Informtique 3 Les directives de l’assembleur

Nom de segment (Section) Segment de base Contenu


.text .text Code du programme
.data .data Variables initialisées
.bss .bss Variables non initialisées
.startup .text Code de démarrage
.rodata, .rodata* .text Données en lecture (strings, constants)
.glue_7, .glue_7t .text (ev. .data) Code d’interface ARM - Thumb

Tableau 35 : Nom de segment prédéfini

Les changements de segment, qui ne sont pas en rapport avec les segments de base, doivent être défini avec la
directive .section. Cette dernière peut être omis avec les classes de base :

.text
.data
.bss
.section .subroutines, "x"
.section .text @ Synonyme to .text
.section .startup
.section MySection, "w"

Exemple :

Lorsque des nouvelles sections sont nécessaires, il faut les définir dans le module assembleur. Dans l’exemple
suivant, deux sous-routines sont définies dans le segment « subroutines » :

.text
start:
BL mysub1
BL mysub2
B start

.section .subroutines
mysub1: MOV pc,lr

.data
b1: .byte 0x22,0x33
msg: .asciz ″Hello″

.section .subroutines
mysub2: MOV pc,lr

L’affectation du segment subroutines aux classes de base (.text, .data ou .bss) est spécifiée dans le
script du relieur « ldscript_ram ». Ce dernier devrait être affecté logiquement à la classe de base .text.

Dans le manuscrit de reliage de la Figure 70, les segments de l’exemple de ci-dessus sont insérés dans les parties
prédéfinies. Il est ainsi possible de spécifier l’ordre, avec lequel ces segments doivent être stockés dans la
mémoire. Il est évident que les modifications du plan de reliage (linkmap) doivent être effectuées avec la plus
grande précaution et en bonne connaissance des choses. Les éventuelles erreurs peuvent provoquer des chutes de
systèmes.

Version 3.1, juin 2008 Page 95


Informtique 3 Les directives de l’assembleur

/* identify the Entry Point ***************************************************/

ENTRY(_startup)

/* specify the colibri memory areas *******************************************/

MEMORY
{
flash : ORIGIN = 0x00000000, LENGTH = 0x02000000 /* 32MB FLASH */
ram : ORIGIN = 0xA0000000, LENGTH = 0x02000000 /* 64MB RAM */
}

/* specify sections ***********************************************************/


SECTIONS
{
/* startup code */
.text :
{
. = ALIGN(4); /* advance location counter to the next 32bit boundary*/
*(.startup)
*(.glue_7)
*(.glue_7t)
} >ram

/* collect all sections that should go into ram after startup */


/* User defined .subroutines section */
.text :
{
. = ALIGN(4); /* advance location counter to the next 32bit boundary*/
*(.text) /* all .text sections (executable code) */
*(.subroutines) /* all .subroutines sections (user defined sec.) */
_etext = .; /* define a symbol _etext after the last code byte */
} >ram

/* collect all sections that should go into ram after startup */


.text :
{
. = ALIGN(4); /* advance location counter to the next 32bit boundary*/
*(.text) /* all .text sections (executable code) */
*(.rodata) /* all .rodata sections (constants, strings, etc.) */
*(.rodata*) /* all .rodata* sections (constants, strings, etc.) */
_etext = .; /* define a symbol _etext after the last code byte */
} >ram

Figure 70: Extrait du manuscrit de reliage pour l’exemple de ci-dessus. Les attributions propres à l’exemple on
été mises en évidence avec des caractères gras.

Les adresses absolues, avec lesquelles les différents objets ont été stockés dans la mémoire, peuvent être
consultées dans le plan de mémoire. Pour cela il faut activer dans les options du relieur sous
« Miscellaneous » les flags « -Wl,-Map=Filename » (voir
Figure 71).

Version 3.1, juin 2008 Page 96


Informtique 3 Les directives de l’assembleur

Figure 71: Menu de l’environnement de développement, qui permet d’activer la génération d’un plan de
mémoire (linkmap) pour l’exemple de ci dessus.

Memory Configuration

Name Origin Length Attributes


flash 0x00000000 0x02000000
ram 0xa0000000 0x02000000
*default* 0x00000000 0xffffffff

Linker script and memory map

LOAD startup/crt0.o
LOAD startup/BSP_STARTUP.o
LOAD AsmSectionAnweisung.o
LOAD D:\Programme/CarmeIDE/carme/lib\libBSP.a
START GROUP
LOAD D:/Programme/CarmeIDE/yagarto//lib/gcc/arm-elf/4.1.1\libgcc.a
LOAD d:/programme/carmeide/yagarto/bin/../lib/gcc/arm-elf/4.1.1/../../../../arm-elf/lib\libc.
END GROUP

.text 0xa0000000 0x8b8


0xa0000000 . = ALIGN (0x4)
*(.startup)
.startup 0xa0000000 0xc0 startup/crt0.o
0xa0000000 _startup
.startup 0xa00000c0 0x4 AsmSectionAnweisung.o
*(.glue_7)
.glue_7 0xa00000c4 0x0 startup/crt0.o
.glue_7 0xa00000c4 0x0 startup/BSP_STARTUP.o
.glue_7 0xa00000c4 0x0 AsmSectionAnweisung.o
*(.glue_7t)
.glue_7t 0xa00000c4 0x0 startup/crt0.o
.glue_7t 0xa00000c4 0x0 startup/BSP_STARTUP.o
.glue_7t 0xa00000c4 0x0 AsmSectionAnweisung.o
0xa00000c4 . = ALIGN (0x4)

Version 3.1, juin 2008 Page 97


Informtique 3 Les directives de l’assembleur

*(.text)
.text 0xa00000c4 0x0 startup/crt0.o
.text 0xa00000c4 0x7e4 startup/BSP_STARTUP.o
0xa0000598 BSP_STARTUP_init
0xa0000194 UNDEF_Routine
0xa00001a8 DA_Routine
0xa0000180 SWI_Routine
0xa0000834 _sbrk_r
0xa0000214 pxa27x_set_core_freq
0xa0000308 pxa27x_get_freq
0xa0000120 FIQ_Routine
0xa00003d0 InitMemoryController
0xa00001bc PA_Routine
0xa00000c4 IRQ_Routine
.text 0xa00008a8 0xc AsmSectionAnweisung.o
0xa00008a8 start
*(.subroutines)
.subroutines 0xa00008b4 0x4 AsmSectionAnweisung.o
0xa00008b8 _etext = .
0xa00008b8 . = ALIGN (0x4)
*(.text)

Figure 72 : Extrait du plan de reliage (linkmap) pour l’exemple de ci-dessus

5.13 .end
La directive .end indique la fin du code source. Toutes les instructions, qui suivent .end, sont ignorées par
l’assembleur. La directive .end est facultative avec l’assembleur ARM_GNU.

Exemple :
mysub: ...
MOV pc, lr @ dernière instruction

.end @ les instructions suivantes seront ignorées par l’assembleur

5.14 Les opérations assembleur


De nombreux opérateurs sont mis à disposition pour exécuter des calculs à l’intérieur des opérandes. Ces
derniers sont essentiellement utilisés pour le calcul des offsets et des adresses de stockage, comme par exemple
pour les accès Tableaux. Les opérandes de ces opérateurs doivent posséder des valeurs, qui sont fixes durant le
processus d’assemblage. Par conséquent, ces derniers doivent être des constantes.

L’assembleur GCC connaît deux opérateurs signés, qui sont équivalent à ceux de C.

Opérateur Descriptions
- Inversion arithmétique (complément à 2)
~ Inversion binaire (complément à 2)
Tableau 36: Les opérateurs signés de l’assembleur

Les opérateurs arithmétiques et logiques sont décrits dans le Tableau 37. La priorité de ces opérateurs est
identique à celle des opérateurs ANSI-C.

Version 3.1, juin 2008 Page 98


Informtique 3 Les directives de l’assembleur

Opérateur Priorité Description


/ 1 Division (entier)
* 1 Multiplication
% 1 Reste de la division (Modulo)
<< 1 Décalage vers la gauche
>> 1 Décalage vers la gauche
| 2 OU binaire
^ 2 OU Exclusif binaire
& 2 ET binaire
! 2 NON binaire
+ 3 Addition
- 3 Soustraction
== 3 Egalité
<> 3 Inégalité
< 3 Plus petit que
> 3 Plus grand que
<= 3 Plus petit que ou égalité
>= 3 Plus grand que ou égalité
&& 4 ET logique
|| 5 OU logique
Tableau 37 : Les opérateurs assembleur

Le résultat d’une opération de comparaison est toujours une valeur numérique. La valeur -1 représente ainsi vrai
et celle 0 faux. Toutes les opérations de comparaisons permettent de comparer des valeurs non signées.

Les opérations logiques livrent une valeurs 1 correspond à vrai et celle 0 à faux.
Les calculs arithmétiques ne sont pas possibles si les opérandes se situent dans des sections différentes.

5.15 Les structures de contrôle en assembleur


Les structures de contrôle en assembleurs sont destinées au processus d’assemblage. Il est ainsi possible de
générer des versions différentes du code en fonction de conditions prédéterminées. Par exemple du code
supplémentaire peut être inséré dans le programme afin de pouvoir le tester. Ce code, qui n’est plus nécessaire
dans la version finale du programme, peut ainsi être facilement omis.

5.15.1 L’assemblage conditionnel avec .if


La directive .if permet d’assembler de façon conditionnelle le bloque de code, qui suit cette dernière jusqu’aux
directives .endif ou .else. Le code n’est ainsi assemblé, que si la condition se réalise.

La syntaxe de .if est la suivante :

.if <ExpressionLogique>
...
{.else}
.endif

Lorsque la condition de l’expression « ExpressionLogique» est vrai, le bloque .if sera assemblé. Si non
c’est le bloque .else, qui sera assemblé.

Exemple :

La macro suivante permet de décaler a, soit vers la gauche ou vers la droite, en fonction du signe de b.

Version 3.1, juin 2008 Page 99


Informtique 3 Les directives de l’assembleur

.macro SHIFTLEFT a, B
.if \b < 0
MOV \a, \a, ASR #-\b
.else
MOV \a, \a, LSL #\b
.endif
.endm

5.15.2 L’assemblage conditionnel avec .ifdef


La directive .ifdef ne permet d’assembler un bloc de code que si son symbole existe. Par conséquent, ce
dernier doit être défini auparavant en tant qu’étiquette (label), avec les directives .set, .equ ou =.

La syntaxe de .ifdef est la suivante :

.ifdef <Symbole>
...
{.else}

.endif

Exemple :

Du code supplémentaire peut être inséré dans un programme, afin de pouvoir le tester. Dans l’exemple suivant,
le point d’arrêt n’est exécuté que si le symbole DEBUG a été défini auparavant.

.set DEBUG, 1

start:
LDR r0, =0x80
.ifdef DEBUG
BKPT
.endif
LDR r1, =0x80

5.15.3 L’assemblage conditionnel avec .ifndef


La directive .ifndef ne permet d’assembler un bloc de code que si son symbole n’existe pas. Le principe de
fonctionnement est identique à celui de .ifdef

La syntaxe .ifndef est la suivante :

.ifndef <Symbole>
...
{.else}

.endif

5.16 La définition de macro avec .macro


La directive .macro permet de définir un symbole pour une certaine quantité de texte. Cette création de texte
peut également être paramétrée. La directive macro n’agit qu’au niveau substitution de texte. Toutes les
définitions de macro doivent se terminer avec la directive .endm.

La syntaxe de .macro est la suivante :

.macro <Nom> {<arg1>} {, <arg2>} {, <arg3>} ... {, <argN>}


{BlocCode}
.endm

Le nom doit remplir les critères, qui régissent les noms des symboles. La convention veut que l’on définisse les

Version 3.1, juin 2008 Page 100


Informtique 3 Les directives de l’assembleur

noms de macro avec des majuscules. Les arguments représentent formellement les paramètres, comme pour une
fonction C. L’accès à ces paramètres doit s’effectuer dans la macro avec un caractère back slash ‘\’. Une
instruction macro peut être quittée avec la directive .exitm. Cela est toutefois en désaccord avec la
programmation structurée, mais peut dans certain cas simplifier le codage de la macro.

Exemple :
.exitm permet de définir une macro sans la directive .else.

Avant:
r0 = 0x80
r1 = 0x80

.macro SHIFTLEFT a, b
.if \b < 0
MOV \a, \a, ASR #-\b
.exitm
.endif
MOV \a, \a, LSL #\b
.endm

SHIFTLEFT r0, 2
SHIFTLEFT r1, -2

Après:
r0 = 0x200
r1 = 0x20

Exemple :

La macro ADR est une macro prédéfinie pour charger l’adresse des objets. Cette dernière exécute
automatiquement le calcul de l’offset par rapport au registre du compteur de programme pc. La macro peut être
utilisée comme une instruction du processeur.

La syntaxe de ADR est la suivante:

ADR Rd, <Label>

Exemple :
Le chargement de l’adresse de base d’un Tableau peut être effectué très simplement avec la macro :

.text
...
ADR r0,Tab
...

.data
Tab: .word 0, 1, 2, 3, 4

5.17 Les structures de répétitions en assembleur


Les structures de répétition peuvent être considérées comme des macros, parce que ces derniers génèrent
également du texte. Les structures de répétitions permettent d’insérer un bloc de code plusieurs fois dans le
programme. Ce bloc peut être composé d’instructions ou de caractères. L’assembleur GNU met à disposition
pour cela les directives suivantes :

• .rept (répétition)
• .irp (répétition indéfinie)

Version 3.1, juin 2008 Page 101


Informtique 3 Les directives de l’assembleur

5.17.1 La répétition avec .rept


La directive .rept permet d’insérer un bloc de code un certain nombre de fois.

La syntaxe de .rept est la suivante :

.rept <Quantite>
{BlocCode}
.endr

Exemple :
Les mots 0x55AA55AA, 0x00000000, 0xAA55AA55, 0x11111111 doivent être insérés 16 fois dans la
mémoire. La directive .rept permet de réaliser cela de façon compacte :

.rept 16
.word 0x55AA55AA
.word 0x00000000
.word 0xAA55AA55
.word 0x11111111
.endr

Le débuggeur permet de voir, comment ces valeurs ont été déposées dans la mémoire :

Figure 73 : La déposition de structure dans la mémoire avec .rept

Exemple :
.rept permet également de générer un Tableau contenant des valeurs pré calculées à l’aide de symbole.
L’exemple suivant montre la construction d’un Tableau du type byte contenant des valeurs allant de 0 à 255.

Version 3.1, juin 2008 Page 102


Informtique 3 Les directives de l’assembleur

.set L1, 0 @ L1 is a local symbole with a start value


.rept 256
.byte L1
.set L1, L1+1
.endr

5.17.2 La répétition paramétrée avec .irp


La directive .irp permet d’exécuter une suite d’instruction avec plusieurs opérandes. Cette directive est en
quelque sorte une version simplifiée d’une macro avec un nombre de paramètres variable. Le premier paramètre
est le symbole de l’opérande. Ensuite suivent un certain nombre de paramètres, qui seront utilisés l’un après
l’autre dans le bloc de code.

La syntaxe de .irp est la suivante :

.irp <Symbole> {, <Valeur>}{, < Valeur >} ...


{BlocCode}
.endr

Les paramètres « Valeur » doivent être des valeurs entières.

Exemple :
La directive .irp permet de répéter un bloc en fonction d’une liste de paramètres. Le code suivant additionne
tous les paramètres au registre r0 à l’aide du registre r1.

.irp param, 1, 2, 3, 4
MOV r1, #\param
ADD r0, r0, r1
.endr

La macro est étendu à l’assemblage du programme :

.irp param, 1, 2, 3, 4
MOV r1, #\param
ADD r0, r0, r1
.endr

MOV r1, #1 @ 0x1


ADD r0, r0, r1
MOV r1, #2 @ 0x2
ADD r0, r0, r1
MOV r1, #3 @ 0x3
ADD r0, r0, r1
MOV r1, #4 @ 0x4
ADD r0, r0, r1

Figure 74 : Extension de la macro .irp de l’exemple de ci-dessus

Version 3.1, juin 2008 Page 103


Informtique 3 Les sous routines

6 Les sous routines

6.1 Introduction
Les sous routines sont des sous programme en assembleur. Ils correspondent, par conséquent, aux fonctions ou
aux procédures des langages de programmation évolués.

Une sous routine possède les propriétés suivantes :


• Une sous routine est une séquence d’instructions, avec une fonctionnalité et une interface (paramètres).
• Une sous routine est une boîte noire pour la fonction appelante, qui doit respecter scrupuleusement l’interface
(Information Hiding).
• Les sous routines peuvent être appelées plusieurs fois.

Les sous routines possèdent les avantages suivants :


• Modularité : Une application peut être divisée en plusieurs sous routines. Ce qui augmente sa lisibilité et
facilite son entretient.
• Travail d’équipe : La programmation peut être effectuée par plusieurs personnes.
• Réduction de la taille du programme : Une séquence de codes, qui est exécutée plusieurs fois, n’est stockée
qu’une seule fois dans la mémoire.
• Augmentation de la qualité : Les sous routines permettent de mieux tester et documenter le programme.
• Reprise : Les sous routines peuvent être également utilisées dans des autres projets. Ce qui réduit l’effort de
programmation.

Dans les langages de programmation évolués, le compilateur gère l’appel des sous programmes (callee) à partir
des programmes appelants (caller). Cela n’est malheureusement pas le cas dans les langages de programmation
en assembleur : ici le programmeur est l’unique responsable du déroulement de cet appel. Typiquement, les
problèmes suivants doivent être considérés par ce dernier :
• Appel de la sous routine et retour depuis cette dernière
• Echange de données entre la fonction appelante et la sous routine (transfert des paramètres)
• Les variables locales

6.2 Appel et retour de sous routine


6.2.1 Appel de sous routine
=
= Programme principal Sous routine 1

subr1:

bsr subr1 1. instruction


instruction suivante instruction suivante

n. instruction
retour

Figure 75 : Appel d’une sous routine


Dans l’exemple de la Figure 75, la sous-routine subr1 est appelée à partir du programme principal. A la fin de
l’exécution subr1, le programme retourne dans la routine principale, afin d’y exécuter les instructions

Version 3.1, juin 2008 Page 104


Informtique 3 Les sous routines

suivantes.

Dans l’architecture ARM, les appelles de sous routine sont réalisés avec les instructions « Branch-and-Link »
(BL). Cette instruction initialise le compteur de programme (PC) avec l’adresse de départ de la sous routine et
stocke simultanément l’adresse de retour (l’adresse de l’instruction qui suit l’appel de la sous routine dans le
programme appelant) dans le registre de reliage (lr).

ProgrammePrincipale:
BL subr1 @ branch to subr1 and save return address in "lr" (r14)
... @ next instruction

subr1: ... @ start subroutine


MOV pc, lr @ return

L’instruction « MOV pc, lr » est mise à disposition pour le retour depuis la sous routine. Le contenu du
registre de reliage (l’adresse de retour) est ainsi copié dans le compteur de programme. Cette opération peut
également être définie de la manière suivante : « MOV r15, r14 ».

La sous routine ne devrait pas modifier le contenu du registre de reliage, car ce dernier contient l’adresse de
retour. En particulier, la sous routine ne devrait pas appeler d’autre sous routine, sans sauver préalablement le
contenu du registre de reliage.

6.2.2 Appel emboîté de sous routine, pile


Une sous routine peut à son tour appeler une autre sous routine. Cet appel est illustré à l’aide de l’exemple
suivant. Le programme principal appelle la sous routine « subr1 », qui appelle une seconde sous routine
« subr2 ».

=
= Programme principal Sous routine 1 Sous routine 2

subr1 subr2

bsr subr1 1. instruction 1. Instruction


i t
Instruction bsr subr2
suivante
Instruction
suivante

n. instruction n. Instruction
i t
retour retour

Figure 76: Appel emboîté de sous routine

Une sous routine peut s’appeler elle-même, générant ainsi un code récursif. Avec les codes récursifs, il faut faire
attention à la condition d’arrêt. Si non, la pile (stack) pourrait déborder.

Les adresses de retour doivent être systématiquement déposées sur la pile (stack), avec les appels emboîtés de
sous routines. Pour cela il faut :
a) Définir le domaine de la pile avec un le plan de mémoire
b) Initialiser de la pile

La pile est une structure de donnée dynamique, qui fonctionne selon le principe « Last In, First Out ». Les
opérations suivantes sont mises à disposition pour gérer cette dernière :
• Initialisation
• Push (poser un élément sur la pile)

Version 3.1, juin 2008 Page 105


Informtique 3 Les sous routines

• Pop (chercher le dernier élément de la pile)

Un nouvel élément est posé sur la pile avec l’opération « push ». L’élément, qui a été déposé en dernier sur la
pile, peut être recherché avec l’opération « pop ». Ces opérations modifient la taille de la pile.

Début de la pile
1. Elément

2. Elément

3. Elément
Pointeur de pile

push pop

Figure 77 : La pile (stack)

Le pointeur de pile (stack pointer) adresse la fin de la pile, c. à d. l’endroit où la prochaine opération aura lieu.
Le registre r13 sert de pointeur de pile dans les processeurs ARM. Il est également possible de définir « sp » au
lieu de r13.

Les piles peuvent être implémenté de différentes manières :


• La pile peut croître « vers le bas » (descending). Dans ce cas les données sont déposées sur la pile en
décrémentant le pointeur de la pile. La pile peut égalent croître « vers le haut » (ascending). Dans ce cas les
données sont déposées sur la pile en incrémentant le pointeur de pile.
• Le pointeur de pile peut adresser soit la dernière case utilisée, c'est-à-dire l’endroit où le dernier élément a été
déposé sur la pile (« full )»); ou la prochaine case libre, c'est-à-dire l’endroit où le prochain élément peut être
déposé sur la pile (« empty )»).

Par conséquent, il est important que la même version de la pile soit utilisée par le compilateur et le programmeur
en assembleur. Le standard d’appel de procédure ARM (ARM Procedure Call Standard, APCS, voir chapitre
6.5) spécifie pour la pile le mode de fonctionnement « full descending ». Les opérations push sont alors
réalisées avec les instructions STR (sauvegarder uniquement du contenu du registre de reliage) et STMFD ("store
multiple full descending", afin de pouvoir sauver plusieurs registres simultanément). Les opérations pop peuvent
être réalisés soit avec les instructions LDR (recherche uniquement du contenu du registre de reliage) et
LDMFD ("load multiple full descending", afin de rechercher le contenu de plusieurs registre à partir de la pile).

L’instruction STMDB ("store multiple decrement before") peut être également utilisée au lieu de STMFD. Car les
deux instructions sont équivalentes. Pour les même raisons, l’instruction LDMFD peut être remplacée par
LDMIA ("load multiple increment after").

Le code du programme principal et de la sous-routine subr1 de la Figure 76 devient ainsi :

Hauptprogramm:
BL subr1 @ branch to subr1, save return address in "lr" (r14)
… @ next instruction

subr1:
STR lr, [sp, #-4]! @ push lr on the stack
… @ code subroutine 1
BL subr2 @ call subroutine 2
LDR pc, [sp], #4 @ return, pop return adress from stack to pc and increment sp

L’instruction STR décrémente d’abord le pointeur de pile de 4 bytes (la pile croît vers le bas). L’adresse de
retour du registre lr est ensuite déposée sur la pile.

Version 3.1, juin 2008 Page 106


Informtique 3 Les sous routines

Point de départ de l’exemple: Opérations de pile au sein de subr1:


PC = 0x2000, 0x3200 lr auf
adresse de la sous routine 0x1000, 0x00002004 2 Stack
0x31FC
SP = 0x3200 1
sp-4
Adresse Code
0x2000 BL subr1
0x2004 Next instruction
...
subr1:
0x1000 STR lr, [sp, #-4]!
...

Figure 78: Déposition de l’adresse de retour sur la pile

L’opération contraire est réalisée à la fin de la sous routine : L’adresse de retour est d’abord transférée depuis la
pile dans le registre compteur de programme pc. Le pointeur de pile est en suite corrigé de 4 bytes vers le haut.
Le programme retourne finalement dans la routine appelante. C'est-à-dire, qu’il exécute l’instruction qui suit
l’appel de la sous routine. Cette dernière se situe dans l’exemple de ci-dessus à l’adresse 0x2004.

L’initialisation de la pile exige d’une part la définition du domaine d’adressage, et d’autre part l’initialisation du
pointeur de pile. L’extrait de code suivant montre comment cela est réalisé :

Définition:
.set SVC_STACK_SIZE, 0x00000200 @ stack size for supervisor mode
.set MODE_SVC, 0x13 @ supervisor mode

Code de démarrage :
LDR r0, =_stack_top_address @ copy start address of stack into r0

MSR CPSR_c, #MODE_SVC @ switch to supervisor mode


MOV sp, r0 @ initialize supervisor stack pointer
SUB r0, r0, # SVC_STACK_SIZE @ start address next stack

Remarque: Les processeurs ARM sont capables de fonctionner dans différents modes (voir chapitre 2). Chaque
mode possède sa propre pile (stack) avec son propre pointeur de pile. Le segment de code de ci-dessus initialise
par exemple la pile du mode superviseur. Les piles des autres modes (fiq, irq etc.) doivent être initialisés de la
même manière. Vous trouverez le code de démarrage (startup code), qui initialise toutes le piles, dans le fichier
« crt0.s ».

Les instructions pour les appelles et les retours de sous routines sont fournies dans le Tableau suivant :

Instruction Syntaxe Opération


Branch-and-Link BL subr_name lr Å Adresse de retour
pc Å pc + distance de saut
push simple STR lr, [sp, #-4]! sp Å sp – 4
Stack Å Adresse de retour
push multiple STMFD sp!, {r0-r2, lr} sp Å sp – n
Variante: STMDB Stack Å Adresse de retour + registre de travail
pop simple LDR pc, [sp], #4 pc Å Adresse de retour
+ Adresse de retour sp Å sp + 4
return
pop multiple LDMFD sp!, {r0-r2, pc} registre de travail Å Stack
+ Adresse de retour Variante: LDMIA sp Å sp + n
return
Tableau 38 : Opération de pile pour les appelles et les retours de sous routines.

Version 3.1, juin 2008 Page 107


Informtique 3 Les sous routines

La pile de l’exemple de la Figure 76 contient les valeurs suivantes :

sp return return
0x3200 Adr 1 Adr 1

sp return
0x31FC Adr 2

sp
0x31F8
Stack a) b) c)

Figure 79 : Déposition des adresses de retour sur la pile


a) Contenu de la pile, lorsque le programme se trouve dans la routine principale
b) Contenu de la pile, lorsque le programme se trouve dans « subr1 »
c) Contenu de la pile, lorsque le programme se trouve dans « subr2 »

6.3 La sauvegarde du contenu des registres


Considérons le code suivant, qui appelle la sous routine « subr3 » 10 fois à partir d’une boucle.

Programme principale :
start: MOV r4, #0 @ initialize loop variable r4
loop: BL subr3 @ branch to subroutine
ADD r4, r4, #1 @ increment loop variable
CMP r4, #10 @ check if 10 loops done
BNE loop @ no Æ branch to label loop
...

Sous routine 3 :
subr3: STR lr, [sp, #-4]! @ push lr on the stack
...
MOV r4, #0 @ modify r4
...
LDR pc, [sp], #4 @ return

Le problème de cette séquence de code est que le contenu du registre r4, qui est utilisé dans le programme
principale pour le stockage de la variable de compteur, est modifié dans la sous routine subr3 !

Dans ce cas la règle est le principe des contributions : Les contenus des registres, qui sont modifiés par la sous-
routine, doivent être sauvés au début et restitués à la fin de cette dernière (exception voir chapitre 6.5). Les
instructions du Tableau 38 sont mises à dispositions pour ces opérations. Par conséquent, dans l‘exemple de ci-
dessus, la sous routine subr3 doit également sauvegarder le contenu du registre r4.

La sous routine subr3 doit être modifiée de la manière suivante :


subr3: STMFD sp!, {r4, lr} @ push registers to stack
...
MOV r4, #0 @ modify r4
...
LDMFD sp!, {r4, pc} @ pop registers from stack

Remarque : L’instruction LDMFD copie directement l’adresse de retour dans le registre pc.

Version 3.1, juin 2008 Page 108


Informtique 3 Les sous routines

6.4 Le transfert des paramètres


Le transfert de paramètres entre le programme appelant et les sous routines peut être effectué de 2 manières :
1. Transfert de paramètres à l’aide de registres
2. Transfert de paramètres à l’aide de la pile (stack)

Les fonctions C et les sous routines en assembleur peuvent posséder plusieurs paramètres. Il est donc important
que le compilateur C et le programmeur en assembleur respectent les mêmes directives. Le standard d’appelle de
procédure ARM (ARM Procedure Call Standard, APCS) fixe les règles de transmission des paramètres pour les
processeurs ARM (voir chapitre 6.5) :
Les paramètres sont gérés à l’aide d’une liste. Les 4 premiers paramètres sont transmis avec les registres r0
à r3. Les autres paramètres sont transmis, dans un ordre inversé, à l’aide de la pile.

6.4.1 Le transfert de paramètres à l’aide de registre


Il existe fondamentalement deux types de transfert de paramètres :

Call by Value:
Une copie de la valeur originale est transmise en tant que paramètre à l’aide des registres (r0 à r3). Dans ce cas
la sous routine ne pas accéder à la variable originale.

Exemple: programme principale :


ADR r0, variable @ r0 points to address of variable
LDR r0, [r0] @ copy value of variable into r0
BL mySubr @ call subroutine, parameter is passed in r0

Call by Reference:
L’adresse de la variable est transmise en tant que paramètre à l’aide des registres (r0 à r3). Dans ce cas la sous-
routine peut accéder à la variable originale.

Exemple: programme principale :


ADR r0, variable @ r0 points to address of variable
BL mySubr @ call subroutine, parameter is passed in r0

Exemple :
Considérons comme exemple une sous routine « sum », qui possèdent 3 paramètres. Cette dernière peut être
définie da la manière suivante en C :
int op1 = 2;
int op2 = 5;
int res;

void sum (int v1, int v2, int* res) {


*res = v1 + v2;
}

void main (void) {


sum (op1, op2, &res);
}

Version 3.1, juin 2008 Page 109


Informtique 3 Les sous routines

Le programme appelant peut être défini en assembleur de la manière suivante :


op1: .word 2 @ 1st operand
op2: .word 5 @ 2nd operand
res: .word 0 @ result

main:
ADR r0, op1 @ copy address op1 into r0
LDR r0, [r0] @ read value op1, 1st parameter r0 by value
ADR r1, op2 @ copy address op2 into r1
LDR r1, [r1] @ read value op2, 2nd parameter r1 by value
ADR r2, res @ read address res, 3rd parameter r2 by reference
BL sum

La sous-routine sum peut être définie en assembleur de la manière suivante :


• Calcul la somme des deux opérandes
• r3 est utilisé pour le stockage de la valeur intermédiaire
sum:
STR lr, [sp, #-4]! @ push lr
ADD r3, r0, r1 @ temp = op1 + op2
STR r3, [r2] @ *res = temp
LDR pc, [sp], #4 @ pop lr, return

Remarque : Le standard APCS n’exige pas de sauver le contenu du registre r3 à l’aide de la pile (voir chapitre
6.5).

6.4.2 Le transfert de paramètres avec la pile


Les 4 premiers paramètres sont transmis avec les registres r0 à r3. Les paramètres suivants sont transmis dans
un ordre inverse à l’aide de la pile.
Considérons comme exemple la sous routine « super_sum », qui possède l’interface C suivant :
int super_sum (int p1, int p2, int p3, int p4, int p5, int p6);
Cette sous routine ne retourne pas le résultat de façon « call by reference », mais à l’aide d’une valeur de
restitution. Cette restitution s’effectue avec le registre r0, selon le standard APCS.

Le code de la sous-routine « super_sum » peut être implémenté de la manière suivante :


• r4 est utilisé pour le stockage temporaire du résultat
• r5 est utilisé comme tampon pour la déposition momentanée des paramètres transmis avec la pile
• r4 et r5 doivent être sauvegardés à l’aide de la pile

super_sum:
STMFD sp!, {r4, r5, lr} @ push r4, r5 and lr
MOV r4, r0 @ temp = p1
ADD r4, r1 @ temp += p2
ADD r4, r2 @ temp += p3
ADD r4, r3 @ temp += p4
LDR r5, [sp, #12] @ buffer = p5
ADD r4, r5 @ temp += p5
LDR r5, [sp, #16] @ buffer = p6
ADD r4, r5 @ temp += p6
MOV r0, r4 @ copy return value to r0
LDMFD sp!, {r4, r5, pc} @ pop r4, r5 and lr, return

Le contenu de la pile pour l’appelle de la sous routine « super_sum » est le suivant :

Version 3.1, juin 2008 Page 110


Informtique 3 Les sous routines

=
= = = = = =
SP = = SK= = SK= =
0x3200 = = léÉê~å = léÉê~å =
= = Ç= = Ç= =
= = = =
= = RK= = RK= NS=
= = léÉê~å = léÉê~å =
= = Ç= = Ç= =
= = = =
= = = = = NO=
SP
= = = = äê= =
0x31F8
= = = = = =
= = = = = =
= = = = êR= U=
= = = = =
= = = = =
= = = = =
= = = = êQ= Q=
= = = = =
= = = = =
= = = = =
= = = = SP = M=
= = = = 0x31EC = =
= = = = = =

Figure 80 : Transfert de paramètres à l’aide de la pile


a) Avant l’appelle de la sous-routine super_sum et la déposition des paramètres sur la pile
b) Après l’appelle de la sous routine, les paramètres 5 et 6 ont été déposé sur la pile
c) Dans la sous routine après l’instruction STMFD (push)

6.5 APCS
Le standard d’appelle de procédure ARM (ARM Procedure Call Standard, APCS) fixe l’utilisation des registres
de la CPU. Cette convention est importante, afin que les compilateurs et les assembleurs puissent utiliser les
mêmes conventions pour la transmission des paramètres, la sauvegarde des registres etc.

Registre Nom APCS Brève description


r0 a1 Argument 1 / valeur de restitution à 32 bits/ registre scratch
r1 a2 Argument 2 / valeur de restitution à 64 bits / registre scratch
r2 a3 Argument 3 / registre scratch
r3 a4 Argument 4 / registre scratch
r4 v1 Variable registre 1
r5 v2 Variable registre 2
r6 v3 Variable registre 3
r7 v4 Variable registre 4
r8 v5 Variable registre 5
r9 Sb / tr / v6 Dépend de la plateforme / Variable registre 6
r10 v7 Variable registre 7
r11 v8 Variable registre 8
r12 Ip Intra-Procedure-call / registre scratch
r13 Sp Pointer de pile (stack pointer)
r14 Lr Registre de reliage (link register)
r15 Pc Compteur de programme (Program-Counter)
Tableau 39 : Attribution de registre selon le standard APCS

Version 3.1, juin 2008 Page 111


Informtique 3 Les sous routines

• Les registres r0 à r3 (a1 à a4) sont utilisés pour transmettre les arguments aux sous routines. Ces dernières
ne doivent pas conserver leur contenu. Par conséquent, ces registres peuvent être utilisés comme registres
scratch (volatiles, utilisables à souhait et qui ne doivent pas être sauvés dans par les sous routine appelée).
Attention : cela veut dire que les fonctions appelantes doivent considérer, que le contenu de ces registres peut
être modifié par l’appelle de la sous routine ! Le registre r0 est utilisé pour le retour d’un résultat à 32 bits.
Les registres r0 et r1 sont utilisés lorsque ce résultat est de 64 bits.
• Les registres r4 à r8 (v1 à v5) et les registres r10 et r11 (v7 et v8) peuvent être utilisés comme registre
de variable (mémoire intermédiaire). Ces registres doivent retrouver leur valeur d’origine à la fin de la sous
routine. Ils doivent par conséquent être sauvés au début de cette dernière (callee-saved), voir chapitre 6.3.
• Le registre r9 dépend de la plateforme. Il peut être utilisé comme registre de base statique (static base, sb)
ou comme registre thread (thread register, tr). Si r9 n’est pas utilisé pour ces tâches, il peut être utilisé
comme registre de variable.
• Le registre r12 (ip, Interlink Pointer) peut être utilisé comme registre scratch entre les routines et les sous
routines.
• Le registre r13 est le pointeur de pile.
• Le registre r14 est le registre de reliage.
• Le registre r15 est le compteur de programme.

6.6 Définition de variable locales


Les variables locales sont souvent utilisés dans les langages de programmation évolués. Exemple en C :

void myFunc (void)


{
unsigned int myArray [10]; // 10 * 4 Byte local variable
...
...
}

Les variables locales sont définies normalement à l’aide des registres r4 à r8, r10 et r11. Lorsque des
variables locales supplémentaires sont nécessaires, il faut stocker ces dernières sur la pile. Dans ce cas une zone
de mémoire, dont la taille correspond au bloc de variables locales, est allouée sur la pile. Un registre de pointeur
de trame (Frame Pointer), qui est normalement le registre r11, est initialisé avec l’adresse de base de ce bloc.

Le code de la sous-routine « myFunc » peut être implémenté de la façon suivante :

myFunc:
STMFD sp!, {r11, lr} @ push r11 and return address, (1)
SUB sp, sp, #40 @ allocate 10 * 4 bytes local variable space, (2)
MOV r11, sp @ r11 points to first local variable, (3)
...
...
ADD sp, sp, #40 @ free local variable space
LDMFD sp!, {r11, pc} @ pop r11 and lr, return

Le stockage des variable locale à l’aide le la pile s’effectue de la manière suivante :

Version 3.1, juin 2008 Page 112


Informtique 3 Les sous routines

SP alt
lr

r11 alt
1
1
lokaler
Variablen-
bereich 3

2 SP neu r11 neu

Figure 81 : Déposition des variables locales sur la pile

La zone de mémoire contenant les variables locales peut être adressée à l’aide du pointeur de trame r11 et d’un
offset positif. Le programmeur est responsable du calcul correct de cet offset, comme ce fut le cas pour le
transfert des paramètres !

Le pointeur de trame adresse la partie inférieure la zone de mémoire contenant les variables locales. Toutefois,
ce pointeur peut être initialisé afin qu’il adresse la partie supérieur de cette zone. L’offset, pour pouvoir accéder
aux variables locales, doit alors être négatifs. Une autre variante est l’utilisation du pointeur de pile au lieu du
pointeur de trame pour adresser ces variables locales.

Lorsque des variables locales sont utilisées simultanément avec une transmission de paramètre avec la pile (voir
chapitre 6.4.2), les paramètres peuvent également être adressés avec le pointeur de trame au lieu du pointeur de
pile. Remarque : certain compilateur C initialise toujours un pointeur de trame, même si la sous routine n’utilise
pas de variables locales alouées sur la pile. Le code est ainsi un peu plus lent mais, par contre, le calcul des
offsets pour l’accès aux paramètres devient beaucoup plus simple.

6.7 Sources d’erreurs


Il faut faire attention aux opérations suivantes concernant l’appel et la terminaison des sous routines :
• Appeler les sous routines avec « BL » et non « B » !
• Terminer les sous routine en copiant l’adresse de retour dans le registre de compteur de programme pc (soit
directement depuis le registre de reliage lr ou depuis la pile)
• Lorsque la sous routine utilise des registres (mis à part les registres scratch), elle doit sauver leur contenu sur
la pile (faire attention à la succession des opérations de sauvetage, c. à d. que le registre qui a été sauvé en
dernier doit être repris en premier). Le nombre des opérations « pop » doit correspondre au nombre des
opérations « push ».
• Définir la pile suffisamment grande, afin que des dépassements de capacité ne puissent pas avoir lieu.
• Erreur de calcul des offsets des paramètres transmis à l’aide de la pile

Les erreurs de gestion de la pile génèrent toujours des chutes de programme, car les adresses de retour ne sont
plus justes !

6.8 Comparaison entre sous routine et macro


Le code de la sous-routine n’est déposé qu’une fois dans la mémoire, même si cette dernière est appelée depuis
plusieurs endroits du programme. Par contre, le code de la macro est déposé à chaque appel de cette dernière
dans la mémoire : Ce qui augment d’une part la taille du programme et empêche d’autre part de définir des
macros récursifs.

Il s’en suit la question : pourquoi utilise-t-on les macros. La réponse est dans le comportement temporel : un
appel de sous routine avec l’instruction « BL » et le retour depuis cette dernière nécessite plus de temps (même si
cela ne concerne que deux instructions). Dans les applications, qui sont très critiques au niveau temps, cette
diminution de la vitesse d’exécution favorise la macro.

Version 3.1, juin 2008 Page 113


Informtique 3 Les sous routines

Dans des applications standards, il faut utiliser en générale des sous routines. Alors que dans les applications, qui
sont critique au niveau temps, il faut utiliser des macros.

Remarque: Un bon design software et des bons algorithmes sont beaucoup plus efficaces pour la performance du
processeur, que le remplacement systématique des sous routines par des macros.

Version 3.1, juin 2008 Page 114


Informtique 3 Les interruptions et les exceptions

7 Les interruptions et les exceptions


Les interruptions sont introduits au cours « d’informatique 2 » dans le cadre de la programmation proche du
hardware en C (firmware). Ce chapitre traite les interruptions et les exceptions (interruptions générées par des
erreurs dans le programme) au niveau de l’assembleur et du hardware.

7.1 Introduction
Les interruptions sont des évènements, qui peuvent survenir pendant l’exécution d’un programme et qui requiert
un traitement par ce dernier. Les interruptions ARM peuvent être partagés en 3 catégories :

1. Les interruptions et les exceptions, qui surviennent durant l’exécution d’une instruction. Ce type
d’interruption ou d’exception apparaît de façon synchrone au déroulement au programme. Cette catégorie
comprend les interruptions et les exceptions suivantes :
− Les interruptions software
− Les instructions non définies (l’instruction à exécuter est inconnue ou destinée à un coprocesseur
indisponible)
− Prefetch Abort (exception générée à cause d’une erreur d’accès mémoire durant sa lecture)
2. Les exceptions, qui apparaissent comme effet secondaire à une instruction. Ce type d’exception apparaît
également de façon synchrone au déroulement au programme. Les exceptions, qui composent cette catégorie,
sont les suivantes :
− Data Abort (exception à cause d’une erreur d’accès mémoire, durant la lecture ou l’écriture d’une donnée)
3. Les interruptions générées de façon externe. Ce type d’interruption apparaît de façon asynchrone au
déroulement du programme. C’est à dire que le programme peut être interrompu à n’importe quel instant. Les
interruptions, qui composent cette catégorie, sont les suivantes :
− Reset (mise sous alimentation, appui de la touche reset ou activation du « watch dog »)
− Les interruptions hardware : Les requêtes d’interruption standard (Interrupt ReQuest et abrégé avec IRQ)
et les requêtes d’interruption rapide (Fast Interrupt Request et abrégé avec FIR).

Lorsque des interruptions ou des exceptions surviennent dans uns système, ce dernier doit appeler des sous
routines pour leur traitement. Dans le cas d’une interruption on parle alors de « routine de
service d’interruption » (Interrupt Service Routine : ISR) et dans le cas d’une exception on parle de « traiteur
d’exception » (Exception Handler).

Le déroulement du programme est identique pour les trois catégories d’interruption : le programme principale est
interrompu et l’exception est traitée par le traiteur d’exception. Une description exacte du déroulement se trouve
aux chapitres 7.6 et 7.7.

Programme principale Traiteur d’exception

Première
instruction
Exception
Instruction
courante

Instruction
suivante
Dernière
instruction

Figure 82 : Fonctionnement du programme à la suite d’une exception

Version 3.1, juin 2008 Page 115


Informtique 3 Les interruptions et les exceptions

7.2 Les propriétés des interruptions


Les interruptions possèdent les propriétés suivantes :

1) Les sous routines sont appelées directement avec les instructions de branchement BL. Ce qui n’est pas le cas
des routines de service d’interruption (ISR). En effet, ces dernières sont appelées par des évènements
externes. Le « Tableau des vecteurs d’exception » (vector table) est mise à disposition ici, pour gérer l’appel
de ces différents traiteurs d’exception (voir chapitres 7.6 et 7.7)
2) Le processeur change de mode, lorsque apparaît une interruption. Ce mode dépend de la nature de
l’interruption (voir chapitre 7.3).
3) Les interruptions possèdent des priorités différentes (voir chapitre 7.3)
4) Les requêtes d’interruption standard et les requêtes d’interruption rapides peuvent être masquées (voir
chapitre 7.5)

7.3 La priorité des exceptions et les modes du


processeur
Les questions suivantes apparaissent lorsque plusieurs exceptions surviennent simultanément :
• Quelle exception sera traitée en premier ?
• Est que les traiteurs d’exception peuvent être interrompue par d’autres exceptions ?

La plupart des contrôleurs possèdent des exceptions avec des priorités différentes. Certaines familles de
processeurs, dont celles des processeurs ARM, permettent également de spécifier ces priorités en fonction des
applications.

Chez les processeurs ARM, chaque type d’exception est exécuté dans un mode différent. Par conséquent,
certains registres du processeur ne doivent pas être sauvés dans la routine de service d’interruption. Ces registres
sont appelés des registres fantômes (banked registre).

Le Tableau suivant fournit un aperçu des priorités et des modes de traitement des différentes exceptions :

Exception Priorité Mode du processeur


Reset 1 Superviseur
Data Abort 2 Abort
FIQ (Fast Interrupt Request) 3 FIQ
IRQ (Interrupt Request) 4 IRQ
Prefetch Abort 5 Abort
SWI (Software Interrupts) 6 Superviseur
Instruction non définie 6 Non défini
Tableau 40 : Les priorités et les modes de traitement des exceptions

Exemple :
Le programme principal est interrompu par la requête d’interruption IRQ, dont le niveau de priorité est 4. Durant
le traitement de IRQ par sa routine de service d’interruption « irq_handler », apparaît une requête
d’interruption rapide FIQ, dont le niveau de priorité est 3. Par conséquent irq_handler sera interrompu au
détriment de la routine de service d’interruption rapide « fiq_handler ». La Figure suivante montre le
schéma temporel de cet

Version 3.1, juin 2008 Page 116


Informtique 3 Les interruptions et les exceptions

Exemple :
Priorité

fiq_handler

irq_handler

Programme
principale Temps

IRQ FIQ

Figure 83 : Emboîtement des interruptions

7.4 Les interruptions


Les interruptions peuvent être partagés en deux catégories : les interruptions hardwares et softwares.

Les interruptions hardware :


Les interruptions hardware surviennent de façon asynchrone au déroulement du programme. Ces dernières sont
très importantes pour accomplir les requêtes temps réel.

Les interruptions hardware sont toujours générées par des composants hardware périphériques. Par exemple le
timer, l’interface sérielle ou un port d’entrée quelconque. Les éventuelles sources d’interruptions dépendent donc
du processeur et de ses composants périphériques.

Dans les processeurs ARM, les composants périphériques peuvent générer soit un IRQ ou un FIQ. La gestion de
ces requêtes d’interruption est réalisée par un contrôleur d’interruption supplémentaire. Car le PXA270 possède
de nombreus composants périphériques capables de générer des interruptions (voir chapitre 7.8). Le registre de
contrôle des niveaux d’interruption (en anglais Interrupt Controller Level Register et abrégé par ICLR) permet
de définir le niveau de chaque source d’interruption (IRQ ou FIQ).

Exemple d’interruption hardware :


Le programme d’un microprocesseur gère un système contenant un affichage, des touches et une interface
sérielle. Il existe deux approches pour réaliser la lecture des données à partir des touches ou de l’interface
sérielle :
1. Les touches et l’interface sérielle sont lues périodiquement (polling). Le programme test de façon cyclique,
par exemple toutes les 10 millisecondes, si une touche a été appuyée ou si l’interface sérielle a reçu un
nouveau caractère. Cette approche présente néanmoins les défauts suivants :
− La lecture périodique des entrées nécessite beaucoup de temps de calcul. La plupart du temps le
programme constatera qu’aucune touche n’a été appuyée et qu’aucun caractère n’a été reçu.
− Un évènement peut être perdu à cause de la période du polling. Par exemple : si la lecture des touches ne
s’effectue que toutes les secondes et qu’une touche n’a été appuyée que pendant une demi seconde.
− Le temps nécessaire pour réagir à un évènement correspond, au pire des cas, à la période de polling.
2. Les touches et l’interface sérielle génèrent des requêtes d’interruption, lorsqu’elles doivent transmettre une
nouvelle information au programme. Cette approche présente les avantages suivants :
− Temps de réaction très rapide aux évènements
− Utilisation de la CPU qu’en cas de nécessité

Les interruptions software :


Les interruptions software sont traitées de la même manière que les interruptions hardware. Ces dernières
surviennent toutefois de façon synchrone au déroulement du programme. Par conséquent, elles représentent
quelque chose entre un appel de sous routine et un traitement d’interruption.

Les interruptions software sont souvent utilisées pour appeler des fonctions du système d’exploitation. Car ces

Version 3.1, juin 2008 Page 117


Informtique 3 Les interruptions et les exceptions

dernières font entrer le microprocesseur dans le mode superviseur. Ces fonctions ont ainsi la possibilité
d’accéder à tous les registres.

Il est possible de transmettre un paramètre aux interruptions software avec les processeurs ARM (SWI-number,
24 bits). Ce paramètre permet aux systèmes d’exploitation de définir la fonction à appeler.

7.5 Le masquage des interruptions


Les interruptions peuvent être activées (enabled) ou désactivées (disabled) dans la plupart des processeurs.

La gestion des interruptions peut être réalisée en deux étapes avec le PXA270 :
Dans une première étape, les interruptions IRQ et FIQ peuvent être activées ou désactivées. Cela peut être réalisé
à l’aide de leurs bits de contrôle, qui se situent dans le registre d’état courant du programme CPSR (Current
Program Status Register).

Flags Status Extension Control


Fields

Bit 31 30 29 28 7 6 5 4 0

N Z C V Q not used I F T Mode

Function
Condition Interrupt Processor
Flags Mask Mode
Thumb
State

Figure 84 : Current Program Status Register

Le bit I permet de gérer l’interruption IRQ : 1 désactive cette interruption et 0 l’active. Le bit F gère
l’interruption FIQ de la même façon.

Dans une deuxième étape, les différentes interruptions peuvent être activées ou désactivées à l’aide du contrôleur
d’interruption. Le registre de masquage du contrôleur d’interruption ICMR (Interrupt Controller Mask Register)
permet de réaliser cela (voir chapitre 7.8).

Interrupt- CPU
Controller

Interrupt- Interrupt-
Quelle I/F-Bit Verarbeitung

ICMR CPSR

Figure 85 : Masquage des interruptions en deux étapes

7.6 Le Tableau des vecteurs d’exception


Lorsque apparaît une exception, la CPU interrompt l’exécution du programme pour exécuter la routine de
service d’interruption. L’adresse de cette routine est stockée dans le Tableau des vecteurs d’exception, qui
contient pour chaque type d’exception un vecteur d’exception.

Version 3.1, juin 2008 Page 118


Informtique 3 Les interruptions et les exceptions

L’adresse de base des Tableaux de vecteurs d’exception est normalement 0. Toutefois, du fait que le kit de
développement CARME possède une mémoire flash à cette adresse, ce Tableau y a été déplacé à l’adresse
0xA0000000 :

Exception Adresse de vecteur


Reset 0xA0000000
Instruction non définie 0xA0000004
Interruption software 0xA0000008
Prefetch Abort 0xA000000C
Data Abort 0xA0000010
IRQ 0xA0000018
FIQ 0xA000001C

Tableau 41 : Tableau des vecteurs

Dans certaines familles de processeurs, le Tableau des vecteurs d’exception contient les adresses des différents
traiteurs d’exception (exception handler). Le processeur lit alors cette adresse et réalise le saut de programme
dans la routine de service.

Dans d’autres familles de processeurs, comme celles des processeurs ARM, le Tableau des vecteurs d’exception
contient uniquement des instructions. Dans ce cas, lorsque apparaît une exception, l’instruction, qui est stockée
dans son vecteur d’exception, est alors chargée et exécutée (Par exemple : avec IRQ ce sera l’instruction qui
est stockée à l’adresse 0xA0000018).

Le vecteur d’exception contient normalement une instruction de branchement relative, avec une distance de 24
bits. Si le processeur doit réaliser un saut de programme absolu, avec une adresse de 32 bits, il doit copier
indirectement cette adresse dans le compteur de programme.

Exemple d’un Tableau des vecteurs :


0xA0000000: reset: B reset_handler @ branch with 24-Bit offset
0xA0000004: undef: B und_handler
0xA0000008: SWI: LDR pc, [pc, #swi_handler] @ indirect jump with LDR load to pc
0xA000000C: pabt: B pabt_handler
0xA0000010: dabt: B dabt_handler
0xA0000014: - B notassigned
0xA0000018: IRQ B irq_handler
0xA000001C: FIQ B fiq_handler

Le Tableau des vecteurs d’exception de ci-dessus est construit de manière statique. C'est-à-dire que les adresses
ont été définies de façon fixe pendant la programmation, et sont introduites par le relieur (linker) durant la
procédure de compilation.

Lorsque le Tableau des vecteurs d’exception est stocké dans une RAM, il peut être construit de façon
dynamique. Il peut ainsi être initialisé au démarrage du programme et changé durant son déroulement. :
1) Définition des déplacements (offset), c'est-à-dire les différences d’adresse entre les traiteurs et les vecteurs
d’exception.
2) Soustraire deux à ces déplacements.
3) Relier les offsets au code d’opération (opcode) de l’instruction de branchement (0xEA000000).
4) Copier les valeurs obtenues dans le Tableau des vecteurs d’exception

7.7 Déroulement d’une requête d’interruption


Cette section décrit le déroulement d’une requête d’interruption dans les processeurs ARM. Ce déroulement peut
être légèrement différent avec d’autres processeurs.

Entrée :

Version 3.1, juin 2008 Page 119


Informtique 3 Les interruptions et les exceptions

• La CPU termine l’exécution de l’instruction courante.


• Le mode de fonctionnement change en fonction du type de l’exception. Par exemple : une interruption IRQ
fait entrer le processeur dans le mode IRQ et une interruption software dans le mode superviseur.
• L’adresse de la dernière instruction (complétée avec un déplacement) est stockée dans le registre du relieur
(r14) du nouveau mode. Le déplacement dépend du type de l’exception et doit être considéré pour le calcul
de l’adresse de retour (voir Tableau 42).
• L’ancien contenu du registre CPSR et copié dans le registre SPSR du nouveau mode
• Le bit I est mis à un dans le registre CPSR avec les interruptions IRQ. Ce qui bloque uniquement les
interruptions IRQ. Le bit F est mis à un de la même manière avec les interruptions FIQ. Ce qui bloque les
deux types interruptions. Ce mécanisme empêche que te traiteur d’interruption ne soit interrompu par des
interruptions de priorité identique ou inférieur.
• Le compteur de programme est chargé avec l’adresse du vecteur d’exception correspondant à l’évènement. Ce
qui permet de continuer l’exécution du programme avec l’instruction, qui a été stockée dans le Tableau des
vecteurs d’interruption.

Dans le traiteur d’exception :


Les traiteurs d’exception (Exception Handler) sont toujours exécutés dans des modes privilégiés. Ces modes
mettent à disposition des registres fantômes (banked register), dont la quantité peut varier en fonction des modes.
Tous les modes mettent à disposition un pointeur de pile (r13) et un registre de reliage (r14), destiné au
stockage de l’adresse de retour. Le FIQ met également à disposition les registres r8 à r12.

Si des registres supplémentaires sont nécessaires dans le traiteur d’exception, il faut sauver et restituer leur
contenu initial à l’aide de la pile. Par conséquent, un traiteur d’exception possèdera toujours la structure
suivante :
• Sauvegarde des registres affectés
• Exécution de la tâche
• Restitution des registres préalablement sauvés
• Retour au programme principal

Retour au programme principal :


L’application doit continuer normalement, lorsque le traiteur d’exception a fini son travail. Pour cela il faut
rétablir l’état initial du processeur. En particulier, il faut faire attention aux points suivants :
• Tous les registres du processeur doivent contenir leur valeur initiale (après exécution de instruction, qui
précède le saut dans le traiteur d’exception)
• Le registre CPSR doit retrouver sa valeur d’origine. Cette dernière sera chargée à partir du registre SPSR du
mode d’exception.
• Le compteur de programme (PC) doit contenir l’adresse de la prochaine instruction du programme principale.

Le Tableau suivant permet de calculer l’adresse de la prochaine instruction à exécuter :

Exception Adresse de retour


Reset -
Instruction non définie lr
Interruption software lr
Pre fetch Abort lr - 4
Data Abort lr - 8
IRQ lr - 4
FIQ lr - 4

Tableau 42 : Adresse de retour en fonction des modes du processeur

Le retour depuis le irq_handler ou le fiq_handler peut être programmé de la manière suivante :

Version 3.1, juin 2008 Page 120


Informtique 3 Les interruptions et les exceptions

irq_handler:
...
<handler code>
...
SUBS pc, lr, #4 @ pc = lr – 4, restore CPSR

L’instruction LDMDF peut également être utilisée, lorsque des registres doivent être sauvegardées dans le traiteur
d’exception :

irq_handler:
SUB lr, lr, #4 @ lr = lr -4, subtract offset for return address
STMFD sp!, {r0-r3, r12, lr} @ save context
...
<handler code>
...
LDMFD sp!, {r0-r3, r12, pc}^ @ restore context, return

Le caractères « ^ » à la fin de la liste des registres de l’instruction LDMDF signifie : qu’avant de charger le
compteur de programme avec la valeur du registre de reliage, il faut restituer l’ancien contenu du registre CPSR,
à partir du registre SPSR. Ainsi l’ancien mode du processeur avec les valeurs initiales des bits I et F (c'est-à-dire
avant l’arrivé de l’exception) peuvent être restitués.

Le déroulement du traitement des exceptions peut être schématisé à l’aide de l’exemple suivant :

Application

instr 1
instr 2
IRQ
instr3 PC = LR - 4
CPSR = SPSR_irq
Retour au mode utilisateur
LR = PC+4
Passage au mode IRQ
SPSR_irq = CPSR Vector Table
PC = 0x00000018

B irq_handler

irq_handler:

instr a
instr b

SUB pc, lr,

Figure 86 : Déroulement d’une requête d’interruption

Dans l’exemple de ci-dessus, les instructions 1 et 2 sont exécutées de façon séquentielle. Un IRQ interrompt
alors le programme principale (l’instruction 2 sera toutefois encore exécutée). La CPU lit ensuite la prochaine
instruction à exécuter dans le Tableau des vecteurs d’exception. Ce qui mène à un branchement dans le traiteur
d’IRQ. Finalement, l’état initial du processeur est rétabli et le programme continu avec l’exécution de
l’instruction 3.

7.8 Comportement temporel des interruptions


Le déroulement d’un traitement d’interruption peut être représenté graphiquement de la manière suivante :

Version 3.1, juin 2008 Page 121


Informtique 3 Les interruptions et les exceptions

Interrupt Request

User Program User Program


CPU context saved

CPU context restored


User ISR Code

Interrupt Latency
Interrupt Recovery

Interrupt Response

Time

Figure 87 : Comportement temporel des interruptions

Le temps de latence d’interruption (Interrupt Latency) est le temps entre l’apparition de la requête d’interruption
(Interrupt Request) et l’exécution de la première instruction du traiteur d’interruption (interrupt handle) :

tILat = tdis + tcmod

tILat : Interrupt Latency


tdis : Temps maximal, pendant lequel l’interruption peut être désactivée
tcmod : Temps nécessaire pour le changement de mode

Le temps de réponse à l’interruption (Interrupt Response) est le temps entre l’apparition de la requête
d’interruption (Interrupt Request) et l’exécution de la première instruction de sa routine de service (ISR) :

tIRes = tIL + tcsw

tIRes : Interrupt Response


tILat : Interrupt Latency
tcsw : Temps nécessaire à la sauvegarde du contexte de la CPU

Le temps de recouvrement de l’interruption (Interrupt Recovery) est le temps nécessaire pour revenir dans le
programme principal après exécution de la routine de service (ISR) :

tIRec = tcsw2 + trti

tIRec : Interrupt Recovery


tcsw2 : Temps nécessaire pour restituer l’ancien contexte
trti : Temps nécessaire pour appeler la routine « return from interrupt »

7.9 Le contrôleur d’interruption du PXA270


Les chapitres précédents décrivent les deux interruptions externes, qui sont soutenus par les processeurs ARM :
IRQ et FIQ. Ces deux interruptions ne sont pas suffisantes pour les systèmes embarqués, où il faut pouvoir réagir
à de nombreux évènements externes. Par conséquent, le PXA270 contient également un contrôleur d’interruption
(Interrupt Controller). Ce dernier est schématiquement un multiplexeur, qui permet de gérer les diverses sources
d’interruption.

Chaque composant périphérique peut générer soit une interruption IRQ ou une interruption FIQ. Des priorités

Version 3.1, juin 2008 Page 122


Informtique 3 Les interruptions et les exceptions

allant de 0 à 39 peuvent être attribuées à ces composants, indépendamment du type d’interruption (IRQ ou FIQ).
Ces composants ne possèdent toutefois pas des vecteurs d’interruption propres.

Une description détaillée du contrôleur d’interruption est fournie par [2], Intel PXA27x Processor Family
Developer's Manual. Ce chapitre fournit un bref aperçu du contrôleur d’interruption et une brève description des
registres les plus importants.

La Figure suivante montre le schéma bloc du contrôleur d’interruption :

ICLR

ICMR

ICPR

ICIP

ICFP

ICHP

IPRx

Figure 88 : Diagramme de bloc du contrôleur d’interruption, Source : [2]

Les registres de configuration et de statut du contrôleur d’interruption sont décrits dans le Tableau suivant. Les
noms des registres commencent par « IC », ce qui signifie « Interrupt Controller ».

Version 3.1, juin 2008 Page 123


Informtique 3 Les interruptions et les exceptions

Nom Fonction Adresse Brève description


ICIP IRQ Pending Reg. 0x40D0_0000 Indique les composants périphériques non masqués, qui
ont généré une IRQ (1 bit par source)
0: inactif
1: IRQ de cette source actif
ICMR Mask Register 0x40D0_0004 Masquage ou activation des différentes sources
d’interruption (1 bit par source)
0: masqué (disabled)
1: non masqué (enabled)
ICLR Level Register 0x40D0_0008 Défini le type d’interruption (IRQ ou FIQ) généré par
le composant périphérique
0: IRQ
1: FIQ
ICFP FIQ Pending Reg. 0x40D0_000C Indique les composants périphériques non masqués, qui
ont généré un FIQ (1 bit par source).
0: inactif
1: FIQ de cette source actif
ICPR Pending Register 0x40D0_0010 Montre l’état de toutes les sources d’interruption (1 bit
par composant périphérique)
0: inactif
1: Interruption est activé
ICCR Control Register 0x40D0_0014 Le bit de masquage Idle défini, si les interruptions
doivent être activées indépendamment du registre de
masquage (ICMR).
ICHP Highest Priority R. 0x40D0_0018 Montre pour IRQ et FIQ, la source d’interruption qui a
la plus haute priorité. L’identité de la source
périphérique est utilisée pour cela (voir Tableau 44).
IPR0 - Priority Register 0x40D0_001C Défini la priorité d’un composant périphérique. Chaque
IPR31 0 – 31 0x40D0_0098 priorité possède son propre registre IPRx, dans la
quelle il faut introduire l’identité du composant qui
génère l’interruption.
ICIP2 IRQ Pending R. 2 0x40D0_009C comme ICIP
ICMR2 Mask Register 2 0x40D0_00A0 comme ICMR
ICLR2 Level Register 2 0x40D0_00A4 comme ICLR
ICFP2 FIQ Pending Reg. 2 0x40D0_00A8 comme ICFP
IPPR2 Pending Register 2 0x40D0_00AC comme ICIP
IPR32 – Priority Register 0x40D0_00B0 comme IPRxx
IPR39 32 - 39 0x40D0_00CC

Tableau 43 : Les registres de configuration et de statut du contrôleur d’interruption

Le Tableau suivant contient les différentes sources d’interruption et leur identité périphérique :

Version 3.1, juin 2008 Page 124


Informtique 3 Les interruptions et les exceptions

Tableau 44 : Identité périphérique (periphery-ID), source : [2]

7.10 Les variante pour le contrôleur d’interruption


Il existe différentes variantes pour implémenter un contrôleur d’interruption : « Nonnested Interrupt Handler »,
« Nested Interrupt Handler », « Reentrant Interrupt Handler », « Prioritized Simple Interrupt Handler » etc.
Toutes ces variantes ont été décrites de façon détaillée dans [10], « ARM System Developer's Guide ». Ce
chapitre ne contient que la description pour le « Nonnested Interrupt Handler ». Ce dernier possède les propriétés
suivantes :
• Traitement des interruptions de façon séquentiel. Le traitement d’une interruption ne peut pas être interrompu
par une interruption de priorité égale.
• Avantage : l’implémentation et les tests sont simples.
• Désavantage : Des temps de latence relativement lents. Ce qui peut être un désavantage pour les systèmes
embarqués avec plusieurs sources d’interruption.

Le « Nonnested Interrupt Handler » fonctionne de la manière suivante :

Version 3.1, juin 2008 Page 125


Informtique 3 Les interruptions et les exceptions

Interrupt

Disable Interrupts
1 spsr_mode = cpsr
pc = vector table entry

Save context
2

Interrupt Handler
3

Interrupt Service
4
Routine

Restore context
5

Enable Interrupts
6 pc = lr - 4
cpsr = spsr_mode

return

Figure 89 : « Nonnested Interrupt Handler », source: [10]

Le fonctionnement du « Nonnested Interrupt Handlers » est discuté à l’aide de l’exemple IRQ.


1) Le processeur ARM désactive toutes les interruptions IRQ. Ensuite il entre dans le mode IRQ, dans lequel il
sauve et le contenu du registre CPSR dans le registre SPSR. Le compteur de programme est finalement
chargé avec l’adresse du vecteur d’interruption (0x00000018).
2) Le contexte doit être sauvegardé : En cas d’appel de fonction C, il faut absolument sauvegarder les registres
r0 à r3 et r12 (voir APCS). Les registre r4 jusqu’à r11 sont sauvés automatiquement par le compilateur
dans les foncions C. S’il n’y a pas d’appel de fonction C, seul les registres affectés doivent être sauvés.
3) Le traiteur d’interruption identifie la source d’interruption et appelle la routine de service adéquate.
4) La routine de service traite l’interruption et désactive l’interruption.
5) Le contexte original est remis.
6) Les interruptions sont de nouveau activées, le registre CPSR est remis dans son état initial et le compteur de
programme est chargé avec l’adresse de retour.

Le code en assembleur pour le « Nonnested Interrupt Handler » pourrait être le suivant :

irq_handler:
SUB lr, lr, #4 @ adjust link register for return address
STMFD sp!, {r0-r3, r12, lr} @ save context
LDR r0, =ICIP @ load IRQ status register address
LDR r0, [r0] @ read IRQ status register
TST r0, #1<<PER_ID_OST @ test if operating system timer (OST) caused IRQ
BLNE timer_isr @ if yes, call timer ISR
TST r0, <other source> @ test other IRQ sources
...
LDMFD sp!, {r0-r3, r12, pc}^ @ restore context and return

Version 3.1, juin 2008 Page 126


Informtique 3 Les Structures de contrôle en assembleur

8 Les Structures de contrôle en


assembleur

8.1 Introduction
Le déroulement d’un programme peut être influencé à l’aide de structure de contrôle. Pour cela il existe les
procédures suivantes :
• Les séquences
• Les ramifications
• Les boucles

Une séquence est une suite d’instruction, qui est exécutée sans critères préalables. Alors que les ramifications et
les boucles ne sont exécutées qu’en fonction des critères externes, comme par exemple l’état du processeur.

Les langages de programmation évolués mettent à disposition des instructions standardisées pour définir des
structures de contrôle. Par exemple le langage de programmation C contient les instructions suivantes :

Pour les ramifications :


• if - else (Ramification simple)
• switch (Ramification multiple)

Pour les boucles :


• while (Boucle avec évaluation initiale)
• do - while (Boucle avec évaluation finale)
• for (Boucle d’itération)

Dans le langage de programmation assembleur, il est également possible d’utiliser ces structures de contrôle. Ce
qui permet de mieux structurer le code et, par conséquent, de faciliter son entretient.

Contrairement aux langages de programmations évolués, l’assembleur ne met pas à disposition des instructions
pour la définition des structures de contrôle. Toutefois, ces structures peuvent être réalisée avec des séquences
d’instructions en utilisant des chablons. Les chapitres suivants montrent, comment ces structures de contrôles
peuvent être réalisées en assembleur.

Version 3.1, juin 2008 Page 127


Informtique 3 Les Structures de contrôle en assembleur

8.2 La ramification simple


Dans la ramification simple, une condition est évaluée au début de l’instruction. Cette condition peut être
« réalisée » (true) ou « non réalisée » (false).

if condition

true false

true- false-
block block

Figure 90 : La ramification simple

Lorsque la condition est réalisée, le programme exécute les instructions qui sont contenues dans le bloc
« then » ; sinon, il exécute les instructions du bloc « else ». Le bloc « else » est en option. C’est à dire
qu’une ramification simple ne peut contenir que du bloc « if ».

Exemple de code :

C Assembler
if if: TST <condition>
(condition)
{ BNE false
/* true-Block */ true: ... @ true-block
} B endif
else
{ false: ... @ false-block
/* false-Block */
} endif:

Tableau 45 : La ramification simple en C et en assembleur, avec un bloc « else »

Une ramification simple sans le bloc « else » peur être programmée de la manière suivante :

C Assembler
if (condition) if: TST <condition>
{ BNE endif
/* true-Block */ true: ... @ true-block
}
endif:

Tableau 46 : La ramification simple en C et en assembleur, sans le bloc « else »

Une ramification simple contient toujours une instruction d’entrée (ici « TST »), qui modifie les bits d’état le
registre CPSR (Current Program Status Register), suivie d’une instruction de saut de programme conditionnel
(ici « BNE »). Toutes les instructions, qui influencent les bits d’état, peuvent être utilisées comme instruction
d’entrée (TST, CMP, MOVS etc.) ; et toutes les instructions « Bcc » peuvent être utilisées comme sauts de
programme conditionnels.

Les architectures ARM soutiennent une autre forme de ramification simple : L’exécution conditionnelles des
instructions. Toutefois cela n’est raisonnable que pour des conditions simples, qui réunissent un à trois
instructions dans un bloc.

Version 3.1, juin 2008 Page 128


Informtique 3 Les Structures de contrôle en assembleur

Exemple (de [11]):


La recherche du maximum entre deux nombres peut être programmé en C de la manière suivante :
if (a > b)
c = a;
else
c = b;

En assembleur ARM, il est possible de programmer cet algorithme avec des instructions conditionnelles. Ce qui
évite l’utilisation des sauts conditionnels ou inconditionnelles de la structure proposée au Tableau 45 (les
variables a, b et c sont stockées dans les registres r0, r1 et r2) :
CMP r0, r1 @ if (a > b)
MOVGT r2, r0 @ c = a
MOVLE r2, r1 @ c = b

8.3 La ramification multiple


La ramification multiple prend une décision entre plusieurs alternatives. Pour cela une expression d’entrée est
évaluée et le résultat est comparé avec les valeurs constantes de toutes les étiquettes case. En cas de
correspondance, le programme exécute les instructions du bloc appartenant à l’étiquette. S’il n’y a pas de
correspondance, le programme exécute le bloc par défaut.

switch expression
case const-expr1

const-expr1 case const-expr2


block

const-expr2
block
default

default
block

Figure 91 : La ramification multiple

Exemple de code :

Version 3.1, juin 2008 Page 129


Informtique 3 Les Structures de contrôle en assembleur

C Assembler
switch (expression) switch: MOV r0, #expression
{
case (const-expr1): CMP r0, #const_expr1
... BEQ case1
break;
case (const-expr2): CMP r0, #const_expr2
... BEQ case2
break;
... ...
default: B default
...
break;
}
case1: ... @ const-expr1 block
B endSwitch
case2: ... @ const-expr2 block
B endSwitch
default: ... @ default block

endSwitch:

Tableau 47 : Ramification multiple en C et Assembler

Au début de la ramification multiple, l’expression à évaluer est copiée dans un registre, afin de pouvoir être
comparée avec les constantes des étiquettes case. Lorsqu’il y a correspondance, le programme effectue un saut
à l’étiquette correspondant à la constante, pour y exécuter les instructions.

Le code peut devenir très lent, lorsque l’instruction switch contient de nombreuses étiquettes case. Dans ce
cas, il est recommandé d’utiliser des Tableaux de sauts (jump table). Ces derniers peuvent être programmés de la
manière suivante :

switch: ADR r1, jumptable @ load r1 with base address of jump table
MOV r0, #expression @ load r0 with expression to test
CMP r0, #tablemax @ check if value is in jump table
LDR LO pc, [r1, r0, LSL #2] @ ok Æ load pc with label form jump table
B default @ expression > tablemax Æ default
case1: ... @ const-expr1 block
B endSwitch
case2: ... @ const-expr2 block
B endSwitch
default:
... @ default block
endSwitch:
...

jumptable:
.word default @ case 0 not defined Æ default
.word case1
.word case2

.set tablemax, 0x03 @ jump table has 4 entries

Les limitations des Tableaux de sauts sont les suivantes :


• Le Tableau ne devrait pas être trop grand. Elle ne peut pas contenir toutes les valeurs des expressions
constantes (entier de 32 bits). Un Tableau de saut n’est pas adéquat pour évaluer les expressions de 1 à 10000.
Cela nécessiterait un Tableau avec 10000 entrées.
• La taille du Tableau doit être testée durant l’exécution du programme (CMP r0, #tablemax)
• Il faut introduire dans le Tableau le label par défaut pour les valeurs non définies (l’exemple de ci-dessus ne
contient pas le cas 0. Il faut donc introduire une valeur par défaut à l’indexe 0 du Tableau).

Version 3.1, juin 2008 Page 130


Informtique 3 Les Structures de contrôle en assembleur

8.4 La boucle avec évaluation de la condition au


début
La boucle avec une évaluation de la condition initiale (boucle while) exécute un bloc de code un certain
nombre de fois, qui n’est pas connu d’avance.
La condition est évaluée au début de la boucle. Si cette dernière est « vraie », le programme exécute les
instructions du corps de la boucle et réitère l’évaluation de la condition. Si cette dernière est « fausse », le
programme quitte la boucle et continue avec les instructions suivantes.
Avec ce genre de boucle, lorsque la condition est « fausse » depuis le début, les instructions de la boucle ne sont
jamais exécutées.

Condition de la boucle

Corps de la
boucle

Figure 92 : La boucle avec une évaluation de la condition au début

Exemple de code :

C Assembler
while while: TST <condition>
(condition)
{ BEQ endwhile
// Corps de la boucle … @ Corps de la boucle
} B while

endwhile:

Tableau 48 : La boucle avec une évaluation de la condition au début en C et en Assembler

Les bits d’état courant du programme sont modifiés en fonction de l’instruction d’entrée (comme ce fut le cas
avec la ramification simple). Lorsque la condition « n’est pas réalisée », le programme effectue ensuite un saut
de programme conditionnel à la fin de la boucle. Après exécution des instructions du corps de la boucle, le
programme fait un saut de programme non conditionnel au début de la boucle, afin de réitérer l’évaluation de la
condition.

Le code du Tableau 48 n’est pas très efficace, car il nécessite deux sauts de programme (B et BEQ), qui doivent
être exécutés à chaque passage. Ce code peut être optimisé avec une réorganisation. Dans ce cas, un seul saut de
programme conditionnel (BNE) ne doit être exécuté par passage.

while: B test
loop: … Schleifenkörper
test: TST <condition>
BNE loop
endwhile:

8.5 La boucle avec évaluation de la condition à la fin


La condition de la boucle est évaluée ici à la fin de la boucle (contrairement à la boucle avec évaluation de la
condition initiale). Lorsque la condition est « vraie », le programme exécute de nouveau les instructions du corps
de la boucle. Si la condition « n’est pas réalisée », le programme quitte la boucle et continu avec l’instruction
suivante. Avec ce genre de boucle, les instructions du corps de la boucle seront toujours réalisées au moins une

Version 3.1, juin 2008 Page 131


Informtique 3 Les Structures de contrôle en assembleur

fois.

Corps de la
boucle

Condition de la boucle

Figure 93 : La boucle avec évaluation de la condition à la fin

Exemple de code :
C Assembler
do do:
{
// Corps de la boucle … @ Corps de la boucle
} while (condition); while: TST <condition>
BNE do
enddowhile:

Tabelle 1: La boucle avec évaluation de la condition à la fin en C et en assembler

Les bits d’état sont également modifiés dans cet exemple en fonction de l’instruction d’évaluation (ici « TST »).
Lorsque la condition est « vraie », le programme effectue un saut de programme conditionnel au début de la
boucle. La boucle do - while correspond ainsi à la version optimisée de la boucle while, introduite au
chapitre 8.4, sans la première instruction de branchement.

8.6 La boucle itérative


La boucle itérative (boucle for) est un cas spécial de la boucle avec évaluation de la condition initiale. Dans le
langage de programmation C, toutes les instructions de contrôle sont mises en évidence au début de la boucle.
Normalement ce genre de boucle utilise une variable compteur, qui est initialisée tout au début (valeur départ).
La condition d’arrêt de la boucle est réalisée avec la comparaison de cette variable avec une valeur finale. Tant
que la condition est vraie, le programme exécute le corps de la boucle et incrémente le compteur. Les pas de ce
compteur peuvent être positif ou négatif.

for (valeur départ, valeur fin, Pas)

Corps de la
boucle

Figure 94 : La boucle itérative

Exemple de code :

Version 3.1, juin 2008 Page 132


Informtique 3 Les Structures de contrôle en assembleur

C Assembler
for (expr1; expr2; expr3) for: MOV r0, #valeur_début
{ loop: CMP r0, #valeur_fin
// Corps de la boucle BGE endfor
} ... @ Corps de la boucle
ADD r0, r0, #pas
bra loop
endfor:

Tableau 49 : La boucle itérative en C et ne assembleur

Un registre rx (dans cet exemple r0) est utilisé comme variable compteur. Au début cette variable est initialisée
avec la valeur « valeur_début ». A l’étiquette « loop », le critère d’arrêt est évalué à l’aide de l’instruction
CMP, qui teste si la variable compteur a atteint la valeur « valeur_fin ». Si cette dernière atteint cette valeur
limite, le programme fait un saut de programme conditionnel (BGE) à la fin de la boucle. Si non, le programme
exécute les instructions du corps de la boucle et incrémente la variable compteur en fonction de la valeur
« pas ».

Des autres instructions que BGE peuvent également être utilisées pour évaluer la condition d’arrêt. L’instruction
ADD peut être remplacée par SUB afin de réaliser des pas de compteur décroissant.

Version 3.1, juin 2008 Page 133


Informtique 3 Les structures de données en assembleur

9 Les structures de données en


assembleur

9.1 Introduction
Les structures de données rassemblent plusieurs variables (de type simple ou composé) dans une structure. Voici
un exemple de structure de donnée en C :

struct Adresse
{
char Nom [MAX_CHAR];
char Prenom [MAX_CHAR];
char Route [MAX_CHAR];
int Numero;
char Lieu [MAX_CHAR];
};

Les langages de programmation évolués soutiennent les structures de données. Il en résulte les avantages
suivants :
• Compréhension et entretient facilité du programme
• Meilleur structure

En assembleur il est également possible de profiter des avantages des structures de données. Ce chapitre traite ce
sujet.

Les structures de données sont toujours orientées problème. C'est-à-dire, qu’ils essayent de reproduire au mieux
la réalité à l’aide d’un jeu de données (par exemple les données d’un processus). Il existe également une relation
étroite entre ces structures et le code du programme. Par conséquent, la modification d’une structure aura un
effet sur le code.

9.2 Les Tableaux unidimensionnels


Un Tableau (array) contient plusieurs éléments du même type. Ces éléments sont déposés dans la mémoire sans
lacune, l’un derrière l’autre. L’accès à ces éléments s’effectue à l’aide de leur indexe. Le premier élément
possède l’indexe 0 (array[0])

Exemple : Définition d’un Tableau contenant 4 éléments du type mot :


.data
array .space 4*4, 0x12 @ array of 4 words, each initialized with 0x12121212

La directive « .space » permet de réserver un certain nombre de bytes, qui peuvent être initialisés. Dans cet
exemple 4 * 4 bytes ont été réservés au total et chaque byte a été initialisé avec la valeur 0x12. Si le Tableau ne
doit pas être initialisé, il peut également être défini dans la section « .bss ».

L’élément d’indexe 2 peut être effacé par exemple de la manière suivante :


.text
LDR r0, =array @ load r0 with base address of array
LDR r1, #2 @ load r1 with index 2
MOV r2, #0 @ value to write is 0
STR r2, [r0, r1, LSL #2] @ array[2] = 0

L’adresse de base du Tableau est d’abord copiée dans r0. Ce dernier adresse ainsi le premier élément du
Tableau (indexe 0). L’indexe de l’élément à accéder est ensuit copier dans r1. L’accès au Tableau est effectué
finalement avec l’instruction STR. L’adressage y est indirect et est obtenu avec « r0 + r1 * 4 ». La

Version 3.1, juin 2008 Page 134


Informtique 3 Les structures de données en assembleur

multiplication avec un facteur scalaire (défini dans cet exemple avec LSL #2) est importante, car les adresses
sont toujours calculées en byte.

Important : Un facteur scalaire est utilisé pour l’adressage indirect. Ce dernier possède les valeurs suivantes :
• 1 pour les bytes
• 2 pour les demis mots
• 4 pour les mots

Le code ci-dessus doit être modifié de la manière suivant avec un Tableau, qui contient des éléments du type
byte au lieu du type mot :

.data
array .space 4, 0x34 @ array of 4 bytes, each initialized with 0x34

.text
LDR r0, =array @ load r0 with base address of array
LDR r1, #2 @ load r1 with index 2
MOV r2, #0 @ value to write is 0
STRB r2, [r0, r1] @ array[2] = 0 (Byte)

9.3 Les Tableaux multidimensionnels


Soit un Tableau avec 3 lignes et 4 colonnes du type mot (array [3][4]) :

array .space 3*4*4 @ reserve 3 rows * 4 columns * 4 Bytes

Le Tableau peut être représenté de la manière suivante :

[0,0] [0,1] [0,2] [0,3]


[1,0] [1,1] [1,2] [1,3]
[2,0] [2,1] [2,2] [2,3]
Tableau 50 : Tableau à deux dimensions

Les éléments de ce Tableau ne peuvent être stockés soit en ligne ou en colonne. Par exemple, le stockage en
ligne du Tableau, contenant 3 lignes et 4 colonnes, s’effectue de la manière suivante :

[0,0]
[0,1] 1. ligne
[0,2]
[0,3]
[1,0]
[1,1] 2. ligne
[1,2]
[1,3]
[2,0]
[2,1] 3. ligne
[2,2]
[2,3]

Tableau 51 : Stockage en ligne du Tableau

L’accès à l’élément d’indexes de ligne « i » et de colonnes « j » s’effectue de la manière suivante :

Adresse = 4 * i + j

Version 3.1, juin 2008 Page 135


Informtique 3 Les structures de données en assembleur

Cette formule n’est valable que pour des Tableaux, qui possèdent une adresse de base nulle et 4 colonnes du type
byte. La formule générale, qui contient également l’adresse de base du Tableau et la taille des éléments, est la
suivante :

Adresse de l’élément = Adresse de base + S * (SZ * i + j)

Les notations de cette formule ont les significations suivantes :


Adresse de base : Adresse de départ du Tableau
S : Facteur scalaire, byte = 1, mot = 2, long mot = 4
SZ : Nombre de colonnes
i : Index de ligne
j : Index de colonne

L’évaluation de cette formule peut s’avérer coûteuse, en fonction de la famille du processeur. Notamment
l’opération de multiplication « SZ * i » peut exiger un temps de calcul important. La multiplication avec le
facteur scalaire S peut, par contre, être effectuée avec des opérations de décalages (facteur 2 ou 4).

9.4 Les chaîne de caractères


Une chaîne de caractères (string) est une suite de caractères ASCII, qui se termine avec le caractère nul ou de fin
de chaîne de caractères (′\0′). La chaîne de caractères est définie de la manière suivante :

text: .asciz "abcABC0123" @ null-terminated string

Remarque : Le caractère nul (′\0 ′) et celui du chiffre zéro (′0′) possèdent des valeurs ASCII différentes.

9.5 Les structures


Les structures de données permettent d’assembler des variables avec des types différents. Par exemple, la
structure pour stocker une date peut par être définie de la manière suivante :

date: .byte 14 @ day as byte (1-31)


.byte 03 @ month as byte (1-12)
.hword 1879 @ year as halfword (e.g. 0000 – 3000)

La structure « date » possède deux membres de type byte et un membre de type demi mot. L’accès aux
membres de la structure s’effectue à l’aide de déplacements (offset), qui définissent la position relative des
membres dans la structure. Ces derniers sont les suivants pour la structure « date » :

.set OFFSET_MONTH, 1
.set OFFSET_YEAR, 2

Le membre « day » ne nécessite pas d’offset, car son adresse est identique à celle de base de la structure date.

L’écriture du membre année dans le registre r0 s’effectue par exemple de la manière suivante :

LDR r1, =date @ load r1 with base address


MOV r2, #OFFSET_YEAR @ load r2 with offset
LDR H r0, [r1, r2] @ read year (halfword)

9.6 La pile (stack)


Le chapitre 6 concernant « les sous routines » fournit une description de la structure et du fonctionnement de la

Version 3.1, juin 2008 Page 136


Informtique 3 Les structures de données en assembleur

pile. Cette dernière était destinée au transfert des paramètres, à la sauvegarde des registres et la définition des
variables locales. Mais, l’utilisateur peut également définir des autres piles pour la gestion de données.

Directive pour l’implémentation de la pile :


• Les valeurs, qui doivent être déposées sur la pile (push) ou lues à partir de cette dernière (push), doivent se
trouver dans le registre r0. Les opérations de pile peuvent ainsi également être appelées par les fonctions C.
Car selon l’APCS, les paramètres sont transmis ou retournés à l’aide du registre r0.
• La pile de l’exemple est prévue pour les variables du type mots (word).
• La pile croît dans le sens négatif (adresses décroissantes).
• Le pointeur de pile adresse le dernier élément, qui a été déposé sur la pile (push : decrement before, pop :
increment after).
• Le pointeur de pile est une variable globale.

La pile et le pointeur de pile peuvent être définis de la manière suivante :

.set STACK_SIZE, 1000 @ define stack size


.data
stack: .space STACK_SIZE, 0 @ reserve address space for stack
stackpointer: .word stack + STACK_SIZE @ global variable, holds actual stack pointer

Le pointeur de pile doit adresser le début de la pile. Du fait que la pile croît dans le sens négatif, ce début est
l’adresse la plus grande de la pile. Le pointeur de pile est par conséquent initialisé avec « stack +
STACK_SIZE ».

La situation suivante prévaut après l’initialisation :

Pointeur Adresses
de pile hautes

Variable Adresses
pile basses

Figure 95 : La pile après son initialisation

Une opération « push » peut être implémenté de la manière suivante :

@ parameter r0 holds value to write to stack


@ r1 holds stackpointer address
@ r2 holds stackpointer value
@ r3 holds stack address
@ stack full error is not implemented

push:
STR lr, [sp, #-4]! @ save return address on system-stack
LDR r1, =stackpointer @ load r1 with stackpointer address
LDR r2, [r1] @ load r2 with stackpointer value
LDR r3, =stack @ load r3 with stack address
CMP r2, r3 @ check if stack is already full
BLE stack_full
SUB r2, #4 @ decrement stackpointer (decrement before)
STR r2, [r1] @ save new stackpointer value
STR r0, [r2] @ push value to stack
B endpush @ Æ end
stack_full: ... @ error code
endpush: LDR pc, [sp], #4 @ return

Version 3.1, juin 2008 Page 137


Informtique 3 Les structures de données en assembleur

Une opération « pop » peut être implémenté de la manière suivante :

@ parameter r0 is return value, element read from stack


@ r1 holds stackpointer address
@ r2 holds stackpointer value
@ r3 holds stack address
@ stack empty error is not implemented

pop:
STR lr, [sp, #-4]! @ save return address on system-stack
LDR r1, =stackpointer @ load r1 with stackpointer address
LDR r2, [r1] @ load r2 with stackpointer value
LDR r3, =stack @ load r3 with stack address
ADD r3, #STACK_SIZE @ r3 holds stack top address
CMP r2, r3 @ check if stack is empty
BGE stack_empty
LDR r0, [r2] @ pop value from stack, r0 is return value
ADD r2, #4 @ increment stackpointer (increment after)
STR r2, [r1] @ save new stackpointer value
B end pop @ Æ end
stack_ empty: … @ error code
endpop: LDR pc, [sp], #4 @ return

Contrairement à la pile décrite au chapitre 6, qui ne contient pas de routine de contrôle pour les dépassements de
capacité, il est possible d’ajouter des fonctionnalités de contrôle, afin de pouvoir déceler les éventuels
dépassements.

9.7 Queues et anneaux de tampons (Queue / Ring


buffers)
Contrairement à la pile, une queue de tampons est accessible à ses deux bouts. Son principe est « first in, first
out ». Une queue de tampons fonctionne de la manière suivante :

Put

n. Element Tail / écriture

2. Element

1. Element Head / lecture

Get

Figure 96 : La queue de tampons

Directive pour l’implémentation de la queue de tampons:


• Head et Tail ne doivent se croiser
• La queue de tampons peut engloutir toute la mémoire

Dans la pratique, les queues de tampons sont remplacées par les anneaux de tampons. La problématique de
l’engloutissement de la mémoire est ainsi éliminée. Il existe deux types de réalisation :

Version 3.1, juin 2008 Page 138


Informtique 3 Les structures de données en assembleur

a) Head et Tail peuvent adresser le même élément de mémoire. Dans ce cas une variable supplémentaire
« size » est également nécessaire, afin de pouvoir stocker le nombre d’éléments contenus dans l’anneau.
Ainsi, size = 0 correspond à un anneau vide.

Après Apres écriture du


l’initialisation premier élément

Head Tail 1. Element Head


2. Element Tail

size = 0 size = 1

n. Element

Figure 97: Les pointeurs Head et Tail dans une queue de tampons

b) Head et Tail ne peuvent pas adresser le même élément de mémoire. Un élément de mémoire est ainsi
sacrifié, mais la variable supplémentaire size n’est plus nécessaire (size = Tail – Head – 1). La
queue peut ainsi être initialisée avec « Head = 1 » et « Tail = 2 ».

Dans les deux cas il faut systématiquement contrôler les dépassements de capacités des pointeurs Head et
Tail. La Figure suivant illustre un exemple avec un dépassement de capacité de 8 à 1.

Dépassement

Head / Tail /
lecture écriture
1 8

2 7

3 6

4 5

Figure 98 : Anneau de tampons avec 8 éléments

Version 3.1, juin 2008 Page 139


Informtique 3 Le démarrage d’un programme C

10 Le démarrage d’un programme C


Les 3 derniers chapitres de ce manuscrit traitent les projets qui sont définis en C et assembleur.

10.1 Le processus de démarrage d’un programme C


Le processus de démarrage d’un programme désigne la partie du code, qui est exécuté entre de reset et
l’application. Le processus de Démarrage d’un programme en C est illustré schématiquement dans la Figure
suivante. Les différentes tâches de ce processus sont décrites dans les chapitres suivants.

Reset

Bootloader
Code de démarrage du système (CA RM E)

Code de démarrage de l’application

void main (void)


{
// Programme principale
}

Figure 99 : Processus de démarrage

10.2 Le reset
Au début fut le reset. Ce dernier peut être généré par les événements suivants :
• Allumage
• Watchdog
• Touche reset
• Software

Le reset conduit le processeur dans un état défini. Dans la plupart des contrôleurs le reset est le premier vecteur
d’interruption (souvent à l’adresse 0). Ce dernier contient l’adresse de la première fonction, qui doit être appelée
au démarrage du système. Ce qui est normalement le code de démarrage du système (boot loader), lorsque ce
dernier est disponible, ou le code de démarrage de l’application.

10.3 Le code de démarrage du système (boot loader)


Le boot loader est le code, qui initialise le système afin que qu’il puisse fonctionner. Les tâches du boot loader
sont les suivantes :
1. Initialisation des registres les plus importants, en particulier le « Chip-Select », afin que les composants de la
mémoire externe puissent être accédés.
2. Chargement de l’application à partir de la flash (ou d’un autre média de stockage non volatil) dans la mémoire
de travail (RAM).

Version 3.1, juin 2008 Page 140


Informtique 3 Le démarrage d’un programme C

3. Démarrage de l’application.

Remarque 1 : Le boot loader charge le système d’exploitation en premier, lorsque ce dernier est disponible. Les
applications sont chargées ensuite par le système d’exploitation.
Remarque 2 : Sur le kit de développement CARME, le boot loader contient un Tableau de vecteurs
d’interruption, qui se situe dans la mémoire flash à l’adresse 0. Les vecteurs de ce Tableau contiennent des
instructions de branchement sur tous les vecteurs d’interruption de l’application, qui se situent dans la mémoire
de travail à l’adresse 0xA0000000. La MMU ne sera pas utilisée pour les projets C et assembleur.

10.4 Le code de démarrage de l’application


Ce code de démarrage de l’application est exécuté normalement par une ou plusieurs routines assembleur, qui se
trouvent dans un fichier de démarrage. Les noms de ces fichiers dépendent des systèmes de développement.
Toutefois, ces derniers sont souvent appelés « crt0 » ou « startup ».

La programmation du processus de démarrage n’est pas requise avec les programmes en C. En effet, le
compilateur lit automatiquement le code de démarrage à partir d’une librairie et l’insère dans le projet.
L’application C démarre alors avec la fonction principale « main ». Cependant il existe de nombreux cas, où le
code de démarrage doit être modifié. Ce qui exige des connaissances en assembleur.

Le code de démarrage des projets CARME C se trouve dans le fichier « crt0.s », qui se trouve dans le sous
directoire « startup ».

Le code de démarrage doit réaliser les tâches suivantes :


• Définition du Tableau de vecteurs d’interruption de l’application
• Initialisation supplémentaire des registres CPU
• Initialisation de la pile
• Initialisation des variables globale
• Annuler les variables non initialisées
• Initialisation du paquet du support de bord (Board-Support-Package abrégé par BSP)

Définition du Tableau de vecteurs d’interruption de l’application


Le code de démarrage du système (boot loader) exécute en dernier un saut de programme à l’adresse
0xA0000000 (RAM), où se situe le Tableau des vecteurs d’interruption de l’application. Le vecteur
d’interruption reset de ce Tableau contient l’instruction « B Reset_Handler ». Ce traiteur de reset
(Reset_Handler) contient le code de démarrage de l’application. Cela est défini de la manière
suivante (fichier crt0.s) :

.global _startup
.section .startup

/* Exception vector table *****************************************************/


_startup:
reset: B Reset_Handler /* 0x00 reset vector */
undefvec: B UNDEF_Routine /* 0x04 undef. instruction vector */
wivec: B SWI_Routine /* 0x08 software interrupt vector */
pabtvec: B PA_Routine /* 0x0c prefetch abort vector */
dabtvec: B DA_Routine /* 0x10 data abort vector */
rsvdvec: B rsvdvec /* 0x14 reserved (not used by XSCALE) */
irqvec: B IRQ_Routine /* 0x18 interrupt vector */
fiqvec: B FIQ_Routine /* 0x1c fast interrupt vector */

Reset_Handler:
/* Startup-Code der Applikation */

Initialisation supplémentaire des registres CPU

Version 3.1, juin 2008 Page 141


Informtique 3 Le démarrage d’un programme C

Les registres les plus importants du système sont initialisés par le boot loader. Des registres supplémentaires
peuvent être initialisés à cet endroit, comme par exemple la vitesse de la CPU etc.

Initialisation du la pile
Le code de démarrage de l’application doit initialiser les piles (stack) pour les différents modes (Superviseur,
IRQ, FIQ etc.). En particulier, les pointeurs de piles doivent adresser les espaces mémoire, qui ont été réservés
pour ces piles.

La taille de chaque pile est définie dans le fichier crt0.s de l’environnement de développement CARME. Par
exemple pour le mode FIQ :
.global FIQ_STACK_SIZE
.set FIQ_STACK_SIZE, 0x00000200 @ stack size for FIQ mode

Les zones de mémoire des différentes piles sont définies dans le fichier « ldscript_ram », dont voici un
aperçu :
...
. = ALIGN(4);
_irq_stack_top_address = .; @ IRQ-Stack top address
. += FIQ_STACK_SIZE; @ reserver FIQ stack size
. = ALIGN(4);
_fiq_stack_top_address = .; @ FIQ-Stack top address
...

Les pointeurs de piles sont initialisés dans le fichier crt0.s. Par exemple pour la pile FIQ, cela est définie de la
manière suivante :
LDR r0, =_fiq_stack_top_address @ load FIQ stack top address
MSR CPSR_c, #MODE_FIQ|I_BIT|F_BIT @ switch to FIQ mode, interrupts disabled
MOV sp, r0 @ load stack-pointer with stack address

Initialisation des variables globale initialisées


Les variables globales peuvent être initialisées en C, exemple:

static int myInt = 5;

Es ce que vous vous être déjà poser la question suivante : comment cette variable est elle initialisée ? Cette
instruction n’est exécutée par aucune fonction durant tout le déroulement du programme. Cette initialisation est
par conséquent une tâche supplémentaire du code de démarrage, qui est réalisée par un processus appelé « le
traitement ROM » (ROM-Processing).

Le graphique suivant illustre l’initialisation des variables globales :

RAM ROM/Flash
_data
.data
/* variable globale
à initialiser */
static int myInt = 5;

_edata
_etext
Valeur d’initialisation

Figure 100 : L’initialisation des variables globales

Version 3.1, juin 2008 Page 142


Informtique 3 Le démarrage d’un programme C

Le code de démarrage copie les valeurs d’initialisation des variables globales, depuis le flash dans la RAM. Cela
peut être programmé de la manière suivante :
/* copy .data section, ininialized variables */
LDR r1, =_etext
LDR r2, =_data
LDR r3, =_edata
cpydata_loop:
CMP r2, r3
LDR LO r0, [r1], #4
STRLO r0, [r2], #4
BLO cpydata_loop

_etext est l’adresse de départ de la zone de la flash, qui contient les valeurs d’initialisation. _data et
_edata désignent respectivement le début et la fin de la zone .data, qui contient les variables globales à
initialiser. _etext, _data et _edata sont définies dans le fichier ldscript_ram.

Remarque : Lorsque vous travaillez avec le débuggeur, vous chargez le programme dans la RAM, à travers son
interface. Dans ce cas, le débuggeur initialise automatiquement les variables globales. Les systèmes, prêts pour
la commercialisation, ne contiennent plus de débuggeur pour réaliser cette initialisation. Dans ce cas, il faut
absolument utiliser le code de démarrage.

Mise à zéro des variables non initialisées


Les données non initialisées et la pile sont déposées dans la section .bss. Toutes ces variables sont initialisées
avec 0. Le code est identique à celui pour l’initialisation des variables :
/* Clear .bss section (uninitialized data, stack) */
MOV r0, #0
LDR r1, =_bss_start
LDR r2, =_bss_end
zerobss_loop:
CMP r1, r2
STRLO r0, [r1], #4
BLO zerobss_loop

Initialisation du paquet de support de la platine


Le paquet de support de la platine (Board-Support-Package abrégé par BSP) initialise les composants hardware
de la périphérie.

10.5 Le programme principale


Les applications simples ne nécessitent par de systèmes d’exploitation temps réel (Real Time Operating System
abrégé par RTOS). Le programme principal peut alors posséder la structure suivante :

Dans une première étape, il faut initialiser l’application :


• Les composants hardware de la périphérie, à l’aide de leurs registres de configuration
• Les données : les variables, les structures dynamiques etc.

L’initialisation du hardware peut être critique en temps lorsque, par exemple, les sorties du processeur doivent
être rapidement fixés à des niveaux prédéfinis (Exemple : contrôle de moteur). Cette initialisation doit
éventuellement être réalisée dans le code de démarrage ou de façon hardware.

Dans uns deuxième temps les fonctions des applications sont appelées de façon cyclique, à l’aide d’une boucle
infinie.

Il en résulte le diagramme de « Nassi-Schneidemann » suivant pour le programme principale :

Version 3.1, juin 2008 Page 143


Informtique 3 Le démarrage d’un programme C

=
Initialisation du hardware

Initialisation des données

Boucle infinie

1er Fonction de l’application

2ième Fonction de l’application

...

Nième Fonction de l’application

Figure 101 : Programme principale

Le travail avec les interruptions :


Lorsque vous travaillez avec des interruptions (ISR), il faut faire attention de ne pas perdre trop de temps dans
leurs routines des services. En effet il est fortement recommandé de n’y réaliser que les tâches les plus
importantes, comme par exemple l’activation et la désactivation de drapeaux (flag). Le reste du travail peut ainsi
être effectué à l’aide de machine d’état (state events) en dehors de la routine de service.

Exemple :
Lorsque des bytes sont reçus à l’aide d’une interface sérielle, qui génère des interruptions, il faudrait uniquement
stocker les bytes dans un tampon. Le traitement de ces bytes devrait être réalisé en dehors de la routine de
service.

Un point très important est l’échange de données entre les routines de services et les fonctions de l’application.
Ici la communication n’est possible qu’à l’aide de variables globales (a moins que le système possède un RTOS).
Mais il faut toujours faire attention au fait que les routines de service peuvent sur écrire les données, sans que les
fonctions de l’application principale ne le remarque. Cela est surtout critique avec les données structurées. Par
exemple supposons que le programme possède un tampon de réception de 10 bytes, qui sont remplis par une
routine de service et qui sont lus par les fonctions de l’application principale. Admettons que durant la lecture du
cinquième byte, par une des fonctions de l’application principale, une interruption apparaît pour indiquer la
réception de 10 nouveaux bytes. La routine de service sur écrit alors les 10 bytes du tampon de réception. La
fonction de l’application principale va continuer sa lecture avec le sixième byte, comme si rien ne s’était produit.
Finalement l’application va poursuivre son travaille avec des données inconsistantes. Il faut donc introduire des
mécanismes, qui permettent der verrouiller ces opérations mutuellement. C'est-à-dire qu’aucune interruption de
réception ne devrait être générée pendant que les données sont ne train d’être lues. Le tout peut devenir très
complexe, lorsque plusieurs applications sont exécutées simultanément. Si cette complexité n’est pas maîtrisée
(cela est sûrement le cas, lorsque des nouvelles fonctionnalités, qui n’étaient pas planifiées ont été ajoutée par la
suite), le système va chuter immanquablement.

Version 3.1, juin 2008 Page 144


Informtique 3 Le démarrage d’un programme C

1er fonction de
l’application

2ième fonction
nième
fonction de l’application
de l’application

3ième fonction ISR


n-1ième
fonction de l’application
de l’application

4ième fonction
de l’application

Variables
globales

Figure 102 : Transfert de données entre les routines de service et les fonctions de l’application

Un RTOS n’est pas nécessaire pour les applications simples. Par contre, un RTOS est recommandé pour les
applications complexes, si les ressources hardware le permettent (CPU, taille de la mémoire etc.). Le module
d’approfondissement « système d’exploitation temps réel » traite ce sujet plus en détail.

Version 3.1, juin 2008 Page 145


Informtique 3 L’interface C et assembleur

11 L’interface C et assembleur

11.1 Introduction
Aujourd’hui la plupart des microcontrôleurs sont programmés à l’aide de langages de programmation évolués,
comme le C et le C++. Toutefois, les parties du code, qui sont critiques soit en temps ou en mémoire, sont
toujours définies en assembleur. Ce qui est particulièrement le cas pour les fonctionnalités suivantes :
• Accès optimal au hardware, spécialement pour les driver
• Les algorithmes, qui exigent une puissance de calcul élevée, afin de pouvoir utiliser la CPU de façon optimal
(unité de multiplication et d’accumulation)
• Les fonctions qui sont souvent traitées, afin d’augmenter la performance du système
• Accès aux registres de la CPU, qui ne sont pas accessibles en C

Dans ce cas une attention particulière doit être apportée sur l’interface C/assembleur. Cette interface dépend
technologiquement de la famille des microcontrôleurs et de leur environnement de développement. Les points
suivants sont à considérer :
• Appel des sous routine assembleur depuis les fonctions C et inversement
• Transmission de paramètres et retour de valeur
• Utilisation de variable C en assembleur et inversement
• Assembleur en ligne

Les mécanismes décrits dans se chapitres se réfèrent au PXA27x de XScale, au compilateur GNU (gcc) et à
l’assembleur (gas) de cette famille de processeur.

11.2 Les appels des sous routines assembleur


depuis le C
Les sous routines en assembleur peuvent être appelées à partir des fonctions C et, inversement, les fonctions C
peuvent être appelées depuis les sous routines en assembleur. Pour cela il faut que les noms soient identiques.
Remarque : Dans certain environnement de développement il faut ajouter un « _ » au début du nom symbolique
assembleur. Cela n’est cependant pas le cas avec les compilateurs GNU.

Exemple pour le code C :


extern int asmsub (int par1, int par2);

int cfunc (int par1, int par2){


return (par1 + par2);
}

void main(void)
{
...
res = asmsub(par1, par2);
...
}

Exemple pour le code assembleur :

Version 3.1, juin 2008 Page 146


Informtique 3 L’interface C et assembleur

.global asmsub @ gives symbol external linkage


.extern cfunc @ specify that cfunc is defined in some other source code file

asmsub: @ assembler subroutine


STR lr, [sp, #-4]! @ save return address on stack
...
BL cfunc @ call C-function
...
LDR pc, [sp], #4 @ return

11.3 Transmission de paramètres aux sous routines


assembleur
Le chapitre 8 « les sous routines » traite la transmission des paramètres selon le standard APCS (ARM Procedure
Call Standard). Ce standard doit être respecté si l’on veut programmer en combinant les langages de
programmation C et assembleur.
Ce standard peut être résumé de la manière suivante :
• Les quatre premiers paramètres sont transmis avec les registres r0 à r3, indépendamment du fait que l’on
appel une fonction C ou une sous routine en assembleur.
• Les paramètres suivants sont transmis à l’aide de la pile.
• Le résultat est retourné avec le registre r0.

11.4 Les registres utilisés par le compilateur


L’APCS spécifie également l’utilisation des registres pour le compilateur. Ces registres doivent donc être utilisés
de la même façon par le programmeur assembleur (voir également le chapitre 8) :
r13 / sp : pointeur de pile
r14 / lr : registre du relieur (link register)
r15 / pc : compteur de programme (program counter)

11.5 L’utilisation de variables en commun


Les variables globales peuvent également être utilisées en commun, dans les parties C et assembleur. Pour cela il
faut faire attention, comme ce fut le cas pour les sous routines et les fonctions, que leurs noms soient identiques
en C comme en assembleur. Ces variables en commun peuvent être définies soit dans la partie C ou dans celle en
assembleur.

L’exemple suivant contient une variable globale définie en C (c_var) et une variable globale définie en
assembleur (asm_var) ainsi que les accès sur ces dernières :

Code C :
/* global variables */
int c_var; // reserve memory for word-variable
extern int asm_var; // specified in assembler source

void ctest_var(void){
...
asm_var = 0x22; // modify assembler variable
c_var = 0x55; // modify C variable
}

Code assembleur :

Version 3.1, juin 2008 Page 147


Informtique 3 L’interface C et assembleur

.global asm_var @ give asm_var external linkage


.extern c_var @ specified in C source
...

.data
asm_var: .space 4, 0x11 @ global asm_var, initialized with 0x11111111

.text
asmtest_var:
STR lr, [sp, #-4] @ save return address on stack
LDR r0, =c_var @ r0 holds address of variable c_var
MOV r1, #0x55 @ r1 holds value to write to c_var
STR r1, [r0] @ c_var = 0x55
LDR r0, =asm_var @ r0 holds address of variable asm_var
MOV r1, #0x11 @ r1 holds value to write to asm_var
STR r1, [r0] @ asm_var = 0x11
LDR pc, [sp], #4 @ return

11.6 L’assembleur en ligne


L’assembleur en ligne permet d’insérer des lignes en assembleur directement dans le code C. Il est ainsi possible
d’exécuter les instructions ARM, qui ne sont pas soutenues par le compilateur C. Où le contenu des registres, qui
ne sont pas accessible en C, peut être modifié ; comme par exemple tous les registres de la CPU et du
coprocesseur.
L’utilisation de l’assembleur en ligne peut aider de temps en temps. Toutefois, des effets de bord non souhaités
peuvent apparaître ! Il faut par conséquent faire très attention.
L’instruction (statement) « asm » est mise à disposition par le compilateur GNU gcc pour insérer de
l’assembleur en ligne dans le code C. Cette instruction n’est pas définie par le standard ANSI-C. Par conséquent
cette dernière dépend de l’environnement de développement. Les autres compilateurs utilisent des expressions
comme ASM, __asm ou ASMLINE.

L’utilisation générale de l’instruction asm est la suivante :


asm volatile (code : output operand list : inpup operand list : clobber list);

Exemple :
asm volatile ("AND %0, %1, #0xFF" : "=r" (result) : "r" (value));

Cette instruction peut paraître un peu compliquée. « volatile » est obligatoire, afin que le compilateur C
n’optimise pas l’instruction asm. L’instruction en soit est composée de quatre colonnes :
1. Le code contient les instructions assembleur, qui ont été définies sous forme de chaîne de caractère :
"AND %0, %1, #0xFF"
2. Output operand list : Les opérandes de sortie, séparées par des virgules, peuvent être définies dans la liste
des opérandes de sortie : "=r" (result). Cette liste des opérandes permet d’accéder également aux
variables C. %0 se réfère au premier élément de la liste. "=r" Signifie que le compilateur peut utiliser un
registre, mais uniquement en mode écriture « write only ».
3. Input operand list : Les opérandes d’entrée, séparées par des virgules, peuvent être définies dans la liste
des opérandes d’entrée : "r" (value). Du fait que ce dernier est le deuxième opérande, %1 permet
d’accéder à la variable value. "r" signifie que le compilateur doit utiliser encore un registre
quelconque.
4. Clobber list : Cette liste informe le compilateur sur les registres, mémoire ou de statut, qui doivent être
modifiés par le code assembleur. La liste clobber est vide dans l’exemple de ci-dessus.

L’exemple le plus simple : Une seule ligne d’assembleur est programmé, sans opérande et sans liste clobber :
asm volatile ("MOV r0, r0"); // NOP (No Operation)

Lorsque plusieurs instructions assembleur peuvent être programmées de la manière suivante :

Version 3.1, juin 2008 Page 148


Informtique 3 L’interface C et assembleur

asm volatile (
"MOV r0, r0" "\n\t"
"MOV r0, r0"
);
"\n\t" permet d’augmenter la lisibilité du code assembleur, qui est généré par le compilateur.

Si une variable C doit être utilisée en tant que paramètre d’entrée, elle peut être définie dans une liste des
opérandes d’entrée. L’exemple suivant ne contient pas de paramètres de sortie, la liste des opérandes de sortie est
ainsi vide. L’exemple illustre également l’accès au registre CPSR, ce qui ne serait pas possible en C :
asm volatile("MSR CPSR, %0" : : "r" (status)); // load CPSR register with value in status

Le compilateur génère à partir de cette instruction ASM le code objet (désassemblé) suivant :
LDR r3, =status
LDR r3, [r3]
MSR CPSR, r3

La liste des opérandes d’entrée spécifie l’état "r" pour la variable status. Le compilateur peut ainsi choisir le
un registre quelconque pour exécuter l’instruction. Le registre r3 a été choisi dans l’exemple de ci-dessus.

Il faut informer le compilateur, lorsque l’instruction assembleur change le contenu d’un registre. Le compilateur
ne possède pas les moyens pour remarquer cela. Il dépend donc de cette information, afin qu’il n’y ait pas de
problèmes avec ses propres registres. La déclaration des registres, qui sont modifiés par l’instruction assembleur,
s’effectue dans la liste clobber :
asm volatile("MOV r1, r0" : : : "r1"); // register r1 modified

Finalement encore quelques mots concernant l’exemple du début de ce chapitre :


asm volatile("AND %0, %1, #0xFF" : "=r" (result) : "r" (value));

Ce code possède un paramètre d’entrée, qui est la variable value. value est combiné de façon AND avec la
valeur #0xFF, c'est-à-dire que les 3 bytes de poids plus fort sont effacés. Le résultat de l’opération est déposé
dans la variable result. L’exemple illustre comment l’instruction assembleur peut être étendue et complétée
avec des variables C. Cela n’est par conséquent plus une instruction assembleur pure, mais plutôt un mélange de
C et d’assembleur. Le compilateur génère à partir de cette instruction ASM le code objet (désassemblé) suivant :
LDR r3, =value
LDR r3, [r3]
AND r2, r3, #255
LDR r3, =result
STR r2, [r3]

Du fait que ce code a été généré par le compilateur, il ne faut pas déclarer les registre r2 et r3, qui ont été
modifiées, dans la liste clobber.

Version 3.1, juin 2008 Page 149


Informtique 3 L’adressage des registres en C

12 L’adressage des registres en C


Dans la programmation proche du hardware, il est souvent nécessaire de déposer des variables à des adresses
bien définies (comme par exemple les registres des microcontrôleur ou des éléments périphériques). Pour cela il
existe les techniques suivantes :
a) Avec #define selon ANSI-C
b) A l’aide de section absolue
c) A l’aide de mots clés spécifiques fournis par le fabriquant

12.1 L’adressage avec #define


Cette variante a été introduite dans le module « Informatique 2 » et est motionné dans ce cours pour des raisons
d’intégrité. C’est la seule méthode pour définir des variables à des adresses fixes, selon le standard ANSI-C.

1) Les variables sont définies de la manière suivante :


// für eine 8-bit Variable auf der Adresse 0x1000
#define reg_8 *((volatile unsigned char *) 0x1000)

// für eine 16-bit Variable auf der Adresse 0x2000


#define reg_16 *((volatile unsigned short *) 0x2000)

// für eine 32-bit Variable auf der Adresse 0x3000


#define reg_32 *((volatile unsigned long *) 0x3000)

2) L’accès aux variables s’effectue de la manière suivante :


reg_16 = 0x1234;

12.2 La définition de sections absolues


Les environnements de développement permettent de définir des nouvelles sections, qui possèdent leur propre
adresse.
Le compilateur GNU met à disposition le mot clé « __attribute__ », qui permet de spécifier des attributs
pour les variables. Les attributs sont définis entre parenthèses doubles après le mot clé « __attribute__ »,
et la section avec le mot clé « section ».

Exemple : Il faut définir une variable « led », qui permet d’accéder à la ligne de LED sut le kit de
développement CARME. Ces LED sont accessible à l’adresse 0x0C003000.

char led __attribute__ ((section (".LED"))) = 0;



led = 0x55;

La première ligne du code C défini une variable led de 8 bits. L’expression


« __attribute__ ((section (".LED"))) » indique que la variable led doit se trouver dans la
section ".LED". L’instruction « led = 0x55; » permet d’afficher un échantillon de bit sur les LED.
La section .LED doit être encore définie dans le script du relieur « ldscript_ram ». Pour cela deux étapes
sont nécessaires.
D’abord il faut spécifier les zones mémoire du kit de développement CARME IO1 :
#pragma separate myabsvar
MOMORY
{
flash : ORIGIN = 0x00000000, LENGTH = 0x02000000 /* 32 MB FLASH */
ram : ORIGIN = 0xA0000000, LENGTH = 0x02000000 /* 64 MB RAM */
carmeIO1 : ORIGIN = 0x0C003000, LENGTH = 0x0410 /* CARME IO1 */
}

Version 3.1, juin 2008 Page 150


Informtique 3 L’adressage des registres en C

Ensuite il faut spécifier la section .LED :


.CARME_IO1 :
{
. = ALIGN(4); /* next 32-bit boundary */
_carmeio1 = .; /* defines a symbol for start of CARME IO1 */
*(.LED) /* LED section for CARME IO1 */
. += 0x1FF /* LED address is 0x0C003000 to 0x0C0031FF */
*(.SWITCH) /* Switch section for CARME IO1 */
. += 0x1FF /* Switch address is 0x0C003200 to 0x0C0033FF */
*(.PIO) /* PIO section for CARME IO1 */
. += 0x10 /* PIO address is 0x0C003400 to 0xC003410 */
} >carmeIO1

L’exemple ci-dessus du manuscrit du relieur montre, comment les registres de configuration des différentes
entrées et sorties du kit de développement CARNEIO1 peuvent être rassemblés en sections.

12.3 L’utilisation de mots clés spécifiques du


fabriquant
Certain compilateur mettent à disposition des mots clés spécifiques, pour déposer les variables à des adresses
fixes, comme par exemple « _at_ » ou « _at ».

Exemple :
volatile unsigned short reg1 _at 0x1000;

Le compilateur GNU ne propose pas de tel mot clé.

Version 3.1, juin 2008 Page 151


Informtique 3 Annexe A: Stockage des nombres

Annexe A: Stockage des nombres


Les grandeurs suivantes sont mises à disposition pour stocker les nombres :

Bit (1 Bit): Domaine de représentation 0..1


0

Nibble (4 Bit): Domaine de représentation 0...15


3 0

Byte (8 Bit): Domaine de représentation 0..255


7 0

Halfword (16 Bit): Domaine de représentation 0…65535


15 0

Word (32 Bit): Domaine de représentation 0…429496729


31 0

Le bit le plus faible d’un nombre binaire (byte, demi mot et mot) est qualifié de LSB (Least Significant Bit). Le
bit le plus fort est le MSB (Most Significant Bit).

Un demi mot est composé de deux bytes : le « lower Byte » (les bits 0 à 7) et le « upper Byte » (les bits 8 à 15).

Un mot est composé de deux demi mots : « lower Halfword » (bit 0 bis 15) et le « upper Halfword » (bit 16 bis
31).

Version 3.1, juin 2008 Page 152


Informtique 3 Annexe B: Les format des nombres

Annexe B: Les format des nombres

Complément à deux
Le complément à deux permet de représenter les nombres négatifs dans le système binaire. Des symbole
supplémentaire comme + et – ne sont ainsi plus nécessaire.
Dans le complément à deux, les nombres positifs sont représentés avec un premier bit 0 (le bit de poids le plus
fort qui est également appelé le bit de signe). Les valeurs négatives sont représentées avec un premier bit 1. Ces
dernières sont codées de la manières suivante : tous les bits du nombre positif sont d’abord inversés et la valeur 1
est ensuite additionné au résultat.

Exemple :
+4(10) = 00000100
-4(10) = 11111011 + 1 = 11111100
-1(10) = 11111111
127(10) = 01111111
-128(10) = 10000000

Le complément est un système de nombres signés, qui ne possède qu’une seule représentation de la valeur nulle.
Les additions et les soustractions peuvent être ainsi être effectuées sans dissociation de cas. Il n’existe qu’une
seule représentation de la valeur nulle, si l’on admet que les bits, résultants des dépassements de capacité, sont
tronqués durant les opérations.

Par exemple, l’opération :


-4 + 3 = -1
sera calculé de la manière suivante :
11111100 + 00000011 = 11111111;

Nombre à virgule flottante


Les nombres réels sont représentés dans les ordinateurs à l’aide de nombres à virgule flottante (Floating Point)
avec le format IEEE. Le nombre à virgule flottante Z est ainsi représenté avec sa mantisse (M) et sont exposant
(P) part rapport à la base 2.

Il existe plusieurs possibilités pour stocker la mantisse et l’exposant dans la mémoire. Par exemple avec la
précision simple (32 bits) ou double (64 bits). Ce chapitre se concentre uniquement sur le format précision
simple. Ce dernier est stocké dans la mémoire de la manière suivante :

31 30 23 22 0
V E + 127 M
1 bit 8 bits 23 bits

Représentation Description Domaine des nombres


V Bit de signe 0: positif, 1: négatif
E Exposant -126 bis +127
M Mantisse 1,111..111 bis 1,999...999
Tabelle 2: Précision simple de nombres à virgule flottante

Seule la partie fractionnaire de la mantisse est stockée dans la mémoire (hidden bit). Il en résulte la formule
suivante pour la construction des nombres à virgule flottante :

Z = (-1)V M * 2E-127

Version 3.1, juin 2008 Page 153


Informtique 3 Annexe C: La documentation

Annexe C: La documentation
Nom Edition / Auteur Référence
ARM Architecture Reference Manual, ARM Limited [1]
ARM DDI 0100E
Intel PXA27x Processor Family Developer's Manual Intel [2]
Description détaillée des composants périphériques du chip, 1246 pages
Intel PXA27x Processor Core Developer's Manual Intel [3]
Registres du coprocesseur, cache des instructions et des données, les
spécialités du processeur, 220 pages
Intel PXA270 Electrical, Mechanical and Thermal Specification Intel [4]
Timings, pin out … 128 pages
Intel PXA27x Processor Family Memory Subsystem Intel [5]
Flash, LPSDRAM, 138 pages
Intel XScale Microarchitecture Intel [6]
Technical Summary, 14 pages
Intel PXA27x Processor Family Design Guide Intel [7]
Intel PXA27x Processor Developer's Kit Intel [8]
Tableau 52 : Documentation

Titre Edition / Auteur Référence


ARM System Developmer's Guide Sloss / Symes / Wright [10]
ISBN: 978-1-55860-874-0 Morgan Kaufman Verlag
ARM System on Chip Architecture Steve Furber [11]
ISBN: 0-201-67519-6 Addison Wesley
Tableau 53 : La littérature

Nom Edition / Auteur Référence


GNU Assembler GNU [20]
http://www.gnu.org/software/binutils/manual/gas-
2.9.1/html_mono/as.html
GNU Compiler GNU [21]
http://gcc.gnu.org/onlinedocs/
Tableau 54 : Les liens Internet

Version 3.1, juin 2008 Page 154


Informtique 3 Annexe D: Tableau des valeurs ASCII

Annexe D: Tableau des valeurs ASCII


Caract. Valeur Hex. Caract. Valeur Hex. Caract. Valeur Hex. Caract. Valeur Hex.
NUL 0 0x00 SOH 1 0x01 STX 2 0x02 ETX 3 0x03
EOT 4 0x04 ENQ 5 0x05 ACK 6 0x06 BEL 7 0x07
BS 8 0x08 TAB 9 0x09 LF 10 0x0A VT 11 0x0B
FF 12 0x0C CR 13 0x0D SO 14 0x0E SI 15 0x0F
DLE 16 0x10 DC1 17 0x11 DC2 18 0x12 DC3 19 0x13
DC4 20 0x14 NAK 21 0x15 SYN 22 0x16 ETB 23 0x17
CAN 24 0x18 EM 25 0x19 SUB 26 0x1A ESC 27 0x1B
FS 28 0x1C GS 29 0x1D RS 30 0x1E US 31 0x1F
Leerz. 32 0x20 ! 33 0x21 " 34 0x22 # 35 0x23
$ 36 0x24 % 37 0x25 & 38 0x26 ' 39 0x27
( 40 0x28 ) 41 0x29 * 42 0x2A + 43 0x2B
, 44 0x2C - 45 0x2D . 46 0x2E / 47 0x2F
0 48 0x30 1 49 0x31 2 50 0x32 3 51 0x33
4 52 0x34 5 53 0x35 6 54 0x36 7 55 0x37
8 56 0x38 9 57 0x39 : 58 0x3A ; 59 0x3B
< 60 0x3C = 61 0x3D > 62 0x3E ? 63 0x3F
@ 64 0x40 A 65 0x41 B 66 0x42 C 67 0x43
D 68 0x44 E 69 0x45 F 70 0x46 G 71 0x47
H 72 0x48 I 73 0x49 J 74 0x4A K 75 0x4B
L 76 0x4C M 77 0x4D N 78 0x4E O 79 0x4F
P 80 0x50 Q 81 0x51 R 82 0x52 S 83 0x53
T 84 0x54 U 85 0x55 V 86 0x56 W 87 0x57
X 88 0x58 Y 89 0x59 Z 90 0x5A [ 91 0x5B
\ 92 0x5C ] 93 0x5D ^ 94 0x5E _ 95 0x5F
` 96 0x60 a 97 0x61 b 98 0x62 c 99 0x63
d 100 0x64 e 101 0x65 f 102 0x66 g 103 0x67
h 104 0x68 i 105 0x69 j 106 0x6A k 107 0x6B
l 108 0x6C m 109 0x6D n 110 0x6E o 111 0x6F
p 112 0x70 q 113 0x71 r 114 0x72 s 115 0x73
t 116 0x74 u 117 0x75 v 118 0x76 w 119 0x77
x 120 0x78 y 121 0x79 z 122 0x7A { 123 0x7B
| 124 0x7C } 125 0x7D ~ 126 0x7E DEL 127 0x7F
Tableau 55 : Tableau des valeurs ASCII

Version 3.1, juin 2008 Page 155


Informtique 3 Index

Index
boucle d’itération............... 129
. 8
boucle do while ............ 134
.2byte ............................... 93 8051......................................28 boucle for ........................ 134
.4byte ............................... 93 boucle while ................... 133
A
.align ............................... 90 Branch Target Buffer........... 34
.arm .................................... 89 abt.........................................39 break point........................... 87
.ascii ............................... 92 Acknowledge bit ..................24 BSP.................................... 146
.asciz ............................... 92 ADC ................................78, 79 bus d’adresse ................... 6, 46
.asm .................................... 57 ADD ................................78, 79 bus de contrôle....................... 6
.balign ............................. 91 ADR ....................................102 bus de données................. 6, 46
adressage des registres .......153 BX ........................................ 84
.bin .................................... 58
adresse de retour.................106 byte .............................. 43, 155
.bss .................................... 95
adresse physique...................14
.byte ................................. 93 C
adresse virtuelle....................14
.data ................................. 95 call by reference ................ 110
ALU .................................5, 36
.elf .................................... 58 amplificateur de sortie ..........18 call by value....................... 110
.else ............................... 100 AND ................................78, 81 callee.................................. 105
.end .................................... 99 anneau de tampons .............140 caller .................................. 105
.endif ............................. 100 APCS..........107, 110, 112, 150 caractérisiques AC............... 12
.endm ............................... 101 architecture.............................3 caractérisiques DC............... 12
.equ .................................... 95 architecture ARM.................30 carry..................................... 42
.extern ............................. 90 architecture de Harvard ..........4 case mémoire ....................... 10
.global ............................. 90 architecture de stockage .......11 cercle de nombre.................. 42
.hword ............................... 93 architecture de von Neumann.3 chaîne de caractère ............ 138
.if .................................... 100 architecture RISC .................30 champ des étiquettes............ 51
.ifndef ........................... 101 argument.............................113 chip select .............................. 8
arithmétique des entiers........78 choix parmi une liste............ 62
.include .......................... 94
ARM.....................................30 CISC .................................... 27
.irp .................................. 104
ARMV5TE...........................60 clobber list ......................... 151
.lis .................................... 57 CLZ ...................................... 87
array ...................................136
.macro ............................. 101 ascending............................107 CMN ................................ 78, 79
.map .................................... 58 asm ....................................151 CMP ................................ 78, 79
.o......................................... 57 ASR ......................................67 code d’opération .................. 62
.org .................................... 95 assemblage conditionnel.....100 code de condition................. 63
.p2align .......................... 92 assembleur............................57 code de démarrage............. 144
.rept ............................... 103 assembleur en ligne ............151 code machine ................. 49, 57
.s......................................... 57 assignation des pins..............12 code récursif ...................... 106
.section ............ 95, 96, 153 coeur .................................... 38
B cœur d’exécution ................. 35
.section absolue .................. 153
.set .................................... 95 B 84 commentaire ........................ 53
.space ............................... 94 Banked Register ...................41 compilateur .......................... 57
.text ................................. 95 Barrel Schifter ................36, 67 complément à deux.............. 55
.thumb ............................... 89 baud rate ...............................20 complément à un.................. 55
.word ................................. 93 BIC ................................78, 81 compteur de program........... 41
big endian .............................43 compteur de programme 5, 113
_ binaire...................................55 condition.............................. 81
bit .......................................155 condition d’arrêt .................. 24
__attribute__ ............ 153
bit C......................................42 condition de démarrage ....... 24
_at .................................... 154
bit d’état ...............................41 Condition Flags ................... 41
_at_ .................................. 154 constante........................ 53, 63
bit F ....................................119
= bit I .....................................119 contexte ............................. 128
bit N......................................42 Contitional Execution .......... 42
= 95 bit V......................................42 control bus ............................. 6
1 bit Z ......................................42 contrôleur d’interruption...... 38
BKPT ....................................87 contrôleur d’interrutpion.... 124
1 of X Decoder....................... 8 BL .................................84, 106 convertisseur A/D................ 26
6 BLX ......................................84 convertisseur D/A................ 26
bootloader...........................143 coprocesseur ........................ 65
68HCxx................................ 28 boucle .................................129 Coprocessor ......................... 35

Version 3.1, juin 2008 Page 156


Informtique 3 Index

Core Memory Bus................ 35 for ....................................135 JTAG ................................... 35


counter ................................. 25 FPU ........................................5 jump table .......................... 132
CPSR ............................ 41, 119 frame pointer ..............113, 150
L
CPU........................................ 4 frames...................................15
CPU32.................................. 28 full ......................................107 langage de programmation
Cross Assembleur ................ 57 évolué ...................... 49, 149
G
crt0 .................................. 144 last in, first out................... 107
CS........................................... 8 gestion de projet ...................58 LCD Panel ........................... 39
gestionnaire de consommation LDC ................................ 66, 76
D
..........................................38 LDM ................................ 66, 72
Data Abord......................... 116 GPIO ....................................39 LDR ........................... 66, 68
Data Cache ........................... 34 LDR B............................... 69
H
Debug................................... 35 LDR H............................... 69
débuggeur............................. 58 halfword .......................43, 155 LDR SB ............................ 69
Decode ............................. 5, 37 Header ..................................51 LDR SH ............................ 69
décodeur d’adresse................. 8 hexadécimal..........................93 Link Register ....................... 41
déroulement d’une requête hierarchie des composants de Linker .................................. 58
d’interruption ................. 123 stockage............................13 Linkmap............................... 99
descending.......................... 107 list file.................................. 57
I
directive de l’assembleur ..... 88 listing de l’assembleur ......... 57
directive de programmation . 50 I2C ........................................23 little endian .......................... 43
disabled .............................. 119 ICLR ..................................118 localisateur........................... 58
dispositif de commande ......... 5 IDE .......................................55 Locator................................. 58
DMA .............................. 17, 39 if .......................................130 logique ................................. 55
DMMU................................. 34 IMMU ..................................34 lower byte .......................... 155
do while ........................ 134 indexation.............................62 LSL ...................................... 67
documentation...................... 12 initialisation des variables ..145 LSR ...................................... 67
DRAM ................................. 10 input operand list................151
DSP .................................. 4, 27 instruction.........................1, 51 M
instruction ARM...................62 macro instruction ............... 101
E
Instruction Cache..................34 main ................................. 144
éditeur .................................. 56 instruction conditionnelle .....63
manipulation des bits ........... 81
EEPROM ............................... 9 instruction d’état...................75
manuscrit de reliage............. 97
empty ................................. 107 instruction de décalage .........82
masquage des interruptions 119
enabled ............................... 119 instruction de transport entres
MC683xx............................. 28
entrée et sortie digitale ......... 19 registres ............................66
MCR ................................ 66, 76
environnement de instruction logique................81
développement ................. 55 mémoire cache..................... 13
instruction non définie........116
mémoire de masse ............... 14
EOR ................................ 78, 81 instruction pour la pile..........74
mémoire de travail............... 13
EPROM.................................. 9 instruction pour le
mémoire des données............. 3
équation logique..................... 8 coprocesseur .....................76
mémoire non volatile ............. 9
ET......................................... 81 Instruction Unit ......................5
mémoire programme.............. 3
état du processeur................. 41 interface C/assembleur .......149
mémoire volatile.................. 10
évènement .......................... 116 interface clavier ....................39
Memory Controller .............. 39
exception ............................ 116 interface du bus ......................5
memory map.................... 7, 44
Exception Handler...... 116, 121 interface sériel ................20, 39
memory matrix .................... 10
Execute............................. 5, 37 Interrupt Controller ............124
microcontrôleur ................... 27
exécution conditionnelle ...... 42 Interrupt Mask ......................41
microprocesseur................... 27
Execution Core..................... 35 Interrupt Service Routine ...116
MIMD.................................... 2
Interrupt-Controller ..............38
F Mini D-Cache ...................... 34
interruption.........116, 118, 147
MIPS.................................... 29
famille de microcontrôleur... 27 interruption hardware .........118
MISD ..................................... 2
famille de processeur ARM . 33 interruption software ...86, 116,
MISO ................................... 22
FeRAM ................................ 10 118
intructions de transfert de MLA ................................ 78, 79
Fetch................................. 5, 37
données.............................66 MMU ............................. 14, 34
fichier assembleur ................ 50
IRQ...............................39, 116 mnemonics........................... 51
fichier de mappage ............... 58
ISR .............................116, 147 mode d’adressage ................ 70
fichier elf.............................. 58
mode d’utilisation................ 41
fichier objet .......................... 57
J mode de fonctionnement ..... 39
FIQ ............................... 39, 116
jeu d’instruction..............52, 60 mode privilégié.................... 39
FLASH................................. 10
jeu d’instruction Thumb .......64 modèle de stockage.............. 43
FLOPS ................................. 29
modulo................................. 55

Version 3.1, juin 2008 Page 157


Informtique 3 Index

MOSI ................................... 22 pseudo instruction ................88 SMUL ............................. 78, 79


mot clé................................ 154 push ....................................107 SMULL ................................. 79
MOV ...................................... 66 PWM ....................................39 SMULW ........................... 78, 79
MRAM................................. 10 source d’erreurs ................. 114
Q
MRC ................................ 66, 76 sous programme................. 105
MRS ................................ 66, 75 QADD ..............................78, 79 sous routine........................ 105
MSP430 ............................... 28 QADDD ..................................78 SPI ....................................... 21
MSR ................................ 66, 75 QDADD ..................................79 SRAM.................................. 10
MUL ................................ 78, 79 QDSUB ..................................79 stack........................... 106, 139
Multiply-Accumulate ........... 35 QDSUM ..................................78 stack pointer..........41, 107, 150
MVN ...................................... 66 QSUB ..............................78, 79 startup .......................... 144
queue de tampons ...............140 startup code........................ 144
N STC ................................ 66, 76
R
negative................................ 42 STM ................................ 66, 72
nibble ................................. 155 RAM.....................................10 STR................................ 66, 68
nom de registre..................... 62 ramification ........................129 STRB ................................... 69
Nonnested Interrupt Handler ramification multiple ..........131 STRD ................................... 69
....................................... 127 ramification simple.............130 STRH ................................... 69
NOT ...................................... 81 Real Time Clock...................39 string.................................. 138
nul ...................................... 138 registre........................5, 13, 40 structure ............................. 138
registre de reliage .41, 106, 113 structure de contrôle .......... 129
O registre fantôme....................41 structure de données .......... 136
open drain............................. 19 registre scratch....................113 structure de répétition ........ 102
opérande......................... 36, 52 relieur ...................................58 SUB ................................ 78, 79
opérateur .............................. 54 reset ............................116, 143 super pipeline....................... 36
opérateur assembleur.......... 100 ressource hardware.............148 svc........................................ 39
opération .............................. 51 retour de sous routine .........106 SWI...................................... 86
opération de décalage..... 63, 67 RISC.....................................27 switch............................. 132
opération pop ..................... 140 ROM.......................................9 SWP ................................ 66, 72
opération push.................... 139 ROM-Processing ................145
SWPB ................................... 72
organisation de la mémoire .. 12 ROR ......................................67
symbole ............................... 53
ORR ................................ 78, 81 rotate.....................................82 syntaxe................................. 62
OTP........................................ 9 RRX ......................................67 syntaxe de l'assembleur ....... 51
OU........................................ 81 RS232...................................20 sys........................................ 39
output operand list.............. 151 RSB ................................78, 79 système d’exploitation temps
Overflow .............................. 42 RSC ................................78, 79 réel ................................. 148
RTOS .................................146 système de bus....................... 6
P
S système faiblement couplé..... 2
pages .................................... 15 système fortement couplé ...... 2
paramètre............................ 111 saut de programme ...............83
périphérie ............................. 18 saut de programme absolu....83 T
PIC ....................................... 28 saut de programme conditionel table de vérité ...................... 12
pile ............................. 106, 139 ..........................................82 Tableau .............................. 136
pipeline................................. 36 saut de programme Tableau de page................... 15
plan de mémoire............... 7, 44 inconditionel.....................82 Tableau de saut .................. 132
point d’arrêt.......................... 87 saut de programme relatif.....83 Tableau des vecteurs
pointeur de pile ... 41, 107, 113, sauvegard des registres.......110 d’exeption ...................... 120
150 SBC ......................................79 Tableau multidimensionnel 137
pointeur de trame ............... 150 Schifter .................................37 taille de la mémoire ............. 12
pop ..................................... 107 SD Memory Card .................39 TDMI................................... 33
portable ................................ 49 SDRAM................................10 tension du bus ........................ 7
post indexation ..................... 70 séquence d’instructions ......129 TEQ ...................................... 79
Power-Management ............. 38 set de registre........................40 Timer ............................. 25, 39
pré indexation....................... 70 shift.......................................82 TLB ..................................... 16
Prefetch Abord ................... 116 Sign Extend ..........................43 totem pole ............................ 19
principe des contributions .. 110 signal PWM..........................25 Trace Buffer......................... 35
priorité des interruptions .... 117 signé .....................................55 traitement d’exception ....... 116
priorité des opérateurs.......... 55 SIMD......................................1 transfert des paramètres ..... 110
processus de démarrage ..... 143 SISD .......................................1 transmission des paramètres
Program Counter ...... 5, 41, 150 SMLA ..............................78, 79 ............................... 112, 150
programme principale ........ 146 SMLAL ............................78, 79 tri state ................................. 19
pseudo code.......................... 49 SMLAW ............................78, 79 TST ...................................... 79

Version 3.1, juin 2008 Page 158


Informtique 3 Index

U V word............................. 43, 155


Write Back........................... 37
UMLAL ................................. 79 v5TE.....................................32
Write Buffer......................... 34
UMLULL ............................... 78 variable globale ..................150
UMULL ................................. 79 variable locale ....................113 X
und ....................................... 39 variable registre ..................113
XOR ...................................... 81
unité de calcul ........................ 5 vecteur d’exception ............120
vue d’ensemble des XScale ................................. 33
unité de contrôle..................... 5
upper byte........................... 155 instructions .......................65 Z
usr......................................... 39
W Zero ..................................... 42
while ................................133 zone mémoire ........................ 3

Version 3.1, juin 2008 Page 159

Вам также может понравиться