Ordinateurs, Structure et Applications GIF-1001 Cours 8, Assembleur ARM ARM, MOV, LDR et ADD Etienne Tremblay Université Laval, Hiver 2014 GIF-1001 Cours 8, p.1 Contenu de la présentation • • • • • • • • Comme tout langage de programmation, l’assembleur ARM permet d’effectuer les opérations suivantes: Déclarer des variables et leur affecter des valeurs Effectuer des opérations mathématiques et logiques Gérer la séquence des opérations avec des énoncés conditionnels et des boucles Appeler des fonctions (diviser une tâche en sous-tâches) Gérer les évènements et les exceptions Cette présentation présente les deux premiers points. Les autres points sont vus dans les cours qui suivent. De nombreux documents sont disponibles sur internet et présentent l’assembleur ARM en détail (voir les références à la fin). GIF-1001 Cours 8, p.2 L’assembleur: des instructions en mots • • • Comme vu dans les cours précédents, le microprocesseur lit et exécute des instructions. Chaque instruction, en mémoire, est constituée d’un opcode et de paramètres qui dépendent de l’opcode. Il est donc possible d’écrire un programme en binaire si on sait comment représenter les instructions avec des « 0 » et des « 1 ». Toutefois, le processus est très pénible: qui voudrait écrire 0x23AB435F4EE7832FFA pour effectuer l’opération « a = b + c »? Un assembleur est un programme qui traduit des mots, en anglais, dans un fichier texte, en instructions. Il y a un mot, ou mnémonique, associé à chaque instruction. Pour effectuer a = b + c, il est beaucoup plus facile d’écrire: • • • • LDR R0, b LDR R1, c ADD R2, R0, R1 STR R2, a ; Lire la variable b dans le registre R0 ; Lire la variable c dans le registre R1 ; Registre R2 = R0 + R1 ; Écrire le registre R2 dans la variable a GIF-1001 Cours 8, p.3 Plus que des instructions en mots • Le langage assembleur fait plus que traduire des mots/mnémoniques en binaire. Il interprète aussi le texte de plusieurs façons: • L’assembleur permet d’associer des mots du programmeur à des adresses de mémoire. • L’assembleur permet au programmeur de déclarer des variables et il gère l’adresse de ces variables à travers les instructions du programme. • L’assembleur permet au programmeur d’identifier des fonctions ou des sections de codes avec des étiquettes (labels). Lorsque l’assembleur décode un appel de fonction ou un branchement (saut) dans le programme, il remplace les étiquettes par les adresses ou déplacements (offset) appropriées. • L’assembleur supporte des directives qui lui disent comment placer le code en mémoire, comment gérer plusieurs fichiers, comment précompiler le code –modifier le code avant de le traduire en binaire-, et plus. Les directives sont des mots réservés qui ne génèrent pas de code en binaire, mais dirige la création du code exécuté. • L’assembleur permet d’insérer des commentaires dans le code, ce qui est plus que nécessaire! GIF-1001 Cours 8, p.4 Un exemple de programme NAME main ;Nom du fichier/module PUBLIC __iar_program_start ;Rend l'étiquette __iar_program_start disponible pour d'autres fichiers SECTION .intvec : CODE (2) ;Le texte qui suit doit être assemblé dans la mémoire FLASH CODE32 ;Les instructions qui suivent sont sur 32 bits __iar_program_start B main ;Étiquette __iar_program_start: IAR commence le programme ici ;Saut/Branchement vers l'étiquette main ;MaVarA = MaVarB + MaVarC main LDR R0, MaVarB ;Lecture de mémoire, met MaVarB, 0x000000BB, dans R0 LDR R1, MaVarC ;Lecture de mémoire, met MaVarC, 0x000000CC, dans R1 ADD R2, R0, R1 ;R2 = R0 + R1 LDR R3,=MaVarA STR R2, [R3] ;Écriture de mémoire, met R2 (MaVarB + MaVarC) dand MaVarA B main ;Boucle infinie: retour à l'étiquette main DATA ;Le texte qui suit doit être assemblé comme des constantes en FLASH MaVarB DC32 0x000000BB MaVarC DC32 0x000000CC ; Déclaration de MaVarB, sur 32 bits, valeur initiale = 0xBB ;Déclaration de MaVarC sur 32 bits, valeur initiale = 0xCC SECTION `.noinit`:DATA(2) ;Variables en mémoire RAM! MaVarA DS32 1 ;Déclaration de MaVarA comme une variable de 1*32 bits END ;Fin du fichier/module GIF-1001 Cours 8, p.5 Types d’instructions • • • • • • • Il y a six types d’instructions dans l’assembleur ARM: Déplacement de données: Transfert de données ou de constante impliquant des registres seulement. Accès à la mémoire: l’instruction, un load ou store, lit ou écrit la mémoire. La valeur lue est mise dans un registre. La valeur écrite provient d’un registre. Opération arithmétique: addition, soustraction, multiplication, division et plus. Les calculs s’effectuent sur des registres et peuvent changer les drapeaux de l’unité d’arithmétique et de logique (ALU). Opération logique: ET, OU, NON-OU, OU EXCLUSIF et plus. Les calculs s’effectuent sur des registres et peuvent changer les drapeaux de l’unité d’arithmétique et de logique (ALU). Gestion de la séquence d’instructions: saut et branchements. Peuvent être conditionnels ou inconditionnels, à des adresses directes ou indirectes. Comprend les appels de fonctions. Contrôle du système: Comprend toutes les autres instructions contrôlant le microprocesseur. Permet de gérer le temps, le format des instructions, l’exécution en pipeline, les interruptions et plus. GIF-1001 Cours 8, p.6 Déplacement de Données: MOV • • • • • • • • • • • • L’instruction MOV Rn, Op1 met l’opérande de type 1 dans le registre visé: Rn = Op1 Op1 est une opérande de type 1: il s’agit d’une constante ou d’un registre. S’il s’agit d’un registre, il est possible de faire des décalages de bits (avec le « Barrel Shifter » de l’ALU) sur la valeur de l’opérande avant de faire l’affectation. Cinq opérations sont possibles: LSL, LSR, ASR, ROR et RRX. Ces opérations sont détaillées en Annexe A. Une constante (immédiate) est toujours précédée du symbole # Il existe deux options possibles pour MOV: exécution conditionnelle et changement des drapeaux. L’instruction MOVcc s’exécutera seulement si la condition décrite par cc est rencontrée (voir prochaine page). L’instruction MOVS change les drapeaux Exemples: MOV R0, #1234 ; R0 = 1234 MOV R0, R1 ; R0 = R1 MOV R0, R1, ASR #2 ; R0 = R1 / 4 MOVEQ R0, R1 ; R0 = R1 seulement si le drapeau Z est 1 MOVS R0, R1 ; R0 = R1, change les drapeaux de l’ALU GIF-1001 Cours 8, p.7 Code de Condition (CC) • • • Plusieurs instructions s’exécutent si une condition est rencontrée. Toutes les conditions sont évaluées à partir des drapeaux de L’ALU et assument que ceux-ci ont été déterminés auparavant. Par exemple, la condition EQ (equal) assume qu’une soustraction ou comparaison a été faite avant: si le résultat de l’opération est 0, le drapeau Z sera à 1 et la condition EQ sera rencontrée. • Les drapeaux N (Negative), Z (Zero), C (Carry) et V (Overflow) servent à évaluer toutes les conditions. • Les drapeaux et les conditons à évaluer changent si les nombres comparés son signés ou s’ils ne le sont pas. Voici la liste des codes de condition de l’assembleur ARM: Mnemonic CS EQ VS GT GE PL HI HS Condition Carry Set Equal (Zero Set) Overflow Set Greater Than Greater Than or Equal Plus (Positive) Higher Than Higher os Same (aka CS) Mnemonic CC NE VC LT LE MI LO LS Condition Carry Clear Not Equal (Zero Clear) Overflow Clear Less Than Less Than or Equal Minus (Negative) Lower Than (aka CC) Lower or Same GIF-1001 Cours 8, p.8 Déclaration de variables • • • Une variable est un nom donné à une adresse de mémoire. Il n’existe pas d’instruction pour créer ou manipuler des variables. Il n’existe que des instructions pour manipuler la mémoire. Les variables sont des créations du langage assembleur afin de faciliter la création d’un programme: Il est plus facile de retenir un nom qu’une adresse de mémoire!!! Avec l’assembleurs de ARM, la syntaxe pour déclarer une variable est: – nom DSss NombreDeMots pour déclarer une variable/tableau de taille ss ayant NombreDeMots. Exemple: MaTable DS32 3 réserve 3*32 bits de mémoire à l’adresse qui sera allouée à « MaTable ». – nom DCss valeur pour déclarer une constante de taille ss dont la valeur initiale est valeur et le nom est nom. • ss peut être 8, 16, 32, B, W, D… • • • La directive DC sert à un insérer des bytes dans la mémoire ROM du système. L’adresse de ces bytes est l’adresse de la constante. Il est possible, si l’on connaît les opcodes et les opérandes des instructions ARM, décrire un programme avec des DC! L’assembleur s’occupera de remplacer tous les noms des variables par les adresses correspondant à ces nom. Exemples: – – MonInt DC32 0x11223344 MonOctet DB 0x22 GIF-1001 Cours 8, p.9 Déclaration de variables: Tableaux • • Les tableaux peuvent être vus comme des chaînes de variables. Une chaîne texte est un exemple de tableau d'octets, chaque caractère est présenté comme un élément de code ASCII (0 à 255). Voici quelques exemples de définition d'un tableau de constantes: a DCB 48h, 65h, 6Ch, 6Ch, 6Fh, 00h b DCB 'Hello', 0 b est la copie exacte de a. Lorsque le compilateur voit une chaîne entourée par des guillemets, il la convertit automatiquement en un ensemble d'octets. • Voici quelques exemples de définition d'un tableau de données: MaTable DS32 8 MaTable2 DS8 Tiré du didacticiel de EMU8086 (MaTable aure 8 mots/int de 32 bits) 64 (MaTable2 aura 64 octets) GIF-1001 Cours 8, p.10 Accès Mémoire: Load/Store • • • • Les accès à la mémoire d’un processeur ARM se font avec deux instructions: LDR et STR. LDR (LoaD Register) lit la mémoire et met la valeur lue dans un registre. STR (STore Register) met la valeur d’un registre dans la mémoire. Ces instructions ont le format: LDR Rd, Op2 et STR Rs, Op2 – Rd et Rs décrivent le registre de destination ou de source – Op2 décrit l’adresse de mémoire ou de périphérique visée par l’instruction. Voir la prochaine acétate pour le détail. Les symboles « [ x ] » indiquent qu’il s’agit d’une adresse. Exemples: – LDR R1, [R2] ;R1 = Mémoire[R2] (l’adresse de mémoire désignée par R2) – LDR R1, [R2, #4] ;R1 = Mémoire[R2+4] – LDR R1, [R2, R3] ;R1 = Mémoire[R2+R3] GIF-1001 Cours 8, p.11 Opérande de type 2 • • • • Op2 symbolise tous les modes d’adressage du microprocesseur, c’est-à-dire toutes les façons permises pour désigner une adresse de la mémoire. LDR Rd, Op2 se découpe ainsi: LDR Rd, [Rb, Offset] – Rb est le registre de base – Offset est soit une constante, soit un registre, soit une opérande de type Op1 (un regisitre avec des bits décalés –voir précédemment-) • LDR R0, [R1, #123] ;Offset = constante • LDR R0, [R1, R2] ;Offset = Registre • LDR R0, [R1, R2 LSL #2] ;Offset = Op1 Rb et l’Offset s’additonnent toujours pour former l’adresse visée. Pour faciliter les accès aux tableaux, il est possible de changer le registre de base (Rb) avant ou après le calcul d’accès à la mémoire (pre-indexing ou post-indexing). Le symbole “!” indique du pre-indexing. Le post-indexing se fait en dehors des []. – – LDR R0, [R1, #4]! LDR R0, [R1], #4 ;R0 = Mem[R1 + 4] et R1 = R1 + 4 ;R0 = Mem[R1] et R1 = R1 + 4 GIF-1001 Cours 8, p.12 Accès Mémoire: Load/Store Multiple • • • • • • Les instructions LDM (LoaD Multiple) et STM (Store Multiple) permettent de lire des mots de mémoire contigus et de mettre les valeurs lues dans plusieurs registres. Une seule instruction LDM peut remplacer plusieurs instructions LDR si les adresses visées se suivent. Les instructions LDM et STM sont utilisés pour lire/écrire des données de tableaux ou pour sauvegarder/récupérer de l’information sur la pile (voir les prochains cours). Comme LDM et STM sont des instructions longues à exécuter par rapport aux autres instructions, elles sont traitées spécialement lors d’interruptions ou dans l’exécution en pipeline. LDM et STM peuvent s’exécuter conditionnellement, avec un mode d’exécution (comment incrémenter/décrémenter l’adresse entre chaque mot lu) et permettent de mettre à jour le registre décrivant l’adresse (symbole !). Syntaxe: LDMccmm Ra{!}, {Liste de registres}, mm = Decrement Before, Decrement After, Increment Before or Increment After Exemples: – STMDB SP!, {R0, R1} ;R0 = Mem[SP-4], R1 = Mem[SP-8], SP = SP-8 – LDMIA SP!, {R0, R1} ;R0 = Mem[SP], R1 = Mem[SP+4], SP = SP+8 GIF-1001 Cours 8, p.13 Accès Mémoire et Variables • • • Les instrctions LDR et STR sont utilisée avec la syntaxe suivante pour accéder aux variables: – LDR Rd, NomDeVariable ;Met la valeur de la variable dans Rd – LDR Rd, =NomDevariable ;Met l’adresse de la variable dans Rd Le symbole « = » utilisé dans l’instruction LDR ou STR indique « l’adresse de ». L’assembleur traduit la ligne « LDR Rd, NomDeVariable » ou « LDR Rd, =NomDeVariable » en plusieurs instructions du processeur: – Toutes les adresses sont sur 32 bits et toutes les instructions sont sur 16 bits ou 32 bits. Une instruction 32 bits ne peut pas contenir un opcode, un numéro de registre et une adresse de 32 bits… – Lors d’un LDR R0, MaVar, l’assembleur placera les items suivants en mémoire: • L’adresse de MaVar sera en mémoire code, définie comme une constante • Une instruction LDR Rd, [PC+Offset] mettra l’adresse de MaVar dans Rd. Ici, Offset est une constante qui dépend de la distance entre l’instruction LDR et l’adresse de MaVar (constante en code). • Une autre instruction LDR R0, [Rd] mettra la valeur de Mavar dans R0… GIF-1001 Cours 8, p.14 Instructions arithmétiques et logiques: principe • • • • • Les opérations mathématiques et logiques fonctionnent avec un registre de destination et deux opérandes. Le premier opérande est un registre et le deuxième est un opérande de type Op1 (une constante ou un registre décalé). Le format de l’instruction Add, par exemple, est: – Add Rd, Rs, Op1 Les instructions arithmétiques et logiques changent les drapeaux de l’ALU, lorsque l’option S est ajoutée (voir registre CSPR du cours 6). Les instructions arithmétiques et logiques peuvent s’exécuter conditionnellement. Exemples: – ADD R0, R1, R2 ;R0 = R1 + R2 – ADC R0, R1, #123 ;R0 = R1 + 123 + Carry – MVNS R0, R1 ;R0 = ~R1 ; Met à jour les drapeaux – EORLO R0, R1, R1 ;Si LOwer, R0 = R1 XOR R1 = 0 – ORRHI R0, R1, R2, ASR #1 ; Si HIgher, R0 = R1 OU (R2/2) GIF-1001 Cours 8, p.15 Exemple: Addition de variables sur 64 bits NAME Addition64bits ;Nom du fichier/module; Addition sur 64 bits en little endian PUBLIC Additonne64Bits ;Rend l'étiquette/fonction Additonne64Bits disponible pour d'autres fichiers SECTION .intvec : CODE (2) ;Le texte qui suit doit être assemblé dans la mémoire FLASH CODE32 ;Les instructions qui suivent sont sur 32 bits Additonne64Bits LDR R0, =MaVarOp1 ;Met l'adresse de MaVarOp1 dans R0 LDR R1, [R0] ;Met les 4 octets les moins signification d'Op1 dans R1 LDR R2, [R0,#4] ;Met les 4 octets les plus signification d'Op1 dans R2 LDR R0, =MaVarOp2 ;Met l'adresse de MaVarOp2 dans R0 LDR R3, [R0] ;Met les 4 octets les moins signification d'Op2 dans R3 LDR R4, [R0,#4] ;Met les 4 octets les plus signification d'Op2 dans R4 ADDS R5, R1,R3 ;R5 = R1 + R3, additionne les octets les moins significatifs et met à jour Carry ADC R6, R2,R4 ;Additionne les octets les plus significatifs avec la retenue LDR R0, =MaVarRes ;Met l'adresse du résultat dans R0 STR R5, [R0] ;Sauvegarde le résultat: bit les moins significatifs STR R6, [R0,#4] ;Sauvegarde le résultat: bit les plus significatifs BX LR ;Return DATA ;Le texte qui suit doit être assemblé dans la mémoire FLASH, constantes MaVarOp1 DCW MaVarOp2 DCW 0x11111111, 0x22222222 0x33333333, 0x44444444 ;Déclaration de l'opérande 1 sur 2 fois 32bits ;Déclaration de l'opérande 2 sur 2 fois 32bits SECTION `no_init`: DATA (2) ;Le texte qui suit doit être assemblé dans la mémoire RAM MaVarRes DS32 2 ;Déclaration du resultat sur 2 fois 32 bits END ;Fin du fichier/module GIF-1001 Cours 8, p.16 Références et exercices • Références pour l’assembleur – ARM Architecture Reference Manual, ARMv7-M_ARM.pdf – ARM, Assembly Langage Programming http://www.eng.auburn.edu/~nelson/courses/elec5260_6260/AR M_AssyLang.pdf – ARM, IAR Assembler http://supp.iar.com/FilesPublic/UPDINFO/005832/arm/doc/EWA RM_AssemblerReference.ENU.pdf GIF-1001 Cours 8, p.17 Annexe 1: Décalage de bits • • • • • LSL, Logical Shift Left, décale les bits vers la gauche et met des zéros à droite. Décaler un bit vers la gauche équivaut à multiplier par 2. Carry devient égal au bit le plus significatif. LSR, Logical Shift Right, décale les bits vers la droite et met des 0 à gauche. Décaler un bit vers la droite équivaut à diviser un nombre non-signé par 2. Carry devient égal au bit le moins significatif. ASR, Arithmetical Shift Right, décale les bits vers la droite et copie le bit le plus significatif à gauche. Décaler un bit vers la droite en conservant le bit de signe équivaut à diviser un nombre signé par 2. Carry devient égal au bit le moins significatif. ROR, Rotate Right, décale les bits vers la droite et met le Carry à gauche. Carry devient égal au bit le moins significatif. RRX, Rotate Right eXtended équivaut à ROR #1. GIF-1001 Cours 8, p.18