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 : Auteur : Version : Juin 2008 Dr E FIROUZI 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 Architecture d’un microordinateur standard Informatique 3 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 Single Instruction, Single Data Ordinateur séquentiel SIMD Single Instruction, Multiple Data Ordinateur vectoriel en pipeline MISD Multiple Instruction, Single Data Tableau systolique MIMD Multiple Instruction, Multiple Data 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 instruction : Single instruction veut dire, qu’une instruction est exécutée par cycle d’horloge. Single Data veut dire, qu’un jeu de donnée est traité par cycle d’horloge. 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. Version 3.1, juin 2008 t store C CPU load A1 load B1 C1 = A1 + B1 load A2 load B2 C2 = A2 + B2 store C1 store C2 CPU 1 CPU 2 t SIMD: Les ordinateurs SIMD permettent d’exécuter la même instruction sur plusieurs jeux de données. Ces derniers sont utilisés par exemple pour le traitement des images (JPEG, MPEG). Single Instruction veut dire, que tous les CPU exécutent la même instruction à un cycle d’horloge donné. Multiple Data veut dire, que chaque CPU traite un jeu de donnée différent. 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. load A load B C=A+B Page 1 MISD: Un seul jeu de donnée est traité simultanément par plusieurs CPU, avec des instructions différentes. Multiple Instruction veut dire, que chaque CPU exécute une instruction différentes. Single Data veut dire, que chaque CPU traite le même jeu de donnée. Les ordinateurs MISD ne sont presque plus utilisés aujourd’hui. MIMD: Aujourd’hui presque tous les ordinateurs multiprocesseurs se basent sur l’architecture MIMD. Multiple Instruction veut dire, que chaque CPU exécute une instruction différente par cycle d’horloge. Des programmes entiers ou des partitions de ces derniers (process, thread, task) sont souvent répartis entre les différents CPU. Multiple Data veut dire, que chaque CPU traite un jeu de données différent. load A1 load B1 C1 = A1 + B1 load A1 load B1 C2 = A1 * B1 store C1 store C2 CPU 1 CPU 2 load A1 load B1 C1 = A1 + B1 load D E = func1(D) F=D/2 store C1 func2() CPU 1 CPU 2 t Architecture d’un microordinateur standard t Informatique 3 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). Tous les CPU travaillent indépendamment. Mais ils sont avertis, lorsqu’un CPU accède à une autre zone de mémoire. L’accès à la mémoire doit être synchronisé. Car plusieurs CPU ne peuvent pas accéder simultanément à la mémoire. b) Les systèmes faiblement couplés (distributed memory) Plusieurs CPU communiquent à l’aide d’un 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. Ces systèmes peuvent être composés de plusieurs systèmes SISD, reliés par un réseau. Mémoire Bus CPU 1 CPU 2 CPU 3 Figure 1 : Les systèmes fortement couplés Réseau CPU 1 CPU 2 CPU 3 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. CPU CPU Mémoire Mémoire CPU CPU CPU CPU CPU CPU Réseaux CPU CPU Mémoire 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 CPU Bus pour les instructions et les données 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. Mémoire programme Mémoire des 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 Architecture d’un microordinateur standard Informatique 3 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. Bus des instructions Bus de données Mémoire du programme Mémoire des données 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 d’adresse Bus de contrôle Bus des données Interface du bus Register Program-Counter Bus interne Opérande 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 Architecture d’un microordinateur standard Informatique 3 Bus de contrôle Bus d’adresse CPU Mémoire programme Mémoire des données Périphérie 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) 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). Avec qui? Le bus de données permet de transmettre les instructions et les données du programme. Ces 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. quoi? Le bus de contrôle permet de transmettre des informations supplémentaires pour la gestion de la communication (read/write, reset, interrupts, requests et acknowledge, handshake etc.). comment? 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) 2) 3) 4) 5) 6) 7) 8) 9) 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). La CPU fixe le sens du transfert « lecture », à l’aide du bus de contrôle. 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. La CPU lit cette instruction. La CPU fournit l’adresse du composant périphérique, à partir de laquelle les données doivent être lues, sur le bus d’adresse. La CPU fixe le sens du transfert « lecture », à l’aide du bus de contrôle. La périphérie fournit l’information, contenue dans la case mémoire sélectionnée, sur le bus de données. La CPU lit les données. 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 Architecture d’un microordinateur standard Informatique 3 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 d’adresse AMP APE Bus de données AMD DMP Bus de contrôle DPE RD 1) 2) DMD RD 3) 4) 5) 6) WR 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 Périphérie Non utilisé Non utilisé RAM 2 (8kByte) RAM 1 (8kByte) Flash (32kByte) Adresse 0xFFFF 0xE000 A15 1 1 A14 1 1 A13 1 1 A12 1 0 0xBFFF 0xA000 0x9FFF 0x8000 0x7FFF 0 1 1 1 1 0 0 0 0 0 0 1 0 1 1 0 0 1 0 1 0 1 0 1 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 : Adresse Logique program. CS0 Flash CS1 RAM 1 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 Architecture d’un microordinateur standard Informatique 3 CS1 CS2 CS3 CS4 = = = = /A15 A15 * /A14 * /A13 A15 * /A14 * A13 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 Décodeur d’adresse CS2 8k * 8 RAM 1 32k * 8 Flash 8k * 8 RAM 2 Périphérie (convertisseur 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 Architecture d’un microordinateur standard Informatique 3 • 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 La plus petite adresse 0 1 7 MSB 0 LSB ~ La plus grande adresse Byte 0 1 ~ 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 Architecture d’un microordinateur standard A0 .. An Row-Decoder Informatique 3 Memory-Matrix Column-Output D0 .. Dn Column-Decoder An+1 .. Az OE CS Control 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. A0 .. An Row-Decoder L’architecture d’une SRAM : Memory-Matrix Column-In/Output D0 .. Dn Column-Decoder An+1 .. Az OE CS Control 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 /RAS /CAS row address column address read row address disable output driver 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 Architecture d’un microordinateur standard Informatique 3 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 Faible Élevé Élevé Cache Mémoire de travail Mémoire de masse 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 Architecture d’un microordinateur standard Informatique 3 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 de travail Mémoire de masse Peripherie 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 register CPU Programm jes < Virtual address Relocation register Work memory + Physical address no Address error Trap MMU 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 Architecture d’un microordinateur standard Informatique 3 Adresse physique 0 1 0 0 0 0 0 Numéro de trame = 2 obtenu du tableau de page Tableau de page Numéro de page = 4 correspond à l’indexe du tableau de page 0 15 14 13 12 000 000 11 10 9 8 7 6 5 111 000 4 3 2 1 0 000 000 101 000 100 000 011 010 110 000 001 000 0 0 0 0 10 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 1 0 1 0 010 bit de validité Offset 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 Architecture d’un microordinateur standard Informatique 3 Numéro de la Page (virtuel) Trames (physique) 22 54 60 52 36 18 632 320 Validité modification protection 1 1 1 1 0 1 0 0 rwx r x rw 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 Page Frame Number Number Numéro Offset Mémoire 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 Architecture d’un microordinateur standard Informatique 3 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 CPU Mémoire 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 Architecture d’un microordinateur standard Informatique 3 Port Out Port Out D Port Out G 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 : Pull up Source d’interrup. 1 Source d’interrup. 2 Source d’nterrup. 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 Architecture d’un microordinateur standard Informatique 3 (comme par exemple à l’aide de diodes Transzorb et des varistances). Contrôleur de moteur Microcontrôleur 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 Sende-Schieberegister Steuersignale 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 TxD Internal Bus Transmit Shifter Control Unit Baudrate 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 Architecture d’un microordinateur standard Informatique 3 Générateur de la fréquence d’horloge Entré des données en parallèle 7 Entré des données en parallèle 0 7 Sortie des données en parallèle 0 Sortie des données 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 à décalage Registre à décalage Esclave SPI 2 Esclave SPI 1 MOSI MISO SCK Sélection esclave SPI maître Registre à décalage Horloge FIFO de réception FIFO de 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 Architecture d’un microordinateur standard Informatique 3 Le Tableau suivant illustre quelques exemples de transmission de données avec l’interface I2C (le bit confirmation n’est pas affiché) : Composant Convertisseur D/A Démarrage Ecriture RAM Démarrage Lecture RAM Démarrage Adresse de l’esclave Adresse de l’esclave Adresse de l’esclave Wr Données Protocole Arrêt Wr Données Données Arrêt Wr Données Arrêt Démarrage Adresse de l’esclave Rd Données 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 Arrêt Architecture d’un microordinateur standard Informatique 3 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 Entrée externe Timer / Counter Register Overflow Flag Counter 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 Register Overflow 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 MUX VREF S&H Control-Register A/D Converter 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 8051 Description brève 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 Le microcontrôleur PXA270 Informatique 3 Architecture ARM v1 (1983) v2 v3 (1991) v4 v4T v5TE (1999) v5TEJ (2000) v6 (2001) v7 Brève description Famille / Coeur Première version de l’architecture ARM de Acorn Computers, basée sur la CPU 6502. Adressage à 26 bits Pas de multiplication et de co-processeur Premier chip commercial, 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 Première version de ARM Limited. Processeur indépendant ou intégré dans un CPU en tant que cellule macro. On-Chip-Cache, MMU, adressage à 32 bits, les registres CPS et SPS sont séparés. 35'000 transistors. La version V3M soutient les instructions « MultiplyAccumulate », fournissant un résultat de 64 bits. La plus vieille architecture ARM, qui est encore soutenue aujourd’hui. 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. Nouveau format comprimé à 16 bits (Thumb) des jeux d’instruction. ARM1 Amélioration des instructions Thumb. Nouvelles instructions, comme par exemple BLX, CLZ et BRK. Extension du jeux d’instruction pour le traitement du signal (support DSP) de la version E, comme par exemple les instruction à cycle unique 16*16 et 16*32 MAC. Introduction de la technologie Jazelle, pour exécuter de façon optimale le code byte Java. Cela est plus rapide qu’une machine virtuelle Java (Java Virtual Machine) implémenté en software. Soutient des environnements multiprocesseurs. Instruction multimédia qui soutiennent le SIMD, comme par exemple le 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). Trois profiles de processeur sont soutenus : A : Les applications pour utilisateur générales 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. ARM2 ARM6, ARM600, ARM610, ARM7, ARM700, ARM710 StrongARM, ARMS, ARM810 ARM7TDMI, ARM710T, ARM740T, ARM9TDMI, ARM920T, ARM940T XScale, ARM9E-S, ARM10TDMI, ARM1020E ARM926EJ, ARM1026EJ ARM1136J, ARM1156T2 Coretex-M3, Coretex-R4, Coretex-A8 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 Le microcontrôleur PXA270 Informatique 3 ARM740T). La nomenclature pour ces derniers est la suivante : ARM{x}{y}{z}{T}{D}{M}{I}{E}{J}{F}{S} x: y: z: T: D: M: I: E: J: F: S: Famille Gestion de mémoire / unité de protection Mémoire cache Décodeur d’instruction Thumb à 16-bit Débuggeur JTAG Multiplication rapide Embedded ICE Macrocell Instruction améliorée Jazelle (code byte Java) Unité à virgule flottante vectorielle 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 Le microcontrôleur PXA270 Informatique 3 Data Sign extend Write Read r15 (PC) Rd Registerbank 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 Le microcontrôleur PXA270 Informatique 3 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é : time Fetch Decode Cycle 1 Instr. 1 Cycle 2 Instr. 2 Instr. 1 Cycle 3 Instr. 3 Instr. 2 Execute 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, deepsleep). 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 Le microcontrôleur PXA270 Informatique 3 • • • • • • − 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 Utilisateur Requête d’interruption rapide Requête d’interruption Superviseur Abandon (abort) Non défini Système Abréviation USR FIQ IRQ SVC ABT UND SYS privilège Non Oui Oui Oui Oui Oui Oui Bit de mode [4:0] du registre CPSR 10000 10001 10010 10011 10111 11011 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 CPSR SPSR 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) Current Program Status Register, voir chapitre 2.6 Saved Program Status Register Version 3.1, juin 2008 Page 39 Le microcontrôleur PXA270 Informatique 3 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. r0 r1 Fast interrupt Request r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r2 r3 r4 r5 r6 r7 r8_fiq r9_fiq r10_fiq r2 r3 r4 r5 r6 r7 r8 r9 r10 r2 r3 r4 r5 r6 r7 r8 r9 r10 r2 r3 r4 r5 r6 r7 r8 r9 r10 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 sp r14 lr r15 pc r11_fiq r12_fiq r13_fiq r14_fiq r15 pc r11 r12 r13_irq r14_irq r15 pc r11 r12 r13_svc r14_svc r15 pc r11 r12 r13_abt r14_abt r15 pc r11 r12 r13_und r14_und r15 pc cpsr cpsr spsr_fiq cpsr spsr_irq cpsr spsr_svc cpsr spsr_abt cpsr spsr_und User und System Interrupt Request Supervisor Abort Undefined r0 r1 r0 r1 r0 r1 r0 r1 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 Le microcontrôleur PXA270 Informatique 3 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 Fields Flags Status Extension Control Bit 31 30 29 28 7 6 N Z C V Q Function not used Condition Flags I 5 4 Mode F T Interrupt Mask 0 Processor 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 Le microcontrôleur PXA270 Informatique 3 Drapeau (flag) N Nom du drapeau Description Negative Z Zero C Carry V oVerflow 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. 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. 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. 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 232 - 1 0 C=0 Dépassement avec Soustraction 32 (2 ) -1 Nulle 0 32 (2 SUB Dépassement avec addition 1 ) C=1 2 ADD 231 Figure 47 : Cercle de nombres binaires non signée Version 3.1, juin 2008 Page 42 Le microcontrôleur PXA270 Informatique 3 - 231 Domaine des nombres 231 -1 Nulle 0 1 -1 2 SUB N=1 Négatif - 231 - 1 V=1 N=0 Positif 231 Dépassement avec soustraction Dépassement avec addition ADD V=1 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 n+1 n+2 n+3 Byte 0 Byte 1 Byte 2 Byte 3 Figure 49: Model de mémoire du type byte Version 3.1, juin 2008 Page 43 Le microcontrôleur PXA270 Informatique 3 Model de mémoire avec un adressage du type demi mot : Adresse n Demi mot 0 n+2 Demi mot 1 Byte de poids plus faible du demi mot 0 Byte de poids plus fort du demi mot 0 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 n+4 Mot 1 Byte de poids le plus fort du mot 0 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 0xFFFF_0000 0xA400_0000 0xA000_0000 0x5800_0000 0x4000_0000 0x3000_0000 0x2000_0000 0x1800_0000 0x1400_0000 0x1000_0000 0x0C00_0000 0x0800_0000 0x0400_0000 0x0200_0000 0x0000_0000 Réservé High Vector Debug Handler Réservé 64 M bytes SDRAM Réservé Périphérie Compact Flash 1 Compact Flash 0 Réservé nCS5 nCS4 CPLD, MIN3IO (nCS3), Extension 1 bis 4 Ethernet-Controller (nCS2) CAN-Controller (nCS1) Réservé 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 Le microcontrôleur PXA270 Informatique 3 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 nWE nCS nWE nOE nOE nADV nADV CLK MA<23:2> MD<15:0> A<21:0> DQ<15:0> CLK MA<23:2> MD<31:16> A<21: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 CS WE OE ADV CLK A DQ Description 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. Write Enable : Signal d’écriture, avec lequel les données peuvent être écrites dans la flash. 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. 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. Horloge pour tous les composants statiques comme les flashs ou les SDRAM 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. 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 Le microcontrôleur PXA270 Informatique 3 nCS nWE nSDRAS, nSDCAS nSDCKE, nSDCLK<2:1> MA<24:10> DQM<3:0> MD<31:0> MA<21:10> MA<23:22> DQM0 DQM1 MD<15:0> 4M*16 SDRAM 4M*16 SDRAM nCS nWE nCS nWE nRAS nRAS nCAS nCAS CKE CKE CLK CLK A<11:0> BA<1:0> DQML DQMH DQ<15:0> MA<21:10> MA<23:22> DQM2 DQM3 MD<31:16> A<11:0> BA<1:0> DQML DQMH 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 CS WE RAS CAS CKE CLK A BA DQML/DQMH DQ Description Chip-Select : Sélectionne un banc de composants SDRAM Write Enable : Signal d’écriture, avec lequel les données peuvent être écrites dans la SDRAM. Row Address Strobe Column Address Strobe Clock Enable Clock Adresses pour row et column 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. 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). 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 La programmation en assembleur Informatique 3 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. Prend une bouteille de bière dans le réfrigérateur Bière – 1 Bière = Bière – 1; LDR SUB STR r4,beer r4,#1 r4,beer 0xe59f4020 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 Langue naturelle Pseudo code Langage de programmation haut niveau Assembler Abstraction Proche du hardware La Figure suivante montre les niveaux de langage de programmation possible : Code machine 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. ANSIC). 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 * * Auteur(s) : NomAuteur * * -----------------------------------------------------------------------* * Description : Description brève du module * * * ************************************************************************** * Modification: * * Auteur Date de la modification * * m.n dd.mm.yyyy * *************************************************************************/ Entête (header) (en option) /************************************************************************* * PUBLIC DECLARATIONS * *************************************************************************/ .global mysub @ exported subroutines Interface du module (en option) /************************************************************************* * EXTERNAL DECLARATIONS (optional) * *************************************************************************/ .extern extsuB @ imported subroutines Symbole importé (en option) /************************************************************************* * include DEFINITIONS * *************************************************************************/ .include ″pxa270.h″ @ include controller registers Fichier à inclure (en option) /************************************************************************* * EQUATE DEFINITIONS * *************************************************************************/ .equ MAX,0x1000 @ maximum allowable size Définition EQU (en option) /************************************************************************* * VARIABLE AND CONSTANT DEFINITIONS * *************************************************************************/ .data myvar: .space 4 @ space for 1 Word (32-Bit) Définition des variables et des constantes (en option) /************************************************************************* * CODE * *************************************************************************/ .text Code Version 3.1, juin 2008 Page 50 La programmation en assembleur Informatique 3 mysub: ADR MOV STR BL MOV r0, myvar r1, #MAX r1, [r0] Extsub pc, lr @ @ @ @ @ Load the address of myvar Load the constant value MAX Copy the MAX value in to myvar Call the subroutine Extsub 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 La programmation en assembleur Informatique 3 d’instruction de l’ARM V5) Toutes les opérations peuvent être exécutées de façon conditionnelle. Exemple : CMP r0, #0 CMPNE r1, #1 ADDEQ r2,r3,r4 @ if (a==0 || b==1) @ 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 SWI start 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 LDR pc,lr 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 La programmation en assembleur Informatique 3 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 La programmation en assembleur Informatique 3 Type Chaîne de caractère Caractère Numérique Numérique Numérique Numérique Description String Char Hexadécimal Binaire Octal Décimal Préfix " ' 0x 0b 0 Pas de préfix Exemple "Bonjour" 'A' 0x7FF 0b0111011 0124 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: loop: 0xa00004e8 0xa00004ec <loop+12> 0xa00004f0 0xa00004f4 LDR LDR ADD B r0,=1 r1,=0x12345678 r0,r0,r1 loop @ Charger la valeur constante 1 @ Charger la valeur 0x12345678 @ Additionner les deux valeurs <start>: <loop>: MOV LDR r0, #1 ; 0x1 r1, [pc, #4] <loop+4>: <loop+8>: ADD B r0, r0, r1 0xa00004ec <loop> @ la valeur est chargé de la mémoire 0xa00004f8 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 La programmation en assembleur Informatique 3 + * / % & | ^ && || ==, <> >, >= <, <= << >> ~ 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 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é maximale 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 La programmation en assembleur Informatique 3 • 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 assembler Source *.s assembler *.asm *.s *.asm Source C / Source C++ *.c C / C++ *.cpp*.c *.cpp Assembler Compiler Listing assembleur Listing *.lst assembleur *.lst Fichier objet Fichier *.oobjet *.ltx*.o Listing compilateur Listing *.lst compilateur *.prn *.lst Fichier objet Fichier *.oobjet *.ltx*.o Linker/Locator Listing du relieur *.map Fichier binaire *.bin Fichier débuggeur *.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. start: loop: .arm .global start .text LDR LDR ADD B r0,=1 r1,=0x12345678 r0,r0,r1 loop @ Load constant value 1 @ Load constant value 0x12345678 @ ADD both values .end Figure 64 : Exemple d’un code en assembleur Version 3.1, juin 2008 Page 56 La programmation en assembleur Informatique 3 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 1 2. 3 4 5 0000 0000A0E3 start: 6 0004 04109FE5 loop: 7 0008 010080E0 8 000c FCFFFFEA 9 10 0010 78563412 ARM GAS page 1 .arm .global start .text LDR LDR ADD B r0,=1 r1,=0x12345678 r0,r0,r1 loop .end EditionExample.s DEFINED SYMBOLS EditionExample.s:1 EditionExample.s:5 EditionExample.s:6 EditionExample.s:10 @ ADD 0x12345678 page 2 .text:00000000 .text:00000000 .text:00000004 .text:00000010 $a start loop $d NO UNDEFINED SYMBOLS Figure 65 : Le listing assembleur Les colonnes du fichier listing contiennent les informations suivantes : Nr. de colonne 1 2 3 reste Contenu Numéro de ligne du code source Adresse relative de départ du code 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). 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 Jeu d’instruction du processeur ARM V5 Informatique 3 Instruction ADC ADD AND B BIC BKPT BL BLX BX CDP CDP2 CLZ CMN CMP EOR LDC LDC2 LDM LDR MCR MCR2 MCRR MLA MOV MRC MRC2 MRRC MRS MSR MUL MVN ORR PLD QADD QDADD QDSUB QSUB RSB RSC SBC SMLAxy SMLAL SMLALxy SMLAWxy SMULxy SMULWy STC STC2 STM STR SUB SWI SWP TEQ TST UMLAL UMUL Fonction Addition de deux valeurs de 32 bits avec la retenue Addition de deux valeurs de 32 bits Opération logique ET entre deux valeurs à 32 bits Saut relatif ± 32 Mégas bytes Effacer les bits d’une valeur 32 bits Point d’arrêt software (break point) Saut avec stockage de l’adresse de retour (appel de sous-routine) Saut avec stockage de l’adresse de retour et changement de registre Saut avec changement de registre Opération coprocesseur Compter les zéros, qui précèdent Comparaison inversée de deux valeurs 32 bits Comparaison de deux valeurs 32 bits Opération logique OU exclusive entre deux valeurs 32 bits Charger le coprocesseur avec une ou plusieurs valeurs 32 bits Charger plusieurs valeurs de 32 bits depuis la mémoire dans les registres ARM Charger la valeur avec une adresse virtuelle dans un registre ARM Charger une ou plusieurs registres ARM dans le coprocesseur Multiplication et accumulation d’une valeur 32 bits Charger la valeur 32 bits dans un registre Charger depuis le processeur dans un ou plusieurs registres Copier le registre de statut (CPSR ou SPSR) dans un registre ARM Copier depuis le registre ARM dans un registre d’état (CPSR ou SPSR) Multiplier deux valeurs de 32 bits Charger une valeur 32 bits, préalablement inversée, dans un registre Opération logique OU entre deux valeurs 32 bits Indique l’adresse de la case mémoire, qui est en train d’être chargée Addition signée de deux valeurs 32 bits avec limitation du dépassement de capacité Addition signée double de deux valeurs 32 bits et limitation du dépassement de capacité Soustraction signée double de deux valeurs 32 bits et limitation du dépassement de capacité Soustraction signée de deux valeurs 32 bits avec limitation du dépassement de capacité Soustraction inverse de deux valeurs 32 bits Soustraction inverse de deux valeurs 32 bits avec la retenu Soustraction de deux valeurs 32 bits avec retenu Multiplication/addition signées (16x16)+32 = 32 Bit Multiplication/addition larges signées (32x32)+64 = 64 Bit Multiplication/addition larges signées (16x16)+64 = 64 Bit Multiplication/addition signées ((32x16)>>16)+32 = 32 Bit Multiplication signée (16x16) = 32 Bit Multiplication/addition signées ((32x16)>>16)+32 = 32 Bit Stocker une ou plusieurs valeurs depuis le processeur dans la mémoire Stocker plusieurs registres ARM dans le processeur Stocker des registres à des adresses virtuelles Soustraire deux valeurs à 32 bits Interruption software Echanger les registres ARM avec la mémoire de façon byte ou mot Comparer deux valeurs 32 bits Tester un bit dans un registre 32 bits Multiplication/addition larges non singées (32x32)+64 = 64 Bit 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 Jeu d’instruction du processeur ARM V5 Informatique 3 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 formulation pour LDR {B}. | LDR B est par exemple une autre 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 (barrelshifter) uniquement le bit C. Version 3.1, juin 2008 Page 63 Jeu d’instruction du processeur ARM V5 Informatique 3 Condition EQ NE CS,HS CC,LO MI PL VS VC HI LS GE LT GT LE Drapeau (flag) Z !Z C !C N !N V !V C && !Z !C && Z (N == V) (N != V) !Z et (N == V) Z ou (N != V) Description Egalité Inégalité Plus grand que ou égalité (non signé) Plus petit (non signé) Minus, négatif Positif ou nul Dépassement de capacité (Overflow) Pas de dépassement de capacité Plus grand que (non signé) Plus petit que ou égalité (non signé) Plus grand que ou égalité (signé) Plus petit que (signé) Plus grand que (signé) 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 BEQ BLT SUB B aIsSmaller: SUB B endIf: r1, r2 endIf aIsSmaller r1, r1, r2 ggt r2, r2, r1 ggt 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 SUBGT SUBLT BNE endIf: r1, r2 r1, r1, r2 r2, r2, r1 ggt 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 Jeu d’instruction du processeur ARM V5 Informatique 3 Instruction SWP Opérande Reg1,Reg2,Reg3 MOV Reg,Op2 Opération Reg2 -> [Reg3], Reg1 <- [Reg3] Reg := Op2 MVN Reg,Op2 Reg := ~OP2 LDR Reg, Address Reg := [address] STR Reg, Address [address] := Reg MSR Reg PSR := Reg MRS Reg Reg := PSR MCR p#, op, cReg, Reg1, Reg2 cReg := Reg1 {op Reg2} MRC p#, op, Reg1, Reg2 Reg := cReg1 {op cReg2} LDC cReg := [Address] LDM p#, cReg, Address p#, cReg, Address Rbase,{Rlist} STM Rbase,{Rlist} {Rlist} -> [Rbase] STC [Address] := cReg [Rbase] -> {Rlist} Description Echange le contenu du registre avec la mémoire Copier le contenu d’un registre ou une valeur constante dans un registre Copier le complément à un du contenu d’un registre ou d’une valeur constante dans un registre Charger le contenu de la mémoire dans un registre Stocker le contenu d’un registre dans la mémoire Copier le contenu du registre dans le registre d’état du programme PSR (Status/Flags) Copier le contenu du registre PSR (Status/Flags) dans un registre Exécuter l’opération op à l’aide du coprocesseur p# et stocker le résultat dans le registre du coprocesseur. Exécuter l’opération op à l’aide du coprocesseur p# et stocker le résultat dans le registre Reg2. Charger le registre du coprocesseur avec le contenu de la mémoire Charger le registre du coprocesseur avec le contenu de la mémoire Charger plusieurs registres avec le contenu de la mémoire (pile pop) 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 MOVS MVN MOV r0, r0, r1, pc, r1 #10 r0 lr @ @ @ @ r0 := r1 r0 := 10, fixe les bit d’état courant du programme r1 := ~r0 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 Jeu d’instruction du processeur ARM V5 Informatique 3 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 LSL LSR ASR Décalage logique vers la gauche Décalage logique vers la droite Décalage arithmétique vers la droite Rotation vers la droite Extension de la rotation vers la droite x LSL y x LSR y x ASR y x << y (non signé) x >> y (signé) x >> y Domaine de décalage #0-31 ou Rs #1-31 ou Rs #1-31 ou Rs x ROR y x RRX ((non signé) x>>y) | (x << (32-y)) (cflag << 31)|((non signé) >> 1) #1-31 ou Rs 1 (fixe) ROR RRX 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 Jeu d’instruction du processeur ARM V5 Informatique 3 Opération de décalage pour N Décaler selon la valeur constante #shift La valeur du registre Décalage logique vers la gauche en fonction de la valeur constante #shift Décalage logique vers la gauche en fonction du registre Rs Décalage logique vers la droite en fonction de la valeur constante #shift Décalage logique vers la droite en fonction du registre Rs Décalage arithmétique vers la droite en fonction de la valeur constante #shift Décalage arithmétique vers la droite en fonction registre Rs Rotation vers la droite en fonction de la valeur constante #shift Rotation vers la droite en fonction du registre Rs Rotation vers la droite étendue (33-Bit Rotation) Syntaxe #shift Rm Rm, LSL Rm, LSL Rm, LSR Rm, LSR Rm, ASR Rm, ASR Rm, ROR Rm, ROR Rm, RRX #shift Rs #shift Rs #shift Rs #shift Rs 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 r0 = 0x00000000 r1 = 0x80008001 MOVS (Majuscule: mise à un, minuscule: mise à zéro) 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 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 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 Jeu d’instruction du processeur ARM V5 Informatique 3 Instruction LDR STR LDRB STRB LDRH STRH LDRSB LDRSH Description Charger un mot dans un registre Stocker un mot à partir d’un registre Charger un byte dans un registre Stocker un byte à partir d’un registre Charger un demi mot dans un registre Stocker un demi mot à partir d’un registre Charger un byte signé dans un registre Charger un demi mot signé dans un registre STRD Stocker deux mots à partir de registres (DSP) LDRD Stocker deux mots dans des registres (DSP) Effet Rd := mem32[Adresse] Mem32[Adresse] := Rd Rd := mem8[Adresse] mem8[Adresse]:= Rd Rd := mem16[Adresse] mem16[Adresse] := Rd Rd := (signExtend) mem8[Adresse] Rd := (signExtend) mem16[Adresse] Mem32[Adresse] := Rd Mem32[Adresse+4] := R(d+1) 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} LDR{<cond>}{SB|SH} Rd, <Address> 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 Jeu d’instruction du processeur ARM V5 Informatique 3 Méthode d’indexation Données Pré indexation avec retour Pré indexation Post indexation mem[Basis+Offset] mem[Basis+Offset] mem[Basis+Offset] Registre contenant l’adresse de base Basis+Offset Basis+Offset Basis+Offset Exemple LDR r0,[r1,#2]! LDR r0,[r1,#2] 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 Jeu d’instruction du processeur ARM V5 Informatique 3 Mode d’adressage Pré indexation avec un offset constant Pré indexation avec un offset registre Pré indexation avec un décalage de l’offset registre Pré indexation avec write back et un offset constant Pré indexation avec write back et un offset registre Pré indexation avec write back et un décalage de l’offset registre Post indexation avec un offset constant Post indexation avec un offset registre Post indexation avec un décalage de l’offset registre Syntaxe [Rn, #±<offset12>] [Rn, ±Rm] [Rn, ±Rm, shift #<shift_value>] [Rn, #±offset12]! [Rn, ±Rm]! [Rn, ±Rm, shift #<shift_value>]! [Rn], #±<offset12> [Rn], ±Rm [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 Pré indexation avec un offset constant Pré indexation avec un offset registre Pré indexation avec write back et un offset constant Pré indexation avec write back et un offset registre Post indexation avec un offset constant Post indexation avec un offset registre Syntaxe [Rn, #±<offset8>] [Rn, ±Rm] [Rn, #±<offset8>]! [Rn, ±Rm]! [Rn], #±<offset8> [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 : @ stock r1 in [r2+r4] and copy the base address r2+r4 in r2 str r1, [r2, r4]! 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 @ conditional load the byte of r1 with [r2+5]. @ the bits D8 up to D31 will be full with zero. ldreqb r1,[r2,#5] 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 SWP Description Echange de mot entre le registre et la mémoire SWPB Echange de byte entre le registre et la mémoire Déroulement interne tmp = mem32[Rn] mem32[Rn] = Rm Rd = tmp tmp = mem8[Rn] mem8[Rn] = Rm Rd=tmp Tableau 22 : Effet des instruction SWP et SWPB Version 3.1, juin 2008 Page 71 Jeu d’instruction du processeur ARM V5 Informatique 3 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 r0 0x55555555 0x10101010 r1 0xAAAAAAAA r2 0x0001A000 Arbeitsspeicher (RAM) 0x19FFC 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 IA IB DA DB Description Incrémenter après Incrémenter avant Décrémenter après Décrémenter avant Adresse de départ Rn Rn+4 Rn-4*N+4 Rn-4*N Adresse d’arrivée Rn+4*N-4 Rn+4*N Rn Rn-4 Rn! Rn+4*N Rn+4*N Rn-4*N 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 Jeu d’instruction du processeur ARM V5 Informatique 3 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} r9start r0 0x00010000 STMIB r9!,{r0,r1,r4} r9start 0x00010000 r0 r1 r4 r1 r9end r9end r4 0x00010010 0x00010010 STMDA r9!,{r0,r1,r4} STMDB r9!,{r0,r1,r4} 0x0000FFF0 r9end 0x0000FFF0 r9end r1 r0 r4 r1 r9start r4 r0 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 LDR r6,0x0001A000-4 STMIB r6!,{r0-r4} r1 r2 r3 0x0001A000-4 r6start r0 0x0001A000 r4 r5 r6 0x0001A000-4 0x0001A010 r7 r1 r2 r4 0x0001A000 r6 start r0 0x0001A004 r1 0x0001A008 r2 0x0001A00C r3 0x0001A010 r4 r6end 0x0001A014 r3 r6end 0x00019FFC 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 Jeu d’instruction du processeur ARM V5 Informatique 3 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 cidessus : Mode d’adressage FA FD EA ED Description pop =LDM push =STM Full Ascending Full Descending Empty Ascending Empty Descending LDMFA LDMFD LDMEA LDMED LDMDA LDMIA LDMDB LDMIB STMFA STMFD STMEA STMED STMIB STMDB STMIA 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 r2=0x00000006 sp=0x00020014 leer (undefiniert) Nachher: r1=0x00000005 r2=0x00000006 sp=0x0002000C sp 0x00000005 leer (undefiniert) sp 0x00000002 0x0002000C 0x00000006 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 r2=0x00000006 sp=0x00020014 leer (undefiniert) Nachher: sp leer (undefiniert) sp leer (undefiniert) 0x00020014 r1=0x00000005 r2=0x00000006 sp=0x0002000C leer (undefiniert) 0x0002000C 0x00000005 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 Jeu d’instruction du processeur ARM V5 Informatique 3 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. Fields Flags [24:31] Status [16-23] Extension [8:15] Bit 31 30 29 28 27 Control [0:7] 7 6 5 4 N Z C V Q not used I F T 0 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 MSR CPSR_c, r1 @ Clear bit 7 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>} <MRC | MCR>{<cond>} CDP{<cond>} CDP2 <MRC2 | MCR2> <LDC2 | STC2> Version 3.1, juin 2008 cp, cp, cp, cp, cp, cp, cd, AddressMode opcode1, rd, cd, cm {, opcode2} opcode1, cd, cn {,opcode2} opcode1, cd, cn {,opcode2} opcode1, rd, cd, cm {, opcode2} cd, AddressMode Page 75 Jeu d’instruction du processeur ARM V5 Informatique 3 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 LDC STC LDC2 STC2 MRC MCR MCR2 MRC2 CDP CDP2 Description Transfert de données entre le coprocesseur et la mémoire Transfert de données entre le coprocesseur et les registres 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 Pré indexation avec un offset constant Pré indexation avec écriture en retour et un offset constant Post indexation avec un offset constant Sans indexe mais avec une option spécifique au coprocesseur Syntaxe [Rn,#+/-offset8] [Rn,#+/-offset8]! [Rn], #+/-offset8 [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 Instruction ADD ADC AND BIC CMP CMN EOR MUL MLA ORR QADD QDADD QDSUB QSUB RSB RSC SMLA SMLAL SMLAW SMUL SMULW SUB UMLULL Jeu d’instruction du processeur ARM V5 Description Adition 32 bits Adition 32 bits avec report de la retenu Opération logique ET Effacer un bit (NICHT UND) Comparaison Comparaison inverse Opération logique OU exclusive Multiplication 32 bits Multiplication et addition 32 bits Opération logique OU Addition 32 bits avec protection contre les dépassements de capacité (DSP) Addition 32 bits avec protection contre les dépassements de capacité (DSP) Soustraction 32 bits avec protection contre les dépassements de capacité (DSP) Soustraction 32 bits avec protection contre les dépassements de capacité (DSP) Soustraction 32 bits inverser Soustraction 32 bits inverser avec report de la retenu Multiplication 16 bits / addition 32 bits signées (DSP) Multiplication 16 bits / addition 64 bits signées (DSP) Multiplication 32x16 bits / addition signées (DSP) Multiplication 16 bits signée (DSP) Multiplication 32x16 bits signée (DSP) Soustraction 32 bits 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 Jeu d’instruction du processeur ARM V5 Informatique 3 Instruction ADD Opérande Rd, Rn, N Description Addition 32 bits Opération Rd=(Rn+N) ADC MUL MLA Addition 32 bits avec report Multiplication 32 bits Multiplication / Addition 32 bits Rd=Rn+N+Carryflag Rd=Rn*Rs Rd=Rn*Rs+Rm Multiplication 32 bits / Addition 32 bits signées Multiplication 16 bits / Addition 32 bits signées Multiplication 32 bits / Addition 64 bits signées Multiplication 32x16 bits / Addition signées Multiplication 16 bits signée Rd= Rn+Rm*Rs Multiplication 32x16 bits signée Rd= (Rm* Rs.<y>)>>16 Multiplication longue signée [RdHi,RdLo]= Rm*Rs QDADD Rd, Rm, Rn QDSUB Rd, Rm, Rn QSUB Rd, Rm, Rn SBC SUB RSB RSC Rd, Rd, Rd, Rd, CMP CMN TEQ TST Rn,N Rn,N Rn,N Rn,N Multiplication longue / addition non signées Multiplication longue non signées Addition 32 bits avec protection anti-dépassement de capacité Addition 32 bits avec protection anti-dépassement de capacité Soustraction 32 bits avec protection anti-dépassement de capacité Soustraction 32 bits avec protection anti-dépassement de capacité Soustraction 32 bits avec report Soustraction 32 bits Soustraction 32 bits inverse Soustraction 32 bits inverse avec report Comparaison Comparaison inverse Tester l’égalité Tester un bit [RdHi,RdLo]= [RdHi,RdLo]+Rm*Rs QADD Rd, Rn, N Rd, Rn, Rs Rd, Rn, Rs, Rm Rd, Rm, Rs, Rn Rd, Rm, Rs, Rn RdLo, RdHi, Rm, Rs RdLo, RdHi, Rm, Rs RdLo, RdHi, Rm, Rs RdLo, RdHi, Rm, Rs RdLo, RdHi, Rm, Rs RdLo, RdHi, Rm, Rs RdLo, RdHi, Rm, Rs Rd, Rm, Rn SMLA<x><y> SMLAL SMLAL<x><y> SMLAW<y> SMUL<x><y> SMULW SMULL UMLAL UMULL Rn, Rn, Rn, Rn, N N N N Rd= Rn+(Rm.<x>*Rs.<y>) [RdHi,RdLo]= [RdHi,RdLo]+Rm.<x>*Rs.<y> Rd=Rn+(((signed)Rm*Rs.<y>)>>16) Rd= Rm.<x>* Rs.<y> [RdHi,RdLo]= Rm*Rs Rd=sat32(Rm+Rn) Rd=sat32(Rm+sat32(2*Rn)) Rd=sat32(Rm-sat32(2*Rn)) Rd=sat32(Rm-Rn) Rd=Rn-N-!(Carryflag) Rd=Rn-N Rd=N-Rn Rd=N1-Rn-!(Carryflag) Drapeau en fonction de Rn-N Drapeau en fonction de Rn+N Drapeau en fonction de Rn^N 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 Jeu d’instruction du processeur ARM V5 Informatique 3 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 r1 r2 r3 = = = = 0x11111111 0x22222222 0x33334444 0x11112222 SMLALBT Version 3.1, juin 2008 r0, r1, r2, r3 @ [r0,r1]=[r0,r1]+Lo(r2)*Hi(r3) Page 79 Jeu d’instruction du processeur ARM V5 Informatique 3 Après : r0 r1 r2 r3 = = = = 0x159E1D95 0x22222222 0x33334444 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 AND ORR EOR Opérande Rd, Rn, N Rd, Rn, N Rd, Rn, N BIC Rd, Rn, N Description Opération logique ET entre deux valeurs 32 bits Opération logique OU entre deux valeurs 32 bits Opération logique OU exclusive entre deux valeurs 32 bits Effacer le bit (AND NOT) Opération Rd=Rn & N Rd=Rn | N Rd=Rn ^ N 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 Jeu d’instruction du processeur ARM V5 Informatique 3 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 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 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 : 0x0000 0x6000 Version 3.1, juin 2008 prog. Start ... ... JMP 0x6000 ... ... instruktion 1 Le même programme est démarré à l’adresse 0x2000 : 0x0000 0x2000 0x6000 prog. Start ... ... JMP 0x6000 ... instruktion x 0x8000 instruktion 1 Page 81 Jeu d’instruction du processeur ARM V5 Informatique 3 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 : 0x0000 0x6000 prog. Start ... ... B label1 ... ... Le même programme est démarré à l’adresse 0x2000 : 0x0000 Offset label1: 0x2000 0x6000 prog. Start ... ... B label1 ... instruktion x 0x8000 label1: Offset 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> BX BLX <label> Rm <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 Jeu d’instruction du processeur ARM V5 Informatique 3 Instruction B BL Distance de saut (offset) ± 32MB ± 32MB BX ± 32MB BLX ± 32MB Description Effet Saut de programme général Appel de sous-routine. Saut de programme avec sauvegarde de l’adresse de retour dans le registre du relieur lr Identique à B, mais possibilité de passage dans le mode Thumb Identique à BL, mais possibilité de passage dans le mode Thumb. pc = offset (label) pc = offset (label) lr = Adresse de l’instruction qui suit BL pc = Rm & 0xfffffffe T = Rm &1 pc = Rm & 0xfffffffe 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 ADD ADD ADD ahead r1,r2,#4 r0,r6,#2 r3,r7,#4 SUB r1,r2,#4 ADD SUB ADD B r1,r2,#4 r1,r2,#4 r4,r6,r7 back ahead: 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 ADD ... subroutine 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 Jeu d’instruction du processeur ARM V5 Informatique 3 dernières est toujours réalisée soit avec l’instruction « MOV retour depuis la pile. pc, lr », ou avec la lecture de l’adresse de 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>} BX{<cond>} BLX{<cond>} label Rm 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 EQ NE CS,HS CC,LO MI PL VS VC HI LS GE LT GT LE Description Equal Not Equal Unsigned higher or same Unsigned lower Minus, Negative Positive or zero Overflow No overflow Unsigned higher Unsigned lower or same Signed greater or equal Signed less than Signed greater than Less or equal Drapeau Z !Z C !C N !N V !V C && !Z !C && Z (N == V) (N != V) !Z && (N == V) 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 BL B r0, #5 FacSuB start @ Example 5! @ Compute (r0!) // 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 Jeu d’instruction du processeur ARM V5 Informatique 3 loop: MUL SUB CMP BGT endFac: MOV r0, r1, r0 r1, r1, #1 r1, #1 loop @ multiplication n*(n-1)*(n-2)*...*3*2 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 SWI Opérande Numéro SWI Description Interruption software Effet lr_SVC = Adresse de l’instruction, qui suit SWI 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 pc = lr = r0 = SWI = nzcvqift_USR 0x00008000 r14= 0x003FFFFF 0x12 0x123456 Après : CPSR SPSR pc = lr = r0 = = nzcvqIft_SVC = nzcvqift_USR 0x00000008 r14= 0x0008004 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 Jeu d’instruction du processeur ARM V5 Informatique 3 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 MOV r1, r0 r0, r0, LSL r1 @ Nombre de déplacement vers la gauche pour la normalisation @ Normalisation, afin que le bit 31 soit mis à un Après : r0 = 0x84210000 r1 = 0x10 Version 3.1, juin 2008 Page 86 Les directives de l’assembleur Informtique 3 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 instructions .arm .thumb .global .extern .align .balign .p2align Nom de symbole .ascii, .asciz Nom de symbole .byte .2byte, .hword .4byte, .word Nom de symbole .space .include .equ, .set, = .org .section .text, .data, .bss .end .if .ifdef .ifndef .else .macro .rep .irp .endm .endr .endif Champ des opérateurs Description Nom de symbole Nom de symbole Alignement, valeur Définition du jeu d’instruction ARM (32-Bit) Définition du jeu d’instruction Thumb (16-Bit) Exporter un symbole Importer un symbole Alignement de l’adressage de la mémoire Chaînes de caractères Valeurs Définition de chaînes de caractères constantes Définition de constantes de type byte, demi mot et mot Nombre, valeur Réserver de l’espace mémoire avec initialisation du bloc en question Insérer le contenu d’un fichier Attribuer une valeur à un symbole Attribuer une adresse absolue Définition de segments de mémoire {chemin} nom de fichier Nom de symbole, valeur Adresse Nom de symbole {, drapeau} Les sections standard Condition Nom de symbole {Paramètre} Nombre Paramètre Fin du code source Assemblage conditionnel du programme Définition d’une macro Répétition des blocs de code Fin d’une macro ou d’une structure de contrôle Tableau 33: Les directives de l’assembleur Version 3.1, juin 2008 Page 87 Les directives de l’assembleur Informtique 3 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 ... .thumb ... @ 32-Bit ARM Instruction @ 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 .extern InitDisplay ... ... ... ... bl InitDisplay lcd.s .global InitDisplay ... ... 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 Les directives de l’assembleur Informtique 3 start: .arm .global start .text 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 0002 0000 0004 48616C6C 6F00 .byte .align .asciz 0xaa, 0x55 @ 2 bytes 0x00 vont être inseres a cet endroi "Hallo" 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 0001 FFFFFFFF FFFFFF 0008 48616C6C 6F00 000e 0000 .byte .align 0xaa 3, 0xFF .asciz ″Hello″ @ alignement modulo 2^3=8 et remplissage avec 0xFF 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: 0000 55 0001 11111111 11111111 11111111 11111111 11111111 0100 FF 0101 00000000 .data .byte .align 0x55 8, 0x11 .byte 0xff 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 Les directives de l’assembleur Informtique 3 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 .byte .balign .byte .balign .byte .balign .byte .balign .byte 0000 FF 0001 FF 0002 0003 0004 0005 0008 FF 00 FF 000000 FF 0xFF 0xFF 2 0xFF 4 0xFF 8 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. 0000 FFFFFFFF 0004 0004 FFFF 0006 3412 b1: b2: .data .byte .balignw .byte .balignw 0xFF, 0xFF, 0xFF, 0xFF 4, 0x1234 0xFF, 0xFF 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. 0000 10 0001 00000000 00000 0008 33 b1: .data .byte .p2align 0x10 3 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 Les directives de l’assembleur Informtique 3 d’erreurs. 0000 0001 0004 0006 FF 565656 FFFF 3412 b1: b2: .data .byte .p2align .byte .p2alignw 0xFF 2, 0x56 0xFF, 0xFF 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 6F 0005 57656C74 2100 .ascii ″Hello″ .asciz "World!" 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 0003 0005 0007 416225 20D0 F608 0A .byte .byte .byte .byte 'A', 'b', 37 0x20, -0x30 -10, 010 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:} Version 3.1, juin 2008 <.2byte|.hword> <short1> {, <short2>} ... Page 91 Les directives de l’assembleur Informtique 3 Exemple : Les directives .2byte et .hword sont des synonymes. Elles déposent les constantes à 16 bits en respectant l’ordre de leurs énumérations. 0000 0002 0006 0008 1100 33224400 1100 33224400 h1: h2: h3: h4: .data .2byte .2byte .hword .hword 0x11 0x2233, 0x44 0x11 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. 0000 11000000 0004 55443322 66000000 000c 11000000 0010 55443322 66000000 w1: w2: .data .4byte .4byte 0x11 0x22334455, 0x66 w3: w4: .word .word 0x11 0x22334455, 0x66 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 Les directives de l’assembleur Informtique 3 00000 00000000 00000000 00000000 00000000 00010 AAAAAAAA AAAAAAAA AAAAAAAA AAAAAAAA AAAAAAAA 10010 00000000 00000000 00000000 00000000 00000000 .data .space 0x10 .space 0x10000, 0xAA .space 0x1234 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 2 3 4 5 6 7 8 9 10 11 12 13 0000 0004 0008 000c 0A00A0E3 9710A0E3 011000E0 0930A0E3 0010 6400A0E3 .text .equ .set TAB = 011 newline, 0xa bitmask, 0b10010111 MOV MOV and MOV r0, r1, r1, r3, .equ newline, 100 MOV r0, #newline #newline #bitmask r0, r1 #TAB /* Redefinion of newlin */ 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 Les directives de l’assembleur Informtique 3 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 : mysub: .org ... MOV 0xa0000800 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 A W X Signification Segment pour l’allocation de mémoire Segment en écriture Segment contenant du code exécutable Tableau 34 : Droit d’accès des segments Version 3.1, juin 2008 Page 94 Les directives de l’assembleur Informtique 3 Nom de segment (Section) .text .data .bss .startup .rodata, .rodata* .glue_7, .glue_7t Segment de base .text .data .bss .text .text .text (ev. .data) Contenu Code du programme Variables initialisées Variables non initialisées Code de démarrage Données en lecture (strings, constants) 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 .section .section .section .subroutines, "x" .text .startup MySection, "w" @ Synonyme to .text 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 BL B mysub1 mysub2 start mysub1: .section MOV .subroutines pc,lr b1: msg: .data .byte .asciz 0x22,0x33 ″Hello″ mysub2: .section MOV .subroutines 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 Les directives de l’assembleur Informtique 3 /* identify the Entry Point ***************************************************/ ENTRY(_startup) /* specify the colibri memory areas *******************************************/ MEMORY { flash ram } : ORIGIN = 0x00000000, LENGTH = 0x02000000 : ORIGIN = 0xA0000000, LENGTH = 0x02000000 /* 32MB FLASH */ /* 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 Les directives de l’assembleur Informtique 3 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 flash ram *default* Origin 0x00000000 0xa0000000 0x00000000 Length 0x02000000 0x02000000 0xffffffff Attributes 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 *(.startup) .startup .startup *(.glue_7) .glue_7 .glue_7 .glue_7 *(.glue_7t) .glue_7t .glue_7t .glue_7t Version 3.1, juin 2008 0xa0000000 0xa0000000 0x8b8 . = ALIGN (0x4) 0xa0000000 0xa0000000 0xa00000c0 0xc0 startup/crt0.o _startup 0x4 AsmSectionAnweisung.o 0xa00000c4 0xa00000c4 0xa00000c4 0x0 startup/crt0.o 0x0 startup/BSP_STARTUP.o 0x0 AsmSectionAnweisung.o 0xa00000c4 0xa00000c4 0xa00000c4 0xa00000c4 0x0 startup/crt0.o 0x0 startup/BSP_STARTUP.o 0x0 AsmSectionAnweisung.o . = ALIGN (0x4) Page 97 Les directives de l’assembleur Informtique 3 *(.text) .text .text 0xa00000c4 0xa00000c4 0xa0000598 0xa0000194 0xa00001a8 0xa0000180 0xa0000834 0xa0000214 0xa0000308 0xa0000120 0xa00003d0 0xa00001bc 0xa00000c4 0xa00008a8 0xa00008a8 .text 0x0 startup/crt0.o 0x7e4 startup/BSP_STARTUP.o BSP_STARTUP_init UNDEF_Routine DA_Routine SWI_Routine _sbrk_r pxa27x_set_core_freq pxa27x_get_freq FIQ_Routine InitMemoryController PA_Routine IRQ_Routine 0xc AsmSectionAnweisung.o start *(.subroutines) .subroutines 0xa00008b4 0xa00008b8 0xa00008b8 *(.text) 0x4 AsmSectionAnweisung.o _etext = . . = ALIGN (0x4) 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 .end pc, lr @ dernière instruction @ 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 Les directives de l’assembleur Informtique 3 Opérateur / * % << >> | ^ & ! + == <> < > <= >= && || Priorité 1 1 1 1 1 2 2 2 2 3 3 3 3 3 3 3 3 4 5 Description Division (entier) Multiplication Reste de la division (Modulo) Décalage vers la gauche Décalage vers la gauche OU binaire OU Exclusif binaire ET binaire NON binaire Addition Soustraction Egalité Inégalité Plus petit que Plus grand que Plus petit que ou égalité Plus grand que ou égalité ET logique 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 Les directives de l’assembleur Informtique 3 .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 LDR .ifdef BKPT .endif LDR r0, =0x80 DEBUG start: 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 ... {.else} <Symbole> .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> {BlocCode} .endm {<arg1>} {, <arg2>} {, <arg3>} ... {, <argN>} 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 Les directives de l’assembleur Informtique 3 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 SHIFTLEFT r0, 2 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 ... Tab: .data .word r0,Tab 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 Les directives de l’assembleur Informtique 3 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 .word .word .word .endr 0x55AA55AA 0x00000000 0xAA55AA55 0x11111111 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 Les directives de l’assembleur Informtique 3 .set L1, 0 .rept 256 .byte L1 .set L1, L1+1 .endr @ L1 is a local symbole with a start value 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 MOV ADD .endr param, 1, 2, 3, 4 r1, #\param r0, r0, r1 La macro est étendu à l’assemblage du programme : .irp MOV ADD .endr MOV ADD MOV ADD MOV ADD MOV ADD param, 1, 2, 3, 4 r1, #\param r0, r0, r1 r1, r0, r1, r0, r1, r0, r1, r0, #1 r0, #2 r0, #3 r0, #4 r0, @ 0x1 r1 @ 0x2 r1 @ 0x3 r1 @ 0x4 r1 Figure 74 : Extension de la macro .irp de l’exemple de ci-dessus Version 3.1, juin 2008 Page 103 Les sous routines Informtique 3 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 1. instruction subr1 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 Les sous routines Informtique 3 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 ... subr1: ... MOV @ branch to subr1 and save return address in "lr" (r14) @ next instruction @ start subroutine @ return pc, lr 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 Instruction suivante bsr subr2 1. Instruction i t Instruction suivante n. instruction retour n. Instruction i t 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 Les sous routines Informtique 3 • 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. 1. Elément Début de la pile 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 lr, [sp, #-4]! @ @ @ @ subr1: STR … BL LDR subr2 pc, [sp], #4 push lr on the stack code subroutine 1 call subroutine 2 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 Les sous routines Informtique 3 Point de départ de l’exemple: PC = 0x2000, adresse de la sous routine 0x1000, SP = 0x3200 Adresse Code 0x2000 0x2004 0x1000 Opérations de pile au sein de subr1: 0x3200 1 0x31FC 0x00002004 lr auf 2 Stack sp-4 BL subr1 Next instruction ... subr1: 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 .set SVC_STACK_SIZE, 0x00000200 MODE_SVC, 0x13 @ stack size for supervisor mode @ supervisor mode Code de démarrage : LDR MSR MOV SUB r0, =_stack_top_address CPSR_c, #MODE_SVC sp, r0 r0, r0, # SVC_STACK_SIZE @ copy start address of stack into r0 @ switch to supervisor mode @ initialize supervisor stack pointer @ 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 Branch-and-Link Syntaxe BL subr_name push simple STR lr, [sp, #-4]! push multiple STMFD sp!, {r0-r2, lr} Variante: STMDB LDR pc, [sp], #4 pop simple + Adresse de retour pop multiple + Adresse de retour LDMFD sp!, {r0-r2, pc} Variante: LDMIA Opération lr Å Adresse de retour pc Å pc + distance de saut sp Å sp – 4 Stack Å Adresse de retour sp Å sp – n Stack Å Adresse de retour + registre de travail pc Å Adresse de retour sp Å sp + 4 return registre de travail Å Stack 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 Les sous routines Informtique 3 La pile de l’exemple de la Figure 76 contient les valeurs suivantes : sp 0x3200 return Adr 1 return Adr 1 sp 0x31FC Stack a) return Adr 2 b) sp 0x31F8 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: loop: MOV BL ADD CMP BNE ... r4, #0 subr3 r4, r4, #1 r4, #10 loop @ @ @ @ @ initialize loop variable r4 branch to subroutine increment loop variable check if 10 loops done no Æ branch to label loop lr, [sp, #-4]! @ push lr on the stack r4, #0 @ modify r4 pc, [sp], #4 @ return Sous routine 3 : subr3: STR ... MOV ... LDR 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 sousroutine, 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 cidessus, 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 ... MOV ... LDMFD sp!, {r4, lr} @ push registers to stack r4, #0 @ modify r4 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 Les sous routines Informtique 3 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 LDR BL r0, variable r0, [r0] mySubr @ r0 points to address of variable @ copy value of variable into r0 @ 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 sousroutine peut accéder à la variable originale. Exemple: programme principale : ADR BL r0, variable mySubr @ r0 points to address of variable @ 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 Les sous routines Informtique 3 Le programme appelant peut être défini en assembleur de la manière suivante : op1: op2: res: .word .word .word 2 5 0 ADR LDR ADR LDR ADR BL r0, r0, r1, r1, r2, sum @ 1st operand @ 2nd operand @ result main: op1 [r0] op2 [r1] res @ @ @ @ @ copy read copy read read address op1 into r0 value op1, 1st parameter r0 by value address op2 into r1 value op2, 2nd parameter r1 by value address res, 3rd parameter r2 by reference 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 ADD STR LDR lr, r3, r3, pc, [sp, #-4]! r0, r1 [r2] [sp], #4 @ @ @ @ push lr temp = op1 + op2 *res = temp 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 MOV ADD ADD ADD LDR ADD LDR ADD MOV LDMFD sp!, {r4, r5, lr} r4, r0 r4, r1 r4, r2 r4, r3 r5, [sp, #12] r4, r5 r5, [sp, #16] r4, r5 r0, r4 sp!, {r4, r5, pc} @ @ @ @ @ @ @ @ @ @ @ push r4, r5 and lr temp = p1 temp += p2 temp += p3 temp += p4 buffer = p5 temp += p5 buffer = p6 temp += p6 copy return value to r0 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 Les sous routines Informtique 3 = = = SP 0x3200 = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = SK= léÉê~å = Ç= = = RK= = léÉê~å = Ç= = = = = SP = = 0x31F8 = = = = = = = = = = = = = = = = = = = = = = = = = = = SK= léÉê~å Ç= RK= léÉê~å Ç= = äê= = = êR= êQ= SP 0x31EC = = = = = = = = NS= = = = NO= = = = U= = = = Q= = = = M= = = 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 r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 Nom APCS a1 a2 a3 a4 v1 v2 v3 v4 v5 Sb / tr / v6 v7 v8 Ip Sp Lr Pc Brève description Argument 1 / valeur de restitution à 32 bits/ registre scratch Argument 2 / valeur de restitution à 64 bits / registre scratch Argument 3 / registre scratch Argument 4 / registre scratch Variable registre 1 Variable registre 2 Variable registre 3 Variable registre 4 Variable registre 5 Dépend de la plateforme / Variable registre 6 Variable registre 7 Variable registre 8 Intra-Procedure-call / registre scratch Pointer de pile (stack pointer) Registre de reliage (link register) Compteur de programme (Program-Counter) Tableau 39 : Attribution de registre selon le standard APCS Version 3.1, juin 2008 Page 111 Les sous routines Informtique 3 • 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 SUB MOV ... ... ADD LDMFD sp!, {r11, lr} sp, sp, #40 r11, sp @ push r11 and return address, (1) @ allocate 10 * 4 bytes local variable space, (2) @ r11 points to first local variable, (3) sp, sp, #40 sp!, {r11, pc} @ free local variable space @ 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 2 SP neu lokaler Variablenbereich 1 3 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 Les interruptions et les exceptions Informtique 3 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 Les interruptions et les exceptions Informtique 3 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 Reset Data Abort FIQ (Fast Interrupt Request) IRQ (Interrupt Request) Prefetch Abort SWI (Software Interrupts) Instruction non définie Priorité 1 2 3 4 5 6 6 Mode du processeur Superviseur Abort FIQ IRQ Abort Superviseur 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 Les interruptions et les exceptions Informtique 3 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 Les interruptions et les exceptions Informtique 3 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). Fields Flags Status Extension Control Bit 31 30 29 28 7 6 5 N Z C V Q Function not used I Condition Flags 4 F T Interrupt Mask 0 Mode Processor 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). InterruptController InterruptQuelle CPU I/F-Bit ICMR InterruptVerarbeitung 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 Les interruptions et les exceptions Informtique 3 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 Reset Instruction non définie Interruption software Prefetch Abort Data Abort IRQ FIQ Adresse de vecteur 0xA0000000 0xA0000004 0xA0000008 0xA000000C 0xA0000010 0xA0000018 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: 0xA0000004: 0xA0000008: 0xA000000C: 0xA0000010: 0xA0000014: 0xA0000018: 0xA000001C: reset: undef: SWI: pabt: dabt: IRQ FIQ B B LDR B B B B B reset_handler und_handler pc, [pc, #swi_handler] pabt_handler dabt_handler notassigned irq_handler fiq_handler @ branch with 24-Bit offset @ indirect jump with LDR load to pc 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 Reset Instruction non définie Interruption software Pre fetch Abort Data Abort IRQ FIQ Adresse de retour lr lr lr - 4 lr - 8 lr - 4 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 Les interruptions et les exceptions Informtique 3 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 STMFD sp!, {r0-r3, r12, lr} ... <handler code> ... LDMFD sp!, {r0-r3, r12, pc}^ @ lr = lr -4, subtract offset for return address @ save context @ 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 IRQ instr 1 instr 2 instr3 LR = PC+4 Passage au mode IRQ SPSR_irq = CPSR PC = 0x00000018 PC = LR - 4 CPSR = SPSR_irq Retour au mode utilisateur Vector Table 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 Les interruptions et les exceptions Informtique 3 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 Les interruptions et les exceptions Informtique 3 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 Les interruptions et les exceptions Informtique 3 Nom ICIP Fonction IRQ Pending Reg. Adresse 0x40D0_0000 ICMR Mask Register 0x40D0_0004 ICLR Level Register 0x40D0_0008 ICFP FIQ Pending Reg. 0x40D0_000C ICPR Pending Register 0x40D0_0010 ICCR Control Register 0x40D0_0014 ICHP Highest Priority R. 0x40D0_0018 IPR0 IPR31 Priority Register 0 – 31 0x40D0_001C 0x40D0_0098 ICIP2 ICMR2 ICLR2 ICFP2 IPPR2 IPR32 – IPR39 IRQ Pending R. 2 Mask Register 2 Level Register 2 FIQ Pending Reg. 2 Pending Register 2 Priority Register 32 - 39 0x40D0_009C 0x40D0_00A0 0x40D0_00A4 0x40D0_00A8 0x40D0_00AC 0x40D0_00B0 0x40D0_00CC Brève description 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 Masquage ou activation des différentes sources d’interruption (1 bit par source) 0: masqué (disabled) 1: non masqué (enabled) Défini le type d’interruption (IRQ ou FIQ) généré par le composant périphérique 0: IRQ 1: FIQ 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 Montre l’état de toutes les sources d’interruption (1 bit par composant périphérique) 0: inactif 1: Interruption est activé Le bit de masquage Idle défini, si les interruptions doivent être activées indépendamment du registre de masquage (ICMR). 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). Défini la priorité d’un composant périphérique. Chaque priorité possède son propre registre IPRx, dans la quelle il faut introduire l’identité du composant qui génère l’interruption. comme ICIP comme ICMR comme ICLR comme ICFP comme ICIP comme IPRxx 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 Les interruptions et les exceptions Informtique 3 Interrupt 1 Disable Interrupts spsr_mode = cpsr pc = vector table entry 2 Save context 3 4 5 6 Interrupt Handler Interrupt Service Routine Restore context Enable Interrupts 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 STMFD LDR LDR TST BLNE TST ... LDMFD Version 3.1, juin 2008 lr, lr, #4 sp!, {r0-r3, r12, lr} r0, =ICIP r0, [r0] r0, #1<<PER_ID_OST timer_isr r0, <other source> @ @ @ @ @ @ @ adjust link register for return address save context load IRQ status register address read IRQ status register test if operating system timer (OST) caused IRQ if yes, call timer ISR test other IRQ sources sp!, {r0-r3, r12, pc}^ @ restore context and return 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 Les Structures de contrôle en assembleur Informtique 3 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 trueblock falseblock 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 (condition) { /* true-Block */ } else { /* false-Block */ } if: TST <condition> BNE ... B false true: false: @ true-block endif ... @ 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) { /* true-Block */ } if: true: TST BNE ... <condition> endif @ 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 Les Structures de contrôle en assembleur Informtique 3 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 MOVGT MOVLE r0, r1 r2, r0 r2, r1 @ if (a > b) @ c = a @ 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 block case const-expr2 const-expr2 block … default default block Figure 91 : La ramification multiple Exemple de code : Version 3.1, juin 2008 Page 129 Les Structures de contrôle en assembleur Informtique 3 C Assembler switch (expression) { case (const-expr1): ... break; case (const-expr2): ... break; ... default: ... break; } switch: case1: MOV r0, #expression CMP BEQ r0, #const_expr1 case1 CMP BEQ r0, #const_expr2 case2 ... B default ... B ... B ... case2: default: @ const-expr1 block endSwitch @ const-expr2 block endSwitch @ 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 MOV CMP LDR B case1: ... B case2: ... B default: ... endSwitch: ... r1, jumptable r0, #expression r0, #tablemax LO pc, [r1, r0, LSL #2] default jumptable: .word .word .word .set @ @ @ @ @ @ load r1 with base address of jump table load r0 with expression to test check if value is in jump table ok Æ load pc with label form jump table expression > tablemax Æ default const-expr1 block endSwitch @ const-expr2 block endSwitch @ default block default case1 case2 @ case 0 not defined Æ default 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 Les Structures de contrôle en assembleur Informtique 3 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 (condition) { // Corps de la boucle } while: TST <condition> BEQ … B endwhile @ Corps de la boucle 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: loop: test: B … TST BNE test Schleifenkörper <condition> 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 Les Structures de contrôle en assembleur Informtique 3 fois. Corps de la boucle Condition de la boucle Figure 93 : La boucle avec évaluation de la condition à la fin Exemple de code : C do { Assembler do: // Corps de la boucle } while (condition); … TST BNE while: @ Corps de la boucle <condition> 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) { // Corps de la boucle } for: loop: MOV CMP BGE ... ADD bra r0, #valeur_début r0, #valeur_fin endfor @ Corps de la boucle r0, r0, #pas 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 Les structures de données en assembleur Informtique 3 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 LDR MOV STR r0, r1, r2, r2, =array #2 #0 [r0, r1, LSL #2] @ @ @ @ load r0 with base address of array load r1 with index 2 value to write is 0 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 Les structures de données en assembleur Informtique 3 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 LDR LDR MOV STRB r0, r1, r2, r2, @ @ @ @ .text =array #2 #0 [r0, r1] load r0 with base address of array load r1 with index 2 value to write is 0 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] [1,0] [2,0] [0,1] [1,1] [2,1] [0,2] [1,2] [2,2] [0,3] [1,3] [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] [0,2] [0,3] [1,0] [1,1] [1,2] [1,3] [2,0] [2,1] [2,2] [2,3] 1. ligne 2. ligne 3. ligne 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 Les structures de données en assembleur Informtique 3 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 .byte .hword 14 03 1879 @ day as byte (1-31) @ month as byte (1-12) @ 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 .set OFFSET_MONTH, 1 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 MOV LDR H r1, =date r2, #OFFSET_YEAR r0, [r1, r2] @ load r1 with base address @ load r2 with offset @ 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 Les structures de données en assembleur Informtique 3 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 : stack: stackpointer: .set .data .space .word STACK_SIZE, 1000 @ define stack size STACK_SIZE, 0 stack + STACK_SIZE @ reserve address space for stack @ 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 de pile Adresses hautes Variable pile Adresses 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: stack_full: endpush: Version 3.1, juin 2008 STR LDR LDR LDR CMP BLE SUB STR STR B ... LDR lr, [sp, #-4]! r1, =stackpointer r2, [r1] r3, =stack r2, r3 stack_full r2, #4 r2, [r1] r0, [r2] endpush pc, [sp], #4 @ @ @ @ @ save return address on system-stack load r1 with stackpointer address load r2 with stackpointer value load r3 with stack address check if stack is already full @ @ @ @ @ @ decrement stackpointer (decrement before) save new stackpointer value push value to stack Æ end error code return Page 137 Les structures de données en assembleur Informtique 3 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: stack_ empty: endpop: STR LDR LDR LDR ADD CMP BGE LDR ADD STR B … LDR lr, [sp, #-4]! r1, =stackpointer r2, [r1] r3, =stack r3, #STACK_SIZE r2, r3 stack_empty r0, [r2] r2, #4 r2, [r1] end pop pc, [sp], #4 @ @ @ @ @ @ save return address on system-stack load r1 with stackpointer address load r2 with stackpointer value load r3 with stack address r3 holds stack top address check if stack is empty @ @ @ @ @ @ pop value from stack, r0 is return value increment stackpointer (increment after) save new stackpointer value Æ end error code 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 Les structures de données en assembleur Informtique 3 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. Apres écriture du premier élément Après l’initialisation Head 1. Element 2. Element Tail Head 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 / lecture 1 Tail / écriture 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 Le démarrage d’un programme C Informtique 3 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 Le démarrage d’un programme C Informtique 3 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 = .; . += FIQ_STACK_SIZE; . = ALIGN(4); _fiq_stack_top_address = .; ... @ IRQ-Stack top address @ reserver FIQ stack size @ 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 MSR MOV r0, =_fiq_stack_top_address CPSR_c, #MODE_FIQ|I_BIT|F_BIT sp, r0 @ load FIQ stack top address @ switch to FIQ mode, interrupts disabled @ 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 _data ROM/Flash .data /* variable globale à initialiser */ static int myInt = 5; _edata Valeur d’initialisation _etext 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 Le démarrage d’un programme C Informtique 3 = 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 Le démarrage d’un programme C Informtique 3 1er fonction de l’application ième n fonction de l’application ième n-1 fonction de l’application 2ième fonction de l’application 3ième fonction de l’application ISR 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 L’interface C et assembleur Informtique 3 .global .extern asmsub: STR ... BL ... LDR asmsub cfunc @ gives symbol external linkage @ specify that cfunc is defined in some other source code file lr, [sp, #-4]! @ assembler subroutine @ save return address on stack cfunc @ call C-function 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; extern int asm_var; void ctest_var(void){ ... asm_var = 0x22; c_var = 0x55; } // reserve memory for word-variable // specified in assembler source // modify assembler variable // modify C variable Code assembleur : Version 3.1, juin 2008 Page 147 L’interface C et assembleur Informtique 3 .global .extern ... asm_var c_var @ give asm_var external linkage @ specified in C source .data asm_var: .space 4, 0x11 @ global asm_var, initialized with 0x11111111 .text asmtest_var: STR LDR MOV STR LDR MOV STR LDR lr, r0, r1, r1, r0, r1, r1, pc, @ @ @ @ @ @ @ @ [sp, #-4] =c_var #0x55 [r0] =asm_var #0x11 [r0] [sp], #4 save return address on stack r0 holds address of variable c_var r1 holds value to write to c_var c_var = 0x55 r0 holds address of variable asm_var r1 holds value to write to asm_var asm_var = 0x11 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 L’interface C et assembleur Informtique 3 asm volatile ( "MOV r0, r0" "MOV r0, r0" ); "\n\t" "\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 LDR MSR r3, =status r3, [r3] 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 LDR AND LDR STR r3, r3, r2, r3, r2, =value [r3] r3, #255 =result [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 … led = 0x55; __attribute__ ((section (".LED"))) = 0; 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 ram : ORIGIN = 0xA0000000, LENGTH = 0x02000000 carmeIO1 : ORIGIN = 0x0C003000, LENGTH = 0x0410 } Version 3.1, juin 2008 /* 32 MB FLASH */ /* 64 MB RAM */ /* CARME IO1 */ Page 150 L’adressage des registres en C Informtique 3 Ensuite il faut spécifier la section .LED : .CARME_IO1 : { . = ALIGN(4); _carmeio1 = .; *(.LED) . += 0x1FF *(.SWITCH) . += 0x1FF *(.PIO) . += 0x10 } >carmeIO1 /* /* /* /* /* /* /* /* next 32-bit boundary */ defines a symbol for start of CARME IO1 */ LED section for CARME IO1 */ LED address is 0x0C003000 to 0x0C0031FF */ Switch section for CARME IO1 */ Switch address is 0x0C003200 to 0x0C0033FF */ PIO section for CARME IO1 */ PIO address is 0x0C003400 to 0xC003410 */ 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 fabriquant de mots clés spécifiques du 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 Annexe B: Les format des nombres Informtique 3 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 V 1 bit 23 22 E + 127 8 bits Représentation V E M 0 M 23 bits Description Bit de signe Exposant Mantisse Domaine des nombres 0: positif, 1: négatif -126 bis +127 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 ARM Architecture Reference Manual, ARM DDI 0100E Intel PXA27x Processor Family Developer's Manual Description détaillée des composants périphériques du chip, 1246 pages Intel PXA27x Processor Core Developer's Manual 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 Timings, pin out … 128 pages Intel PXA27x Processor Family Memory Subsystem Flash, LPSDRAM, 138 pages Intel XScale Microarchitecture Technical Summary, 14 pages Intel PXA27x Processor Family Design Guide Intel PXA27x Processor Developer's Kit Edition / Auteur ARM Limited Référence [1] Intel [2] Intel [3] Intel [4] Intel [5] Intel [6] Intel Intel [7] [8] Tableau 52 : Documentation Titre ARM System Developmer's Guide ISBN: 978-1-55860-874-0 ARM System on Chip Architecture ISBN: 0-201-67519-6 Edition / Auteur Sloss / Symes / Wright Morgan Kaufman Verlag Steve Furber Addison Wesley Référence [10] [11] Tableau 53 : La littérature Nom GNU Assembler http://www.gnu.org/software/binutils/manual/gas2.9.1/html_mono/as.html GNU Compiler http://gcc.gnu.org/onlinedocs/ Edition / Auteur GNU Référence [20] GNU [21] Tableau 54 : Les liens Internet Version 3.1, juin 2008 Page 154 Annexe D: Tableau des valeurs ASCII Informtique 3 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 Index Informtique 3 Index . 8 .2byte ............................... 93 .4byte ............................... 93 .align ............................... 90 .arm .................................... 89 .ascii ............................... 92 .asciz ............................... 92 .asm .................................... 57 .balign ............................. 91 .bin .................................... 58 .bss .................................... 95 .byte ................................. 93 .data ................................. 95 .elf .................................... 58 .else ............................... 100 .end .................................... 99 .endif ............................. 100 .endm ............................... 101 .equ .................................... 95 .extern ............................. 90 .global ............................. 90 .hword ............................... 93 .if .................................... 100 .ifndef ........................... 101 .include .......................... 94 .irp .................................. 104 .lis .................................... 57 .macro ............................. 101 .map .................................... 58 .o......................................... 57 .org .................................... 95 .p2align .......................... 92 .rept ............................... 103 .s......................................... 57 .section ............ 95, 96, 153 .section absolue .................. 153 .set .................................... 95 .space ............................... 94 .text ................................. 95 .thumb ............................... 89 .word ................................. 93 8051......................................28 _ __attribute__ ............ 153 _at .................................... 154 _at_ .................................. 154 = = 95 1 1 of X Decoder....................... 8 6 68HCxx................................ 28 Version 3.1, juin 2008 A abt.........................................39 Acknowledge bit ..................24 ADC ................................78, 79 ADD ................................78, 79 ADR ....................................102 adressage des registres .......153 adresse de retour.................106 adresse physique...................14 adresse virtuelle....................14 ALU .................................5, 36 amplificateur de sortie ..........18 AND ................................78, 81 anneau de tampons .............140 APCS..........107, 110, 112, 150 architecture.............................3 architecture ARM.................30 architecture de Harvard ..........4 architecture de stockage .......11 architecture de von Neumann.3 architecture RISC .................30 argument.............................113 arithmétique des entiers........78 ARM.....................................30 ARMV5TE...........................60 array ...................................136 ascending............................107 asm ....................................151 ASR ......................................67 assemblage conditionnel.....100 assembleur............................57 assembleur en ligne ............151 assignation des pins..............12 B B 84 Banked Register ...................41 Barrel Schifter ................36, 67 baud rate ...............................20 BIC ................................78, 81 big endian .............................43 binaire...................................55 bit .......................................155 bit C......................................42 bit d’état ...............................41 bit F ....................................119 bit I .....................................119 bit N......................................42 bit V......................................42 bit Z ......................................42 BKPT ....................................87 BL .................................84, 106 BLX ......................................84 bootloader...........................143 boucle .................................129 boucle d’itération............... 129 boucle do while ............ 134 boucle for ........................ 134 boucle while ................... 133 Branch Target Buffer........... 34 break point........................... 87 BSP.................................... 146 bus d’adresse ................... 6, 46 bus de contrôle....................... 6 bus de données................. 6, 46 BX ........................................ 84 byte .............................. 43, 155 C call by reference ................ 110 call by value....................... 110 callee.................................. 105 caller .................................. 105 caractérisiques AC............... 12 caractérisiques DC............... 12 carry..................................... 42 case mémoire ....................... 10 cercle de nombre.................. 42 chaîne de caractère ............ 138 champ des étiquettes............ 51 chip select .............................. 8 choix parmi une liste............ 62 CISC .................................... 27 clobber list ......................... 151 CLZ ...................................... 87 CMN ................................ 78, 79 CMP ................................ 78, 79 code d’opération .................. 62 code de condition................. 63 code de démarrage............. 144 code machine ................. 49, 57 code récursif ...................... 106 coeur .................................... 38 cœur d’exécution ................. 35 commentaire ........................ 53 compilateur .......................... 57 complément à deux.............. 55 complément à un.................. 55 compteur de program........... 41 compteur de programme 5, 113 condition.............................. 81 condition d’arrêt .................. 24 condition de démarrage ....... 24 Condition Flags ................... 41 constante........................ 53, 63 contexte ............................. 128 Contitional Execution .......... 42 control bus ............................. 6 contrôleur d’interruption...... 38 contrôleur d’interrutpion.... 124 convertisseur A/D................ 26 convertisseur D/A................ 26 coprocesseur ........................ 65 Coprocessor ......................... 35 Page 156 Index Informtique 3 Core Memory Bus................ 35 counter ................................. 25 CPSR ............................ 41, 119 CPU........................................ 4 CPU32.................................. 28 Cross Assembleur ................ 57 crt0 .................................. 144 CS........................................... 8 D Data Abord......................... 116 Data Cache ........................... 34 Debug................................... 35 débuggeur............................. 58 Decode ............................. 5, 37 décodeur d’adresse................. 8 déroulement d’une requête d’interruption ................. 123 descending.......................... 107 directive de l’assembleur ..... 88 directive de programmation . 50 disabled .............................. 119 dispositif de commande ......... 5 DMA .............................. 17, 39 DMMU................................. 34 do while ........................ 134 documentation...................... 12 DRAM ................................. 10 DSP .................................. 4, 27 E éditeur .................................. 56 EEPROM ............................... 9 empty ................................. 107 enabled ............................... 119 entrée et sortie digitale ......... 19 environnement de développement ................. 55 EOR ................................ 78, 81 EPROM.................................. 9 équation logique..................... 8 ET......................................... 81 état du processeur................. 41 évènement .......................... 116 exception ............................ 116 Exception Handler...... 116, 121 Execute............................. 5, 37 exécution conditionnelle ...... 42 Execution Core..................... 35 F famille de microcontrôleur... 27 famille de processeur ARM . 33 FeRAM ................................ 10 Fetch................................. 5, 37 fichier assembleur ................ 50 fichier de mappage ............... 58 fichier elf.............................. 58 fichier objet .......................... 57 FIQ ............................... 39, 116 FLASH................................. 10 FLOPS ................................. 29 Version 3.1, juin 2008 for ....................................135 FPU ........................................5 frame pointer ..............113, 150 frames...................................15 full ......................................107 G gestion de projet ...................58 gestionnaire de consommation ..........................................38 GPIO ....................................39 H halfword .......................43, 155 Header ..................................51 hexadécimal..........................93 hierarchie des composants de stockage............................13 I I2C ........................................23 ICLR ..................................118 IDE .......................................55 if .......................................130 IMMU ..................................34 indexation.............................62 initialisation des variables ..145 input operand list................151 instruction.........................1, 51 instruction ARM...................62 Instruction Cache..................34 instruction conditionnelle .....63 instruction d’état...................75 instruction de décalage .........82 instruction de transport entres registres ............................66 instruction logique................81 instruction non définie........116 instruction pour la pile..........74 instruction pour le coprocesseur .....................76 Instruction Unit ......................5 interface C/assembleur .......149 interface clavier ....................39 interface du bus ......................5 interface sériel ................20, 39 Interrupt Controller ............124 Interrupt Mask ......................41 Interrupt Service Routine ...116 Interrupt-Controller ..............38 interruption.........116, 118, 147 interruption hardware .........118 interruption software ...86, 116, 118 intructions de transfert de données.............................66 IRQ...............................39, 116 ISR .............................116, 147 J jeu d’instruction..............52, 60 jeu d’instruction Thumb .......64 JTAG ................................... 35 jump table .......................... 132 L langage de programmation évolué ...................... 49, 149 last in, first out................... 107 LCD Panel ........................... 39 LDC ................................ 66, 76 LDM ................................ 66, 72 LDR ........................... 66, 68 LDR B............................... 69 LDR H............................... 69 LDR SB ............................ 69 LDR SH ............................ 69 Link Register ....................... 41 Linker .................................. 58 Linkmap............................... 99 list file.................................. 57 listing de l’assembleur ......... 57 little endian .......................... 43 localisateur........................... 58 Locator................................. 58 logique ................................. 55 lower byte .......................... 155 LSL ...................................... 67 LSR ...................................... 67 M macro instruction ............... 101 main ................................. 144 manipulation des bits ........... 81 manuscrit de reliage............. 97 masquage des interruptions 119 MC683xx............................. 28 MCR ................................ 66, 76 mémoire cache..................... 13 mémoire de masse ............... 14 mémoire de travail............... 13 mémoire des données............. 3 mémoire non volatile ............. 9 mémoire programme.............. 3 mémoire volatile.................. 10 Memory Controller .............. 39 memory map.................... 7, 44 memory matrix .................... 10 microcontrôleur ................... 27 microprocesseur................... 27 MIMD.................................... 2 Mini D-Cache ...................... 34 MIPS.................................... 29 MISD ..................................... 2 MISO ................................... 22 MLA ................................ 78, 79 MMU ............................. 14, 34 mnemonics........................... 51 mode d’adressage ................ 70 mode d’utilisation................ 41 mode de fonctionnement ..... 39 mode privilégié.................... 39 modèle de stockage.............. 43 modulo................................. 55 Page 157 Index Informtique 3 MOSI ................................... 22 mot clé................................ 154 MOV ...................................... 66 MRAM................................. 10 MRC ................................ 66, 76 MRS ................................ 66, 75 MSP430 ............................... 28 MSR ................................ 66, 75 MUL ................................ 78, 79 Multiply-Accumulate ........... 35 MVN ...................................... 66 N negative................................ 42 nibble ................................. 155 nom de registre..................... 62 Nonnested Interrupt Handler ....................................... 127 NOT ...................................... 81 nul ...................................... 138 O open drain............................. 19 opérande......................... 36, 52 opérateur .............................. 54 opérateur assembleur.......... 100 opération .............................. 51 opération de décalage..... 63, 67 opération pop ..................... 140 opération push.................... 139 organisation de la mémoire .. 12 ORR ................................ 78, 81 OTP........................................ 9 OU........................................ 81 output operand list.............. 151 Overflow .............................. 42 P pages .................................... 15 paramètre............................ 111 périphérie ............................. 18 PIC ....................................... 28 pile ............................. 106, 139 pipeline................................. 36 plan de mémoire............... 7, 44 point d’arrêt.......................... 87 pointeur de pile ... 41, 107, 113, 150 pointeur de trame ............... 150 pop ..................................... 107 portable ................................ 49 post indexation ..................... 70 Power-Management ............. 38 pré indexation....................... 70 Prefetch Abord ................... 116 principe des contributions .. 110 priorité des interruptions .... 117 priorité des opérateurs.......... 55 processus de démarrage ..... 143 Program Counter ...... 5, 41, 150 programme principale ........ 146 pseudo code.......................... 49 Version 3.1, juin 2008 pseudo instruction ................88 push ....................................107 PWM ....................................39 Q QADD ..............................78, 79 QADDD ..................................78 QDADD ..................................79 QDSUB ..................................79 QDSUM ..................................78 QSUB ..............................78, 79 queue de tampons ...............140 R RAM.....................................10 ramification ........................129 ramification multiple ..........131 ramification simple.............130 Real Time Clock...................39 registre........................5, 13, 40 registre de reliage .41, 106, 113 registre fantôme....................41 registre scratch....................113 relieur ...................................58 reset ............................116, 143 ressource hardware.............148 retour de sous routine .........106 RISC.....................................27 ROM.......................................9 ROM-Processing ................145 ROR ......................................67 rotate.....................................82 RRX ......................................67 RS232...................................20 RSB ................................78, 79 RSC ................................78, 79 RTOS .................................146 S saut de programme ...............83 saut de programme absolu....83 saut de programme conditionel ..........................................82 saut de programme inconditionel.....................82 saut de programme relatif.....83 sauvegard des registres.......110 SBC ......................................79 Schifter .................................37 SD Memory Card .................39 SDRAM................................10 séquence d’instructions ......129 set de registre........................40 shift.......................................82 Sign Extend ..........................43 signal PWM..........................25 signé .....................................55 SIMD......................................1 SISD .......................................1 SMLA ..............................78, 79 SMLAL ............................78, 79 SMLAW ............................78, 79 SMUL ............................. 78, 79 SMULL ................................. 79 SMULW ........................... 78, 79 source d’erreurs ................. 114 sous programme................. 105 sous routine........................ 105 SPI ....................................... 21 SRAM.................................. 10 stack........................... 106, 139 stack pointer..........41, 107, 150 startup .......................... 144 startup code........................ 144 STC ................................ 66, 76 STM ................................ 66, 72 STR................................ 66, 68 STRB ................................... 69 STRD ................................... 69 STRH ................................... 69 string.................................. 138 structure ............................. 138 structure de contrôle .......... 129 structure de données .......... 136 structure de répétition ........ 102 SUB ................................ 78, 79 super pipeline....................... 36 svc........................................ 39 SWI...................................... 86 switch............................. 132 SWP ................................ 66, 72 SWPB ................................... 72 symbole ............................... 53 syntaxe................................. 62 syntaxe de l'assembleur ....... 51 sys........................................ 39 système d’exploitation temps réel ................................. 148 système de bus....................... 6 système faiblement couplé..... 2 système fortement couplé ...... 2 T table de vérité ...................... 12 Tableau .............................. 136 Tableau de page................... 15 Tableau de saut .................. 132 Tableau des vecteurs d’exeption ...................... 120 Tableau multidimensionnel 137 taille de la mémoire ............. 12 TDMI................................... 33 tension du bus ........................ 7 TEQ ...................................... 79 Timer ............................. 25, 39 TLB ..................................... 16 totem pole ............................ 19 Trace Buffer......................... 35 traitement d’exception ....... 116 transfert des paramètres ..... 110 transmission des paramètres ............................... 112, 150 tri state ................................. 19 TST ...................................... 79 Page 158 Index Informtique 3 U V UMLAL ................................. 79 UMLULL ............................... 78 UMULL ................................. 79 und ....................................... 39 unité de calcul ........................ 5 unité de contrôle..................... 5 upper byte........................... 155 usr......................................... 39 v5TE.....................................32 variable globale ..................150 variable locale ....................113 variable registre ..................113 vecteur d’exception ............120 vue d’ensemble des instructions .......................65 W while ................................133 Version 3.1, juin 2008 word............................. 43, 155 Write Back........................... 37 Write Buffer......................... 34 X XOR ...................................... 81 XScale ................................. 33 Z Zero ..................................... 42 zone mémoire ........................ 3 Page 159