Arm assembler kommandon. Studerar instruktionsuppsättningen för ARM-processorn. Grundläggande regler för att skriva program i assembler

Hej alla!
Till mitt yrke är jag Java-programmerare. De senaste månadernas arbete tvingade mig att bekanta mig med att utveckla för Android NDK och följaktligen skriva infödda applikationer i C. Här ställdes jag inför problemet med att optimera Linux-bibliotek. Många visade sig vara helt ooptimerade för ARM och belastade processorn hårt. Tidigare hade jag praktiskt taget aldrig programmerat i assemblerspråk, så till en början var det svårt att börja lära mig det här språket, men jag bestämde mig ändå för att försöka. Den här artikeln skrevs så att säga från en nybörjare för nybörjare. Jag ska försöka beskriva grunderna som jag redan har lärt mig, jag hoppas att detta kommer att intressera någon. Dessutom tar jag gärna emot konstruktiv kritik från proffs.

Introduktion
Så låt oss först ta reda på vad ARM är. Wikipedia ger denna definition:

ARM-arkitektur (Advanced RISC Machine, Acorn RISC Machine, avancerad RISC-maskin) är en familj av licensierade 32-bitars och 64-bitars mikroprocessorkärnor utvecklade av ARM Limited. Företaget utvecklar exklusivt kärnor och verktyg för dem (kompilatorer, felsökningsverktyg, etc.), och tjänar pengar genom att licensiera arkitekturen till tredjepartstillverkare.

Om någon inte vet, nu de flesta Mobil enheter, surfplattor är utformade specifikt för denna processorarkitektur. Den största fördelen med denna familj är låg energiförbrukning, på grund av vilket det ofta används i olika inbyggda system. Arkitekturen har utvecklats över tiden, och från och med ARMv7 har 3 profiler definierats: 'A' (applikation) - applikationer, 'R' (realtid) - realtid, 'M' (mikrokontroller) - mikrokontroller. Du kan läsa historien om utvecklingen av denna teknik och annan intressant data på Wikipedia eller genom att googla den på Internet. ARM stöder olika driftlägen (Thumb och ARM, dessutom har Thumb-2 nyligen dykt upp, som är en blandning av ARM och Thumb). I den här artikeln kommer vi att titta på själva ARM-läget, där en 32-bitars instruktionsuppsättning exekveras.

Varje ARM-processor skapas från följande block:

  • 37 register (varav endast 17 är synliga under utveckling)
  • Aritmetisk logisk enhet (ALU) - utför aritmetiska och logiska uppgifter
  • Barrel shifter - en enhet utformad för att flytta datablock ett visst antal bitar
  • CP15 är ett speciellt system som styr ARM-samprocessorer
  • Instruktionsavkodare - handlar om att konvertera instruktioner till en sekvens av mikrooperationer
Dessa är inte alla komponenter i ARM, men att fördjupa sig i djungeln av processorkonstruktion ligger utanför ramen för denna artikel.
Utförande av pipeline
ARM-processorer använder en 3-stegs pipeline (börjar med ARM8, en 5-stegs pipeline implementerades). Låt oss titta på en enkel pipeline med ARM7TDMI-processorn som exempel. Utförandet av varje instruktion består av tre steg:

1. Provtagningssteg (F)
I detta skede flödar instruktioner från RAM till processorpipeline.
2. Avkodningssteg (D)
Instruktionerna avkodas och deras typ känns igen.
3. Utförandefas (E)
Data kommer in i ALU och exekveras och det resulterande värdet skrivs till det specificerade registret.

Men när man utvecklar måste man ta hänsyn till att det finns instruktioner som använder flera exekveringscykler, till exempel load(LDR) eller store. I detta fall är exekveringssteget (E) uppdelat i steg (E1, E2, E3...).

Villkorligt utförande
En av de viktigaste funktionerna hos ARM-montören är villkorad utförande. Varje instruktion kan köras villkorligt och suffix används för detta. Om ett suffix läggs till i namnet på en instruktion, kontrolleras parametrarna innan den körs. Om parametrarna inte uppfyller villkoret exekveras inte instruktionen. Suffix:
MI - negativt tal
PL - positiv eller noll
AL - utför alltid instruktioner
Det finns många fler villkorliga exekveringssuffix. Läs resten av suffixen och exemplen i den officiella dokumentationen: ARM-dokumentation
Nu är det dags att fundera...
Grundläggande ARM assembler syntax
För de som har arbetat med assembler tidigare kan du faktiskt hoppa över denna punkt. För alla andra kommer jag att beskriva grunderna för att arbeta med detta språk. Så varje assemblerprogram består av instruktioner. Instruktionen skapas på detta sätt:
(etikett) (instruktion|operander) (@kommentar)
Etikett är en valfri parameter. Instruktion är en direkt mnemonic av instruktioner till processorn. Grundläggande instruktioner och deras användning kommer att diskuteras nedan. Operander - konstanter, registeradresser, adresser in random access minne. En kommentar är en valfri parameter som inte påverkar programexekveringen.
Registrera namn
Följande registernamn är tillåtna:
1.r0-r15

3.v1-v8 (variabelregister, r4 till r11)

4.sb och SB (statiskt register, r9)

5.sl och SL (r10)

6.fp och FP (r11)

7.ip och IP (r12)

8.sp och SP (r13)

9.lr och LR (r14)

10.st och PC (programräknare, r15).

Variabler och konstanter
I ARM assembler kan variabler och konstanter användas, precis som vilket som helst (praktiskt sett) annat programmeringsspråk. De är indelade i följande typer:
  • Numerisk
  • hjärngymnastik
  • Sträng
Numeriska variabler initieras så här:
en SETA 100; en numerisk variabel "a" skapas med värdet 100.
Strängvariabler:
osannolik SETS "bokstavlig"; en variabel improb skapas med värdet "literal". UPPMÄRKSAMHET! Variabelvärdet får inte överstiga 5120 tecken.
Booleska variabler använder värdena TRUE respektive FALSE.
Exempel på ARM assembler instruktioner
I den här tabellen har jag samlat de grundläggande instruktionerna som kommer att krävas för vidare utveckling (i det mest grundläggande skedet:):

För att förstärka användningen av grundläggande instruktioner, låt oss skriva några enkla exempel, men först behöver vi en armverktygskedja. Jag arbetar på Linux så jag valde: frank.harvard.edu/~coldwell/toolchain (arm-unknown-linux-gnu toolchain). Det kan installeras lika enkelt som vilket annat program som helst på Linux. I mitt fall (ryska Fedora) behövde jag bara installera rpm-paket från webbplatsen.
Nu är det dags att skriva ett enkelt exempel. Programmet kommer att vara helt värdelöst, men huvudsaken är att det kommer att fungera :) Här är koden som jag erbjuder dig:
start: @ Valfri rad som indikerar början av programmet mov r0, #3 @ Ladda register r0 med värdet 3 mov r1, #2 @ Gör samma sak med register r1, bara nu med värdet 2 addera r2, r1, r0 @ Lägg till värdena för r0 och r1, svaret skrivs till r2 mul r3, r1, r0 @ Multiplicera värdet på register r1 med värdet på register r0, svaret skrivs till r3 stop: b stop @ Programavslutningsrad
Vi kompilerar programmet för att få .bin-filen:
/usr/arm/bin/arm-unknown-linux-gnu-as -o arm.o arm.s /usr/arm/bin/arm-unknown-linux-gnu-ld -Ttext=0x0 -o ​​​​arm. elf arm .o /usr/arm/bin/arm-unknown-linux-gnu-objcopy -O binär arm.elf arm.bin
(koden finns i arm.s-filen, och verktygskedjan i mitt fall finns i katalogen /usr/arm/bin/)
Om allt gick bra kommer du att ha 3 filer: arm.s (den faktiska koden), arm.o, arm.elf, arm.bin (det faktiska körbara programmet). För att kontrollera programmets funktion är det inte nödvändigt att ha en egen armanordning. Det räcker med att installera QEMU. Som referens:

QEMU- gratis mjukvaraöppen källkod för att emulera hårdvara från olika plattformar.

Inkluderar emulering Intel-processorer x86 och I/O-enheter. Kan emulera 80386, 80486, Pentium, Pentium Pro, AMD64 och andra x86-kompatibla processorer; PowerPC, ARM, MIPS, SPARC, SPARC64, m68k - endast delvis.

Fungerar på Syllable, FreeBSD, FreeDOS, Linux, Windows 9x, Windows 2000, Mac OS X, QNX, Android, etc.

Så för att emulera arm behöver du qemu-system-arm. Det här paketet är i yum, så för de som har Fedora behöver du inte bry dig och bara köra kommandot:
mums installera qemu-system-arm

Därefter måste vi starta ARM-emulatorn så att den kör vårt arm.bin-program. För att göra detta kommer vi att skapa en fil flash.bin, som kommer att vara flashminne för QEMU. Det är väldigt enkelt att göra så här:
dd if=/dev/zero of=flash.bin bs=4096 count=4096 dd if=arm.bin of=flash.bin bs=4096 conv=notrunc
Nu laddar vi QEMU med det resulterande flashminnet:
qemu-system-arm -M connex -pflash flash.bin -nografisk -seriell /dev/null
Utgången blir ungefär så här:

$ qemu-system-arm -M connex -pflash flash.bin -nografisk -seriell /dev/null
QEMU 0.15.1 monitor - skriv "hjälp" för mer information
(qemu)

Vårt arm.bin-program var tvungen att ändra värdena för fyra register, därför, för att kontrollera korrekt operation, låt oss titta på samma register. Detta görs med ett mycket enkelt kommando: inforegister
Vid utgången kommer du att se alla 15 ARM-register, och fyra av dem kommer att ha ändrade värden. Kontrollera :) Registervärdena matchar de som kan förväntas efter programkörning:
(qemu) inforegister R00=00000003 R01=00000002 R02=00000005 R03=00000006 R04=00000000 R05=00000000 R06=000000000 R07=000000 R07=00000 R07=00000 R07=00000 0000 R10=00000000 R11=00000000 R12=00000000 R13=00000000 R14= 00000000 R15=00000010 PSR=400001d3 -Z-- A svc32

P.S. I den här artikeln försökte jag beskriva grunderna för programmering i ARM assembler. Jag hoppas att du tyckte om det! Detta kommer att räcka för att ytterligare fördjupa sig i detta språks djungel och skriva program i det. Om allt löser sig kommer jag att skriva vidare om vad jag själv får reda på. Om det finns fel, vänligen sparka mig inte, eftersom jag är ny på assembler.

GBA ASM - Dag 2: Lite information om ARM assembler - Arkiv WASM.RU

ARM är företaget som tillverkar GBA-processorn. ARM-processorer är RISC-processorer (till skillnad från INTEL-processorer). RISC står för Reduced Instruction Set Computers (CISC - Complex...). Även om dessa processorer inte har många instruktioner (vilket är bra), har ARM-instruktioner (och kanske andra RISC-processorer, jag vet inte) många olika syften och kombinationer, vilket är det som gör RISC-processorer lika kraftfulla som de är .

Register

Jag vet inte om andra ARM-processorer, men den som används i GBA har 16 register och till skillnad från Intel-processorer (och andra) kan alla register säkert användas (vanligtvis). Registren är som följer:

r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15

Wow! Massor! Jag ska förklara i ordning.

ro: Gör vad du vill!

r2 till r12: samma

r13: På vissa ARM-system är r13 en stackpekare (SP på INTEL-processorer). Jag är inte säker på om r13 spelar samma roll i GBA, jag kan bara varna dig för att vara försiktig med det när du arbetar med stacken.

r14: Innehåller returadressen för anropade procedurer. Om du inte använder dem kan du göra vad du vill med dem.

r15: Programräknare och flaggor, samma som IP (Instruktionspekare i Intel). Det skiljer sig från Intels IP-register genom att du har fri tillgång till det precis som alla andra register, men observera att om du ändrar det kommer kontrollen att överföras till en annan del av koden och flaggorna ändras .

Låt oss räkna lite... 16 minus 3 (vanligtvis) ger oss 13 register. Är inte det coolt? Lugna ner dig.

Nu kanske du undrar vad register egentligen är. Register är speciella minnesområden som är en del av processorn och som inte har en riktig adress, utan bara är kända under sina namn. Register är 32-bitars. Nästan allt i alla monteringsspråk använder register, så du bör känna till dem lika väl som dina släktingar.

ARM assembler instruktioner

Först vill jag börja med att säga att enligt min mening är den som kom på ARM-montören ett geni.

För det andra vill jag presentera min gode vän CMP. Säg hej till honom och kanske, bara kanske, blir han din vän också. CMP står för CoMPare (jämför). Denna instruktion kan jämföra register och nummer, register och register, eller register och minnesplats. Sedan, efter jämförelsen, sätter CMP statusflaggor som berättar resultatet av jämförelsen. Som du kanske minns innehåller register r15 flaggor. De redovisar resultatet av jämförelsen. CMP-instruktionen utformades specifikt för att ställa in värdet på dessa flaggor och inget annat.

Flaggor kan innehålla följande tillstånd:

    EQ EQual / Equal

    NE Inte lika

    VS överflödesuppsättning

    VC överflöde Rensa

    HÖG HÖGRE / Högre

    LS lägre eller samma / under eller samma

    PL PLus / Plus

    MI MINus / Minus

    CS Carry Set

    CC Carry Clear

    GE Större än eller lika / Större än eller lika

    GT större än / mer

    LE Mindre än eller lika / Mindre än eller lika

    LT Mindre än / Mindre

    Z är noll/noll

    NZ är inte noll / inte noll

Dessa tillstånd spelar en mycket viktig roll i ARM assembler.

OBS: flaggar endast butiksvillkor (Lika, Mindre än och så vidare). De är inte längre viktiga.

Villkorssuffix

Du har redan sett instruktion B (Branch). Instruktion B gör vad som kallas ett ovillkorligt hopp (som GoTo i Basic eller JMP i INTEL-sammansättning). Men den kan ha ett suffix (ett av de som listas ovan), sedan kontrollerar det om flaggornas tillstånd matchar det. Om inte, så exekveras hoppinstruktionen helt enkelt inte. Så om du vill kontrollera om register r0 är lika med register r4 och sedan gå till en etikett som heter label34, måste du skriva följande kod:

    CMP r0, r4; Kommentarer i assembler kommer efter semikolon (;)

    BEQ-etikett34; B är en hoppinstruktion och EQ är ett suffix som betyder

    ; "Om lika"

OBS: I Goldroad Assembler behöver etiketter inte åtföljas av (, och det ska inte stå något på raden förutom etikettens namn.

NOTERA II: Skriv CMP och BEQ med stora bokstäver inte nödvändigt, det är bara för att göra det tydligare för dig.

Nu vet du hur du gör en övergång beroende på flaggornas tillstånd, men det du inte vet är att du kan göra vad som helst beroende på flaggornas tillstånd, lägg bara till önskat suffix till valfri instruktion!

Du behöver inte heller använda CMP för att ställa in flaggornas tillstånd. Om du till exempel vill att SUB (Subtrahera) instruktionen ska sätta flaggor, lägg till suffixet "S" till instruktionen (står för "Set flags"). Detta är användbart om du inte vill ställa in flaggornas tillstånd med en extra CMP-instruktion, så du kan göra detta och hoppa om resultatet var noll så här:

    SUBS r0,r1,0x0FF ; Ställer in flaggor enligt exekveringsresultatet

    ; instruktioner

    ldrZ r0,=0x0FFFF; Kommer att ladda r0-registret med 0x0FFFF endast om staten

    flaggor är lika med Noll.

Recension

Idag lärde vi oss (lite mer) om register. Vi lärde oss också om flexibiliteten hos ARM-instruktioner, som kan exekveras (eller inte exekveras) beroende på flaggornas tillstånd. Vi lärde oss mycket idag.

I morgon kommer vi att använda kunskapen om ARM assembler som vi förvärvat idag för att visa en bild på GBA-skärmen.

Något omöjligt är bara så tills det blir möjligt / Jean-Luc Picard, kapt. ,USS Enterprise/. Mike H, övers. Aquila

I början ÄRM ganska ovanlig assembler (om du lär dig om från x86, MCS51 eller AVR). Men den har en ganska enkel och logisk organisation, så den lär sig snabbt.

Det finns väldigt lite dokumentation på ryska för assembler. Jag kan råda dig att gå till 2 länkar (du kanske hittar fler och berättar? Jag är tacksam.):
Arkitektur och instruktionssystem för RISC-processorer i ARM-familjen - http://www.gaw.ru/html.cgi/txt/doc/micros/arm/index.htm
Förstå ARM assembler, från artikelserien "GBA ASM", författaren Mike H, övers. Aquila - http://wasm.ru/series.php?sid=21.

Den sista länken hjälpte mig mycket, rensade bort dimman =). Det andra som kan hjälpa är, konstigt nog, en C-kompilator IAR Embedded Workbench för ARM(nedan helt enkelt IAR EW ARM). Faktum är att han sedan urminnes tider har kunnat (som alla kompilatorer med självrespekt) att kompilera C-kod till assemblerkod, som i sin tur lika lätt kompileras av IAR-assemblern till objektkod. Därför finns det inget bättre än att skriva en enkel funktion i C, kompilera den till assembler, och det blir omedelbart klart vilket assembler-kommando som gör vad, hur argument skickas och hur resultatet returneras. Du slår två flugor i en smäll - du lär dig assembler och får samtidigt information om hur man integrerar assemblerkod i ett C-projekt. Jag tränade på räknefunktionen CRC16, och som ett resultat fick jag en fullständig version av den i assembler .

Här är den ursprungliga funktionen i C (u16 betyder kort utan tecken, u32 betyder osignerad int, u8 betyder tecken utan tecken):
// filen crc16.c
u16 CRC16 (void* databuf, u32-storlek)
{
u16 tmpWord, crc16, idx;
u8bitCnt;
#define CRC_POLY 0x1021;

Crc16 = 0;
idx=0;
medan (storlek!=0)
{
/* xeller den höga byten av crc16 och ingångsbyten */
tmpWord = (crc16>>8) ^ (*((((u8*)databuf)+idx));
/* skriv resultatet till den höga byten crc16 */
tmpWord<<= 8;
crc16 = tmpWord + (0x00FF & crc16);
för (bitCnt=8;bitCnt!=0;bitCnt--)
{
/* kontrollera CRC-batteriet av hög ordning */
if (crc16 & 0x8000)
{
crc16<<= 1;
crc16 ^= CRC_POLY;
}
annan
crc16<<= 1;
}
idx++;
storlek--;
}
returnera crc16;
}

Att få IAR EW ARM-monteringskod att generera är mycket enkelt. I alternativen för crc16.c-filen (läggs till i projektet) har jag markerat rutan Åsidosätt ärvda inställningar, och sedan på fliken List markeras tre kryssrutor - Output assembler-fil, Inkludera källa Och Inkludera samtalsramsinformation(även om du förmodligen inte behöver markera den sista rutan - det genererar en massa onödiga CFI-direktiv). Efter kompileringen var den resulterande filen project_folder\ewp\at91sam7x256_sram\List\crc16.s. Den här filen kan lika enkelt läggas till ett projekt som en C-fil (den kompileras normalt).

Naturligtvis, när jag matade C-kompilatorn med en oklippt version av C-koden, gav den mig en sådan sammanställningslista att jag inte förstod något om den. Men när jag tog bort alla C-operatorer från funktionen utom en blev det tydligare. Sedan lade jag till C-operatorer steg för steg, och detta är slutresultatet:

; crc16.s filen
NAMN crc16
OFFENTLIG CRC16

CRC_POLY EQU 0x1021

AVSNITT `.text`:KOD:NOROOT(2)
ÄRM

// u16 CRC16 (void* databuf, u32-storlek)
;R0 - returresultat, CRC16
;R1 - storleksparameter
;R2 - databuf-parameter (den fanns där när du skrev in R0)
;R3, R12 - tillfälliga register

CRC16:
PUSH (R3,R12); slumpmässigt fick jag reda på att R3 och R13 borde sparas
; inte nödvändigt. Men jag bestämde mig för att spara den för säkerhets skull
; happening.
MOVS R2,R0 ;nu R2==databuf
MOV R3,#+0
MOVS R0,R3 ;crc16 = 0
CRC16_LOOP:
CMP R1, #+0 ;alla byte bearbetade (storlek==0)?
BEQ CRC16_RETURN ;om ja, avsluta
LSR R3, R0, #+8;R3 = crc16>>8
LDRB R12, ;R12 = *databuf
EOR R3, R3, R12 ;R3 = *databuf ^ HÖG (crc16)
LSL R3, R3, #+8 ;R3<<= 8 (tmpWord <<= 8)
OCH R0, R0, #+255 ;crc16 &= 0x00FF
ADD R0, R0, R3 ;crc16 = tmpWord + (0x00FF & crc16)
MOV R12, #+8 ;bitCnt = 8
CRC16_BIT_LOOP:
BEQ CRC16_NEXT_BYTE ;bitCnt == 0?
TST R0,#0x8000 ;Alla bitar har inte bearbetats ännu.
BEQ CRC16_BIT15ZERO ;Kontrollera den mest signifikanta biten av crc16.
LSL R0,R0,#+1 ;crc16<<= 1
MOV R3, #+(LOW (CRC_POLY)) ;crc16 ^= CRC_POLY
ORR R3,R3,#+(HIGH(CRC_POLY)<< 8) ;
EOR RO, R3, RO;
B CRC16_NEXT_BIT

CRC16_BIT15ZERO:
LSL R0,R0,#+1 ;crc16<<= 1
CRC16_NEXT_BIT:
SUBS R12,R12,#+1 ;bitCnt--
B CRC16_BIT_LOOP ;

CRC16_NEXT_BYTE:
ADD R2,R2,#+1 ;databuf++
SUBS R1,R1,#+1 ;storlek--
B CRC16_LOOP ;slinga genom alla bytes

CRC16_RETURN:
POP (R3,R12) ;återställ register
BX LR ;avsluta subrutin, R0==crc16

IAR:s C-kompilator producerar förvånansvärt bra kod. Jag har väldigt liten framgång med att optimera det. Jag slängde bara ut det extra temporära registret som kompilatorn ville använda (av någon anledning tog det LR som ett extra temporärt register, även om R3 och R12 räckte), och tog även bort ett par extra kommandon som kontrollerade räknare och satte flaggor ( helt enkelt lägga till S-suffixet till de nödvändiga teamen).

Det här avsnittet beskriver instruktionsuppsättningarna för ARM7TDMI-processorn.

4.1 Kort beskrivning av formatet

Det här avsnittet ger en kort beskrivning av ARM- och Thumb-instruktionsuppsättningarna.

Nyckeln till instruktionsuppsättningstabellerna presenteras i Tabell 1.1.

ARM7TDMI-processorn är baserad på ARMv4T-arkitekturen. En mer fullständig beskrivning av båda instruktionsuppsättningarna finns i ARM Architecture Reference Manual.

Tabell 1.1. Nyckel till bord

ARM-instruktionsuppsättningens format visas i figur 1.5.

För mer detaljerad information om ARM-instruktionsuppsättningsformat, se ARM Architectural Reference Manual.

Figur 1.5. ARM-instruktionsuppsättningsformat

Vissa instruktionskoder är odefinierade, men de orsakar inte en sökning efter odefinierade instruktioner, till exempel en multiplicera instruktion med bit 6 satt till 1. Sådana instruktioner bör inte användas eftersom deras effekt kan komma att ändras i framtiden. Resultatet av att exekvera dessa instruktionskoder i ARM7TDMI-processorn är oförutsägbart.

4.2 Kort beskrivning av ARM-instruktioner

ARM-instruktionsuppsättningen visas i Tabell 1.2.

Tabell 1.2. Kort introduktion till ARM-instruktioner

Operationer Monteringssyntax
Frakt Frakt MOV (cond)(S) Rd,
Vidarebefordran INTE MVN (kond)(S) Rd,
Vidarebefordran av SPSR till registret MRS (cond) Rd, SPSR
Vidarebefordra CPSR till Register MRS (cond) Rd, CPSR
SPSR Registeröverföring MSR (kond) SPSR(fält), Rm
Vidarebefordran av CPSR MSR (kond) CPSR(fält), Rm
Överför konstanter till SPSR-flaggor MSR (kond) SPSR_f, #32bit_Imm
Överför konstanter till CPSR-flaggor MSR (kond) CPSR_f, #32bit_Imm
Aritmetisk Tillägg ADD (cond)(S) Rd, Rn,
Tillägg med bär ADC (kond)(S) Rd, Rn,
Subtraktion SUB (cond)(S) Rd, Rn,
Subtraktion med bär SBC (kond)(S) Rd, Rn,
Subtraktion omvänd subtraktion RSB (kond)(S) Rd, Rn,
Subtraktion omvänd subtraktion med carry RSC (kond)(S) Rd, Rn,
Multiplikation MUL (kond)(S) Rd, Rm, Rs
Multiplikation-ackumulation MLA (kond)(S) Rd, Rm, Rs, Rn
Multiplicera långa osignerade tal UMULL
Multiplikation - osignerad ackumulering av långa värden UMLAL (kond)(S) RdLo, RdHi, Rm, Rs
Multiplicera tecken långa SMULL (kond)(S) RdLo, RdHi, Rm, Rs
Multiplikation - förtecknad ackumulering av långa värden SMLAL (kond)(S) RdLo, RdHi, Rm, Rs
Jämförelse CMP (cond) Rd,
Negativ jämförelse CMN (cond) Rd,
hjärngymnastik Undersökning TST (kond) Rn,
Ekvivalenskontroll TEQ (cond) Rn,
Logga. OCH AND (cond)(S) Rd, Rn,
Exkl. ELLER EOR (kond)(S) Rd, Rn,
ORR ORR (kond)(S) Rd, Rn,
Återställ bit BIC (kond)(S) Rd, Rn, >
Övergång Övergång (kond)etikett
Följer en länk (kond)etikett
Övergång och byte av instruktionsuppsättning (forts) Rn
Läsning ord LDR (cond) Rd,
LDR(cond)T Rd,
bytes LDR (cond)B Rd,
LDR (cond)BT Rd,
signerad byte LDR(cond)SB Rd,
halva ord LDR(cond)H Rd,
halva ord med ett tecken LDR(cond)SH Rd,
operationer med flera datablock -
  • med förökning
  • LDM (cond)IB Rd(, !} {^}
  • med efterföljande ökning
  • LDM (cond)IA Rd(, !} {^}
  • med preliminär minskning
  • LDM (cond)DB Rd(, !} {^}
  • följt av minskning
  • LDM (cond)DA Rd(, !} {^}
  • stackoperation
  • LDM (kond) Rd(, !}
  • stackdrift och CPSR-återställning
  • LDM (kond) Rd(, !} ^
    stackoperation med användarregister LDM (kond) Rd(, !} ^
    Spela in ord STR (cond) Rd,
    ord med fördel i användarläge STR (cond)T Rd,
    bytes STR (cond)B Rd,
    byte med användarlägesprioritet STR (cond)BT Rd,
    halva ord STR(cond)H Rd,
    operationer på flera datablock -
  • med förökning
  • STM (cond)IB Rd(, !} {^}
  • med efterföljande ökning
  • STM (cond)IA Rd(, !} {^}
  • med preliminär minskning
  • STM (cond)DB Rd(, !} {^}
    o följt av minskning STM (cond)DA Rd(, !} {^}
  • stackoperation
  • STM(cond) Rd(, !}
  • stackoperation med användarregister
  • STM(cond) Rd(, !} ^
    Utbyta ord SWP (kond) Rd, Rm,
    byte SWP (cond)B Rd, Rm,
    Coprocessor Operation på data CDP(cond)s , , CRd, CRn, CRm,
    Överföring till ARM-register från samprocessor MRC(cond)s , , Rd, CRn, CRm,
    Överföring till samprocessor från ARM-register MCR(cond)s , , Rd, CRn, CRm,
    Läsning LDC(cond)s ,CRd,
    Spela in STC(cond)s ,CRd,
    Programavbrott SWI 24bit_Imm

    Du kan bekanta dig i detalj med kommandosystemet i ARM-läge.

    Adresseringslägen

    Adresseringslägen är procedurer som används av olika instruktioner för att generera värden som används av instruktionerna. ARM7TDMI-processorn stöder 5 adresseringslägen:

    • Läge 1 - Skiftoperander för instruktioner för databehandling.
    • Läge 2 - Läs och skriv ett ord eller osignerad byte.
    • Läge 3 - Läs och skriv halvord eller ladda teckenbyte.
    • Läge 4 - Flera läs och skriv.
    • Läge 5 - Läs- och skrivsamprocessor.

    Adresseringslägen som anger deras typer och mnemoniska koder presenteras i Tabell 1.3.

    Tabell 1.3. Adresseringslägen

    Adresseringsläge Adresseringstyp eller -läge Mnemonisk kod eller stacktyp
    Läge 2 Offset konstant
    Offsetregister
    Skalförskjutningsregister
    Förindexerad offset -
    Konstant !
    Registrera !
    Skalregister !
    !
    !
    !
    !
    -
    Konstant , #+/-12bit_Offset
    Registrera , +/-Rm
    Skalregister
    Läge 2, privilegierad Offset konstant
    Offsetregister
    Skalförskjutningsregister
    Offset följt av indexering -
    Konstant , #+/-12bit_Offset
    Registrera , +/-Rm
    Skalregister , +/-Rm, LSL #5bit_shift_imm
    , +/-Rm, LSR #5bit_shift_imm
    , +/-Rm, ASR #5bit_shift_imm
    , +/-Rm, ROR #5bit_shift_imm
    Läge 3, > Offset konstant
    !
    Efterföljande indexering , #+/-8bit_Offset
    Registrera
    Förindexering !
    Efterföljande indexering , +/-Rm
    Läge 4, läsning IA, efterföljande ökning FD, fullt fallande
    ED, tom fallande
    DA, efterföljande dekrement FA, fullt stigande
    DB pre-decrement EA, tom stigande
    Läge 4, inspelning IA, efterföljande ökning FD, fullt fallande
    IB, förökning ED, tom fallande
    DA, efterföljande dekrement FA, fullt stigande
    DB pre-decrement EA, tom stigande
    Läge 5, samprocessordataöverföring Offset konstant
    Förindexering !
    Efterföljande indexering , #+/-(8bit_Offset*4)

    Operand 2

    En operand är den del av en instruktion som hänvisar till data eller en kringutrustning. Operander 2 presenteras i tabell 1.4.

    Tabell 1.4. Operand 2

    Fälten presenteras i tabell 1.5.

    Tabell 1.5. Fält

    Tillståndsfält

    Tillståndsfälten presenteras i Tabell 1.6.

    Tabell 1.6. Tillståndsfält

    Fälttyp Ändelse Beskrivning Skick
    Skick (skick) EQ Lika Z=1
    NE Inte jämnlikt Z=0
    C.S. Osignerad större än eller lika med C=1
    CC Osignerad mindre C=0
    MI Negativ N=1
    P.L. Positivt eller noll N=0
    MOT Svämma över V=1
    V.C. Inget överflöde V=0
    HEJ Osignerad mer C=1, Z=0
    L.S. Osignerad mindre än eller lika med C=0, Z=1
    G.E. Mer eller lika N=V (N=V=1 eller N=V=0)
    LT Mindre NV (N=1 och V=0) eller (N=0 och V=1)
    GT Mer Z=0, N=V (N=V=1 eller N=V=0)
    L.E. Mindre eller lika Z=0 eller NV (N=1 och V=0) eller (N=0 och V=1)
    AL Alltid sant flaggor ignoreras

    4.3 Kort beskrivning av tuminstruktionssatsen

    Format för tuminstruktionsuppsättningar visas i figur 1.6. För mer information om ARM-instruktionsuppsättningsformat, se ARM Architectural Reference Manual.


    Figur 1.6. Tummen instruktionsuppsättning format

    Thumb-instruktionsuppsättningen presenteras i Tabell 1.7.

    Tabell 1.7. Kort beskrivning av Thumb-instruktionssetet

    Drift Monteringssyntax
    Vidarebefordran (kopiering) konstanter MOV Rd, #8bit_Imm
    senior till junior MOV Rd, Hs
    junior till senior MOV HD, Rs
    senior till senior MOV Hd, Hs
    Aritmetisk tillägg ADD Rd, Rs, #3bit_Imm
    lägga till moll till moll ADD Rd, Rs, Rn
    lägg till äldst till yngst ADD Rd, Hs
    lägg till junior till senior ADD HD, Rs
    lägga äldst till äldst ADD Hd, Hs
    tillägg med en konstant ADD Rd, #8bit_Imm
    tillför värde till SP ADD SP, #7bit_Imm ADD SP, #-7bit_Imm
    tillägg med bär ADC Rd, Rs
    subtraktion SUB Rd, Rs, Rn SUB Rd, Rs, #3bit_Imm
    subtraktion av en konstant SUB Rd, #8bit_Imm
    subtraktion med bär SBC Rd, Rs.
    teckeninversion NEG Rd, Rs
    multiplikation MUL Rd, Rs.
    jämför yngre med yngre CMP Rd, Rs.
    jämför junior och senior CMP Rd,Hs
    jämför äldre och yngre CMP Hd, Rs
    jämför äldre och äldre CMP Hd, Hs
    jämför negativt CMN Rd, Rs.
    jämför med konstant CMP Rd, #8bit_Imm
    hjärngymnastik OCH OCH Rd, Rs
    Exkl. ELLER EOR Rd, Rs
    ELLER ORR Rd, Rs
    Återställ bit BIC Rd, Rs.
    Vidarebefordran INTE MVN Rd, Rs.
    Bittestning TST Rd, Rs
    Skift/rotation Logisk förskjutning vänster LSL Rd, Rs, #5bit_shift_imm LSL Rd, Rs
    Logisk förskjutning åt höger LSR Rd, Rs, #5bit_shift_imm LSR Rd, Rs
    Aritmetiskt skift till höger ASR Rd, Rs, #5bit_shift_imm ASR Rd, Rs
    Vrid höger ROR Rd, Rs
    Övergång villkorliga hopp -
    BEQ-etikett
    BNE-etikett
    BCS-etikett
    BCC-etikett
    BMI-märkning
    BPL-etikett
    BVS-etikett
    BVC-märkning
  • C=1, Z=0
  • BHI-etikett
  • C=0, Z=1
  • BLS-etikett
  • N=1, V=1 eller N=0, V=0
  • BGE-etikett
  • N=1, V=0 eller N=0, V=1
  • BLT-etikett
  • Z=0 och ((N eller V=1) eller (N eller V=0))
  • BGT-etikett
  • Z=1 eller ((N=1 eller V=0) eller (N=0 och V=1))
  • BLE-etikett
    Ovillkorligt hopp B-etikett
    Lång länkklick BL-etikett
    Valfri tillståndsändring -
  • på adressen i ml. Registrera
  • BX Rs
  • på adressen i st. Registrera
  • BX Hs
    Läsning med offsetkonstant -
  • ord
  • LDR Rd,
  • halva ord
  • LDRH Rd,
  • bytes
  • LDRB Rd,
    med offsetregister -
  • ord
  • LDR Rd,
  • halva ord
  • LDRH Rd,
  • underteckna halvord
  • LDRSH Rd,
    LDRB Rd,
  • signerad byte
  • LDRSB Rd,
    i förhållande till PC-programräknaren LDR Rd,
    relativt stackpekaren SP LDR Rd,
    Adress -
  • via PC
  • ADD Rd, PC, #10bit_Offset
  • använder SP
  • ADD Rd, SP, #10bit_Offset
    Flera läsningar LDMIA Rb!,
    Spela in med offsetkonstant -
  • ord
  • STR Rd,
  • halva ord
  • STRH Rd,
  • bytes
  • STRB Rd,
    med offsetregister -
  • ord
  • STR Rd,
  • halva ord
  • STRH Rd,
  • bytes
  • STRB Rd,
    i förhållande till SP STR Rd,
    Flera ingångar STMIA Rb!,
    Pushing/popping från stack Skjut register på stapeln SKJUTA PÅ
    Tryck på LR och register på stapeln SKJUTA PÅ
    Popregister från stack POP
    Popregister och PC från stack POP
    Programavbrott - SWI 8bit_Imm

    För närvarande används högnivåspråk för att programmera även ganska enkla mikrokontroller, vanligtvis undergrupper av C- eller C++-språket.

    Men när man studerar arkitekturen för processorer och dess funktioner är det lämpligt att använda Assembly-språk, eftersom endast detta tillvägagångssätt kan säkerställa identifieringen av funktionerna i arkitekturen som studeras. Av denna anledning genomförs ytterligare presentation med Assembly-språk.

    Innan vi börjar överväga ARM7-kommandon är det nödvändigt att notera följande funktioner:

      Stöd för två instruktionsuppsättningar: ARM med 32-bitars instruktioner och THUMB med 16-bitars instruktioner. Därefter överväger vi 32-bitars instruktionsuppsättningen, ordet ARM kommer att betyda instruktioner som tillhör detta format, och ordet ARM7 kommer att betyda själva CPU:n.

      Stöd för två 32-bitars adressformat: big-endian-processor och little-endian-processor. I det första fallet är den mest signifikanta biten (Most Significant Bit - MSB) placerad i den minst signifikanta biten av ordet, och i det andra fallet - i den mest signifikanta biten. Detta säkerställer kompatibilitet med andra familjer av 32-bitarsprocessorer vid användning av högnivåspråk. I ett antal familjer av processorer med ARM-kärnan används dock endast little-endian-byte (dvs. MSB är den viktigaste biten av adressen), vilket gör arbetet med processorn mycket lättare. Eftersom kompilatorn som används för ARM7 fungerar med kod i båda formaten måste du se till att ordformatet är korrekt inställt, annars kommer den resulterande koden att vändas ut och in.

      Möjligheten att utföra olika typer av skift av en av operanderna "på pass" innan den används i ALU

      Stöd för villkorlig exekvering av alla kommandon

      Möjlighet att förbjuda ändring av operationsresultatflaggor.

        1. Villkorlig utförande av kommandon

    En av de viktiga egenskaperna hos ARM-instruktionsuppsättningen är att den stöder villkorad exekvering av alla instruktioner. I traditionella mikrokontroller är de enda villkorliga kommandona villkorliga hoppkommandon, och kanske ett antal andra, såsom kommandon för att testa eller ändra tillståndet för enskilda bitar. I ARM-instruktionsuppsättningen jämförs de mest signifikanta 4 bitarna av instruktionskoden alltid med villkorsflaggorna i CPSR-registret. Om deras värden inte stämmer överens, ersätts kommandot i dekrypteringsstadiet med ett NOP-kommando (ingen operation).

    Detta minskar avsevärt exekveringstiden för programsektioner med "korta" övergångar. Så, till exempel, när du löser andragradsekvationer med reella koefficienter och godtyckliga rötter med en negativ diskriminant, innan du beräknar kvadratroten, är det nödvändigt att ändra tecknet för diskriminanten och tilldela resultatet till den imaginära delen av svaret.

    Den traditionella lösningen på detta problem är att ange ett villkorligt hoppkommando. Att utföra detta kommando tar minst 2 klockcykler - dekryptering och laddning av det nya adressvärdet i programräknaren och ytterligare ett antal klockcykler för att ladda kommandopipeline. När man använder villkorlig kommandoexekvering med en positiv diskriminant ersätts teckenändringskommandot med en tom operation. I det här fallet rensas inte kommandopipelinen och förlusten är inte mer än en cykel. Tröskeln vid vilken ersättning av villkorliga kommandon med ett NOP-kommando är effektivare än att utföra traditionella villkorliga hoppkommandon och den associerade återfyllningen av pipelinen är lika med dess djup, dvs. tre.

    För att implementera den här funktionen måste du lägga till något av de sexton prefixen som definierar de testade tillstånden för tillståndsflaggorna till de grundläggande mnemoniska beteckningarna för assemblerkommandon (och även C). Dessa prefix anges i tabellen. 3. Följaktligen finns det 16 alternativ för varje kommando. Till exempel följande kommando:

    MOVEQ R1, #0x008

    betyder att numret 0x00800000 kommer att laddas in i R1-registret endast om resultatet av det senaste databearbetningskommandot var "lika" eller ett 0-resultat erhölls och flaggan (Z) för CPSR-registret är inställd i enlighet därmed.

    Tabell 3

    Kommandoprefix

    Menande

    Z installerad

    Z-återställning

    Med installerad

    Större än eller lika med (osignerad)

    C återställ

    Nedan (osignerad)

    N installerad

    Negativt resultat

    N återställ

    Positivt resultat eller 0

    V installerat

    Svämma över

    V-återställning

    Inget överflöde

    Med installerat,

    Z-återställning

    Ovan (osignerad)

    Med återställning,

    Z installerad

    Mindre än eller lika med (osignerad)

    Större än eller lika med (signerad)

    N är inte lika med V

    Mindre (tecken)

    Z återställ OCH

    (N är lika med V)

    Mer (ikoniskt)

    Z set ELLER

    (N är inte lika med V)

    Mindre än eller lika med (signerad)

    (ignoreras)

    Ovillkorlig avrättning

    
    Topp