18/5/2015 Aide Mémoire du Programmeur - Cortex M3 Aide Mémoire du Programmeur - Cortex M3 J.L. Noullet - INSA Toulouse - révision 1.3 Le STM32 est une implémentation du Cortex M3, qui exécute un sous-ensemble du jeu d'instructions ARMv7-M ("M" pour "Microcontrôleur"). Ce jeu d'instruction utilise le codage Thumb-2, contenant le jeu simplifié Thumb codé sur 16 bits, et un ensemble de codes complémentaire sur 32 bits. 1. Mnémoniques classés par catégories Les instructions soulignées acceptent le suffixe S pour mise à jour des flags (NZCV). Copie de données (32 bits) MOV LDR, STR LDM, STM PUSH, POP de registre à registre ou immédiat vers registre Load (RAM vers registre), Store (registre vers RAM) Load et Store multiples (liste de registres), indirects cas particuliers de STM et LDM Copie et manipulation de byte (8 bits) et half-word (16 bits) LDR, STR MOVT REV SXT, UXT avec suffixes B, H, SB, SH T=Top, affecte seulement les 16 MSBs permutation de bytes extension à 32 bits signée ou non-signée (suff. B et H) Manipulation de bits BFC, BFI, SBFX, UBFX CLZ, RBIT bit fields (Clear, Insert, Extract) comptage des zéros en tête, permutation de bits Arithmétique ADD, ADC SUB, SBC, RSB MUL, MLA, MLS UMULL, UMLAL SMULL, SMLAL SDIV, UDIV SSAT, USAT C=Carry (inclusion dans la somme) C=Carry, R=reverse ( Rm-Rn au lieu de Rn-Rm ) résultat modulo 2^32 (débordement possible), A=Accumulation résultat 64 bits (débordement impossible), A=Accumulation résultat 64 bits (débordement impossible), A=Accumulation AND, BIC ORR, ORN EOR MVN BIC = AND NOT ORN = OR NOT XOR NOT LSL, LSR, ASR, ROR RRX décalage constant ou variable, de 1 à 31 positions rotation de 1 position via le flag C saturation taille arbitraire < 32 bits Logique Décalages Tests sur data TST, TEQ CMP, CMN CBZ, CBNZ comme ANDS et EORS mais resultat non conservé (pas de Rd) comme SUBS et ADDS mais resultat non conservé (pas de Rd) Comparaison registre avec zéro puis branch Sauts "Branch" B, BX BL, BLX CBZ, CBNZ TBB, TBH X=Indirect L=Link (sauvegarde PC dans LR) Comparaison registre avec zéro puis branch Table Branch : branchement indirect par table d'adresses NOP IT SVC MSR, MRS WFE, WFI ADR If-Then interruption soft accés au registre des flags mise en veille Divers file:///F:/memo_cm3.html 1/6 18/5/2015 Aide Mémoire du Programmeur - Cortex M3 2. Syntaxe de codage des instructions 2.1 Suffixes des mnémoniques (à coller sans espace) : taille du transfer : B, H, D pour 8 bits (Byte), 16 bits (Half-word), 64 bits (Double-word) (Attention : conflit avec la notation Microsoft utilisée par Keil : WORD = 16 bits, DWORD = 32 bits) SB, SH pour les extensions de signe à 32 bits, 16 pour opération effectuée en parallèle sur les deux moitiés d'un mot de 32 bits mise a jour optionnelle des flags : S incrémentation ou décrémentation pour les Load et Store Multiples LDM et STM : IA : Increment After DB : Decrement Before codes de condition sur 2 caractères (voir 2.8 traitements conditionnels) : . EQ Z=1 Equal NE Z=0 Not equal HI C = 1 and Z = 0 Higher unsigned CS or HS C = 1 Higher or same unsigned LS C = 0 or Z = 1 Lower or same unsigned CC or LO C = 0 Lower unsigned MI N=1 Negative signed PL N=0 Positive or zero signed VS V=1 Overflow signed VC V=0 No overflow signed GT Z = 0 and N = V Greater than signed GE N=V Greater than or equal signed LE Z = 1 or N != V Less than or equal signed LT N != V Less than signed forçage de taille pour le codage instruction .W : forcer 32 bits "Wide" (si disponible) .N : forcer 16 bits "Narrow" (si possible) 2.2 Registre destination Le premier registre de la liste va recevoir le résultat, SAUF dans le cas STR (Store). Ce cas particulier est dû à un codage homogène pour LDR et STR : LDR STR r0, [r1, #4] r0, [r1, #4] ; Load : registre <-- mémoire ; Store : registre --> mémoire La seconde instruction fait l'opération inverse de la première. 2.3 Forme simplifiée 2 opérandes au lieu de 3 De nombreuses instructions prennent 2 opérandes sources et 1 opérande destination : ADD Rd, Rn, Rm ; Rd = Rn + Rm Si on donne seulement 2 opérandes : ADD Rd, Rm ; Rd = Rd + Rm soit Rd += Rm l'assembleur met Rd à la position de Rn : ADD file:///F:/memo_cm3.html Rd, Rd, Rm ; Rd += Rm 2/6 18/5/2015 Aide Mémoire du Programmeur - Cortex M3 2.4 Modes d'adressage immediat ou littéral constante ou expression constante (signe '#') MOV MOV MOV r0, #0x4F r1, #112 r2, #(12*3+5) ; hexa ; decimal ; expression calculee pendant l'assemblage Attention aux limitations dues au codage sur 12 bits (soit une constante 8 bits décalée ou dupliquée). Il existe une variante "Wide" acceptant une constante de 16 bits : MOVW r3, #0x8001 ; (l'assembleur sait remplacer MOV par MOVW si nécessaire) constante de 32 bits en 2 opérations MOVW MOVT r0, #0x2013 r0, #0x1963 ; 0x00002013 dans r0 (imm16) ; 0x19632013 dans r0 (imm16) macro LDR et litteral pool (signe '=') LDR r0, =0x19632013 En fonction de la valeur de la constante, l'assembleur va remplacer cette pseudo-instruction (macro) par un MOV, un MOVW, ou un LDR avec adressage relatif-PC pour chercher la constante dans le litteral pool. Le litteral pool est une zone de données constantes que l'assembleur peut créer automatiquement dans la section courante, pour faciliter l'introduction de constantes 2.5 Modes d'adressage registre Simple : MOV r0, r1 ; copie de r1 dans r0 avec décalage ou rotation du registre source : MOV MOV MOV r0, r1, LSL #4 ; copie de r1, décalé de 4 bits a gauche, dans r0 r0, r1, LSR r5 ; copie de r1, décalé de r5 bits a droite, dans r0 r0, r1, RRX ; copie de r1, avec rotation a droite de 1 bit, dans r0 LSL Logic Shift Left LSR Logic Shift Right (unsigned) ASR Arithmetic Shift Right (sign extension) ROR Rotate Right over 32 bits RRX Rotate Right 1 place over 33 bits (C flag included) Note : on pourrait donc se passer des instructions LSL, LSR, ASR, ROR, RRX... Rappel : les décalages permettent de faire des multiplications et divisions par les puissances de 2 très efficacement. 2.6 Modes d'adressage mémoire 1 registre LDR r1, [r7] ; les crochets '[' et ']' signalent l'indirection 2 registres ("pre-indexed"), le second (index) peut être décalé à gauche LDR LDR LDR r1, [r6, r7] r1, [r6, r7, LSL #2] r1, [r6, r7]! ; adresse = r6 + r7, par exemple base + index ; adresse = r6 + r7 * 4 ; le '!' signale mise a jour de r6 = r6 + r7 Note : dans le 3eme cas, r7 est un incrément plutôt qu'un index, c'est pour parcourir un tableau séquentiellement. 1 registre + 1 constante (déplacement ou offset signé) LDR LDR LDR r1, [r6, #120] r1, [r6, #4]! r1, [r6], #4 ; acces à un membre d'une structure ou objet C++ ; pré-indexation, le '!' signale mise a jour de r6 = r6 + 4 ; post-indexation, adresse = r6, puis r6 = r6 + 4 Note : dans le 2eme et le 3eme cas, la constante est un decrément plutôt qu'un index, c'est pour parcourir un tableau séquentiellement: r1 = *(++r6) r1 = *(r6++) file:///F:/memo_cm3.html // comme on l'écrirait en C 3/6 18/5/2015 Aide Mémoire du Programmeur - Cortex M3 application particulière : adressage relatif-PC pour une donnée en ROM Dans le cas d'un code relogeable, ni l'adresse associée à un label ni celle de l'instruction courante ne sont connues au moment de l'assemblage, mais la différence l'est, l'assembleur peut donc calculer un déplacement à additionner au contenu du registre PC pour accéder à la donnée : labul dcd ... LDR 0x0561559513 r0, labul ; copie dans r0 la variable labul stockée en ROM Le code produit sera équivalent à : LDR r0, [PC, #(labul-.-K)] ; . = adresse instr. courante, K = constante (2 ou 4) La valeur de K dépend de l'alignement. Cette technique est utilisée pour le litteral pool (macro LDR avec sign '=', voir ci-dessus) Load/Store Multiples (par dérogation au style RISC) Attention : la syntaxe de ces instructions n'est pas cohérente avec le reste du jeu d'instructions. LDM r7, {r0, r1, r2, r4} LDM STM r7!, {r0, r1, r2, r4} r7, {r0, r1, r2, r4} STM r7!, {r0, r1, r2, r4} ; charger les registres de la liste avec les valeurs lues en mémoire, à partir de l'adresse de base donnée par r7 ; idem, puis mettre a jour r7 ; stocker le contenu des registres de la liste en mémoire, à partir de l'adresse de base donnée par r7 ; idem, puis mettre a jour r7 Ces instructions acceptent les suffixes DB (Decrement Before) et IA (Increment After), qui est le choix par défaut. La liste de registres entres accolades '{' et '}' peut contenir 1 à 15 registres (tous sauf SP). Attention : l'ordre des registres stockés ou lus en mémoire par une instruction multiple est toujours tel que les adresses mémoire croissent dans le sens des indices des registres (c'est indépendant de l'ordre des éléments de la liste, qui est ignoré). Push et Pop L'empilage (Push) et le dépilage (Pop) sont des applications de Store Multiple et Load Multiple avec SP et '!' PUSH STMDB POP LDM {r1, r2} SP!, {r1, r2} {r1, r2} SP!, {r1, r2} ; empiler r1 et r2 (r2 en premier, c'est a dire à l'adresse max) ; idem, DB choisi pour "full descending stack" ; dépiler r1 et r2 (r2 en dernier, c'est a dire de l'adresse max) ; idem, IA choisi pour "full descending stack" Le dépilage de PC est équivalent à un saut indirect utilisant une valeur prise dans la pile, ce qui peut tenir lieu de retour de sous-programme à condition d'avoir empilé LR en début de sous-programme. On peut en profiter pour empiler quelques registres : PUSH ... ... POP {r4, r5, r6, LR} ; au début du sous-programme {r4, r5, r6, PC} ; retour du sous-programme 2.7 Instruction de saut : "Branch" B Bcc BL BX BX BLX unlabel ; un saut direct (codé en relatif) unlabel ; saut conditionnel, cc est une condition parmi les 14 possibles (voir suffixes ci-dessus) unlabel ; appel de sous programme (adresse retour copiée dans LR) r3 ; saut indirect par registre (par exemple r3) LR ; retour de sous programme simple r3 ; appel de sous programme indirect par registre (adr retour dans LR) Notes : Historiquement, le X est pour "exchange" car BX et BLX permettent de changer de jeu d'instruction. En Thumb-2 il n'est pas question de cela, on peut considérer que le X signifie simplement indirect par registre. Contrairement à la majorité des autres architectures, l'ARM n'a pas d'intruction de retour de sous programme, le retour se fait avec BX LR si l'adresse de retour est dans LR, ou POP {PC] si elle est dans le pile. Contrairement à la majorité des autres architectures, l'ARM n'a pas d'intruction de retour d'interruption, le retour d'interruption se fait comme un retour de sous-programme ordinaire, c'est dans l'adresse de retour qu'il y a un code spécifique pour appliquer le traitement approprié aux interruptions. file:///F:/memo_cm3.html 4/6 18/5/2015 Aide Mémoire du Programmeur - Cortex M3 2.8 Traitements conditionnels Dans le jeu d'instructions ARM 32 bits, presque toutes les instructions peuvent être conditionnelles (ce qui encombre 4 bits dans l'encodage des instruction). Pour rendre le code plus compact, en Thumb-2 il n'y a que l'instruction B (Branch) qui contienne l'encodage d'une condition parmi les 14 possibles (voir suffixes ci-dessus). Cela couvre déjà la majorité des besoins en matière de traitement conditionnel. Pour compenser cette restriction, l'instruction spéciale IT (If-Then) a été ajoutée, elle permet de rendre conditionnelles 1 à 4 instructions consécutives : le nombre de lettres après le I détermine le nombre d'instructions concernées les lettres permises sont T (Then) et E (Else), la première est toujours T l'instruction IT prend comme argument 1 code condition parmi les 14 possibles chaque instruction associée à un T sera exécutée si la condition est vraie chaque instruction associée à un E sera exécutée si la condition n'est pas vraie Pour que le langage d'assemblage reste compatible avec le jeu d'instructions ARM classique, on applique les règles suivantes : L'assembleur génère l'instruction IT lui-même, on peut l'omettre du code source Chaque instruction du bloc IT est doit être munie d'un suffixe indiquant la condition qui doit lui être appliquée Exemple : ajouter a r0 la valeur absolue de r1 : MOVS r1, r1 ADDPL SUBMI r0, r1 r0, r1 ; l'assembleur insérera automatiquement l'instruction ITE PL Indépendamment de cela il existe 2 instructions combinées effectuant comparaison à zéro et branch, celles-ci ne supportent que 2 conditions : CBZ : compare register with zero, branch if zero CBNZ : compare register with zero, branch if not zero 3. Conventions d'appel de procédures et fonctions 3.1 Empilage différé (ARM) L'architecture ARM préconise un registre dédié (LR pour Link Register) pour l'adresse de retour. A charge pour la fonction appelée d'empiler la valeur de ce registre si elle même doit en appeler une autre. Le gain d'efficacité concerne seulement les fonctions "feuilles" (leaf subroutines), c'est à dire celles qui n'en appellent aucune autre). Exemples de code : appel de fonction (dans tous les cas) BL myfunction ; branch-and-link, update LR corps de la fonction fonction "feuille" ... ... BX LR ; indirect jump to [LR] {LR} ; empiler l'adresse de retour fonction quelconque PUSH ... BL ... POP myfunction2 {PC} ; dépiler directement dans PC Note : chez ARM, le bit de faible poids de PC n'est pas utilisé pour accéder aux instructions (dont les adresses sont obligatoirement paires) mais il sert à signaler l'utilisation du jeu d'instructions Thumb ou Thumb-2 (Cortex M3). file:///F:/memo_cm3.html 5/6 18/5/2015 Aide Mémoire du Programmeur - Cortex M3 3.2 Arguments et registres Résumé très simplifié de l'AAPCS (ARM Architecture Procedure Call Standard) : arguments : les premiers sont passés dans R0 à R3, les suivants dans la pile si nécessaire (les arguments de 64 bits peuvent être passés dans 2 registres consécutifs) valeur de retour : elle est passée dans R0 (ou R0 et R1 si 64 bits) registres dont le contenu doit être préservé : R4 à R11, SP et LR Par conséquent, dans le corps d'une fonction : R0 à R3 et R12 peuvent être utilisés librement comme stockage temporaire entre les appels de fonctions, par contre leur contenu rsique d'être altéré par les fonctions appelées, R4 à R11 peuvent être utilisés comme stockage temporaire à condition de les sauvegarder (push) pour les restituer (pop) avant le retour, LR doit être sauvegardé si la fonction doit en appeler une autre, SP doit être restitué dans son état initial, en particulier tout ce qui a été empilé doit être dépilé avant le retour. 4. Directives d'assemblage RealView (Keil) Entête Commentaire as (GNU) thumb ; ... fin de ligne .syntax unified .arch armv7-m .cpu cortex-m3 .thumb ;@ ...fin de ligne /* ou comme en C */ Inclusion de fichier include myfile .include Sections area area area .text .section .section moncode,code,readonly mesdata,data,readonly maram,data,readwrite align Alignement monlabel Création label Création constante maconst equ 0x1234 Donnée initialisée dcd dcw dcb Export export myfunc Import Procédure (pour le debugger) Fin 0x1234abcd 0x1234 0x12 extern hisfunc import hisfunc myfunc proc myfile .align monlabel: maconst = 0x1234 .long 0x1234abcd .short 0x1234 .byte 0x12 .global myfunc .func myfunc endp end .end Attention : avec l'assembleur GNU as : les directives commencent par un point '.' les labels doivent avoir un ':' à l'endroit de leur création, mais pas lorsqu'on y fait référence. file:///F:/memo_cm3.html 6/6