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
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
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.
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 | - | |
LDM (cond)IB Rd(, !} |
||
LDM (cond)IA Rd(, !} |
||
LDM (cond)DB Rd(, !} |
||
LDM (cond)DA Rd(, !} |
||
LDM (kond) |
||
LDM (kond) |
||
stackoperation med användarregister | LDM (kond) |
|
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 | - | |
STM (cond)IB Rd(, !} |
||
STM (cond)IA Rd(, !} |
||
STM (cond)DB Rd(, !} |
||
o följt av minskning | STM (cond)DA Rd(, !} |
|
STM(cond) |
||
STM(cond) |
||
Utbyta | ord | SWP (kond) Rd, Rm, |
byte | SWP (cond)B Rd, Rm, | |
Coprocessor | Operation på data | CDP(cond)s |
Överföring till ARM-register från samprocessor | MRC(cond)s |
|
Överföring till samprocessor från ARM-register | MCR(cond)s |
|
Läsning | LDC(cond)s |
|
Spela in | STC(cond)s |
|
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 | ||
BHI-etikett | ||
BLS-etikett | ||
BGE-etikett | ||
BLT-etikett | ||
BGT-etikett | ||
BLE-etikett | ||
Ovillkorligt hopp | B-etikett | |
Lång länkklick | BL-etikett | |
Valfri tillståndsändring | - | |
BX Rs | ||
BX Hs | ||
Läsning | med offsetkonstant | - |
LDR Rd, | ||
LDRH Rd, | ||
LDRB Rd, | ||
med offsetregister | - | |
LDR Rd, | ||
LDRH Rd, | ||
LDRSH Rd, | ||
LDRB Rd, | ||
LDRSB Rd, | ||
i förhållande till PC-programräknaren | LDR Rd, | |
relativt stackpekaren SP | LDR Rd, | |
Adress | - | |
ADD Rd, PC, #10bit_Offset | ||
ADD Rd, SP, #10bit_Offset | ||
Flera läsningar | LDMIA Rb!, |
|
Spela in | med offsetkonstant | - |
STR Rd, | ||
STRH Rd, | ||
STRB Rd, | ||
med offsetregister | - | |
STR Rd, | ||
STRH Rd, | ||
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.
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 |