Hlavní navigace

Instrukční sada AArch64

13. 6. 2017
Doba čtení: 23 minut

Sdílet

Minule jsme si řekli základní informace o stále relativně nové architektuře AArch64. Dnes se budeme věnovat instrukční sadě. Popíšeme si i některé rozdíly mezi instrukcemi AArch64 a původní instrukční sadou ARM 32 (A32).

Obsah

1. Instrukční sada AArch64

2. Operační kódy instrukcí

3. Instrukce typu Load-Store

4. Load-Store pro dvojici registrů

5. Nepodmíněné skoky a skoky do subrutiny (branch and link)

6. Podmíněné skoky

7. Základní aritmetické instrukce

8. Násobení a dělení

9. Logické instrukce

10. Znaménkové rozšíření operandu či rozšíření o nuly

11. Aritmetické a bitové posuny, bitová rotace

12. Podmíněné zpracování dat

13. Podmíněný výběr operandu

14. Další instrukce s podmínkou

15. Extrakce dat

16. Odkazy na Internetu

1. Instrukční sada AArch64

Na předchozí článek s popisem 64bitových mikroprocesorů s architekturou AArch64 dnes navážeme, protože se budeme věnovat podrobnějšímu popisu instrukční sady. Zaměříme se spíše na zajímavější a z pohledu jiných ISA i neobvyklé instrukce a nezapomeneme ani zdůraznit význam „nulového“ registru WZR/XZR, díky jehož existenci vzniklo velké množství užitečných instrukční aliasů. Zopakujme si však nejprve seznam typů instrukcí, který je pro účely dnešního článku nepatrně rozšířen:

Skupina Další dělení
Load-Store Load-Store pro jeden registr
  Load-Store pro dvojici registrů
  Prefetch
   
Skoky Nepodmíněné skoky
  Skoky do subrutiny
  Nepodmíněný skok na adresu v registru
  Podmíněné skoky
   
ALU operace Základní aritmetické instrukce
  Násobení a dělení
  Logické instrukce
  Znaménkové rozšíření operandu či rozšíření o nuly
  Bitové operace
  Bitové posuny
  Aritmetické posuny
  Podmíněné zpracování dat
  Podmíněný výběr operandu
  Další instrukce s podmínkou
  Extrakce dat
   
FP operace Přenos operandů mezi registry
  Konverze mezi různými formáty
  Převod na celá čísla (zaokrouhlení)
  Základní aritmetické operace
  Výpočet minima a maxima
  MAC (Multiply Accumulate)
  Porovnání operandů
  Podmíněný výběr operandu
   
SIMD operace Aritmetické operace se skaláry
  Aritmetické operace s vektory
  Permutace vektorů
  Konverze dat
  Instrukce z crypto extension (patří do SIMD)
   
Systémové instrukce Zpracování výjimek
  Přístup k systémovým registrům
  Implementace bariér
  Instrukce pro jádro systému

2. Operační kódy instrukcí

Všechny instrukce mají pevnou šířku třiceti dvou bitů. Těchto 32 bitů je rozděleno do jednotlivých bitových polí, v jejichž uspořádání je možné nalézt určitou pravidelnost. Mnoho instrukcí používá takzvaný tříadresový kód, v němž se pěti bity určuje první zdrojový registr, dalšími pěti bity druhý zdrojový registr a další pětice bitů určuje index cílového registru. Zajímavé je, že u některých instrukcí nejsou všechny bity instrukčního slova využity (alespoň prozatím), naproti tomu například u skokové instrukce B je většina bitů použita pro uložení adresy:

000x 01ii iiii iiii iiii iiii iiii iiii

Pro příklad se podívejme na způsob zakódování těchto dvou instrukcí:

add     x1, x1, #0x1
sub     x2, x2, #0x1

První z těchto instrukcí má kód:

0x91000421

Druhá z těchto instrukcí má kód:

0xd1000442

Při převodu do binární soustavy získáme kódy:

1001 0001 0000 0000 0000 0100 0010 0001
1101 0001 0000 0000 0000 0100 0100 0010

Zapišme si tyto kódy společně s maskami obou instrukcí:

x00x 0001 SSii iiii iiii iinn nnnd dddd
1001 0001 0000 0000 0000 0100 0010 0001
 
x10x 0001 SSii iiii iiii iinn nnnd dddd
1101 0001 0000 0000 0000 0100 0100 0010

„Luštění“ je relativně snadné:

x00x 0001 SSii iiii iiii iinn nnnd dddd
 
1001 0001 0000 0000 0000 0100 0010 0001
                                 ^ ^^^^
                                 dest=x1
                                 (5 bitů)
 
1001 0001 0000 0000 0000 0100 0010 0001
                           ^^ ^^^
                           src=x1
                          (5 bitů)
 
1001 0001 0000 0000 0000 0100 0010 0001
            ^^ ^^^^ ^^^^ ^^
            immediate=0x01
              (12 bitů)
 
1001 0001 0000 0000 0000 0100 0010 0001
          ^^
          shift=0x00 (konstanty)
          (4 bity)
 
1001 0001 0000 0000 0000 0100 0010 0001
 ^^  ^^^^
kód instrukce

Podobné tomu bude i u instrukce SUB, kde se ovšem pracuje s registrem X2 a horní čtyři bity budou taktéž odlišné.

3. Instrukce typu Load-Store

Jak je u RISCové architektury obvyklé, nalezneme v instrukční sadě i několik instrukcí určených pro načítání dat z paměti do registrů a naopak pro ukládání obsahu registrů do paměti. Navíc některé instrukce umožňují práci nejenom s 32bitovými a 64bitovými slovy, ale i s menšími bloky dat – s bajty a šestnáctibitovými „půlslovy“:

# Instrukce Stručný popis
1 LDR načtení 32bitového či 64bitového registru z paměti
2 LDRB načtení bajtu a s rozšířením na slovo (doplňují se nuly)
3 LDRSB načtení bajtu se znaménkovým rozšířením
4 LDRH načtení šestnáctibitového „půlslova“ s rozšířením o nuly
5 LDRSH načtení šestnáctibitového „půlslova“ se znaménkovým rozšířením
6 LDRSW načtení 32bitového slova se znaménkovým rozšířením do 64bitového registru
     
7 STR uložení 32bitového či 64bitového registru do paměti
8 STRB uložení bajtu z vybraného 32bitového registru
9 STRH uložení šestnáctibitového „půlslova“ z vybraného 32bitového registru

Poznámka: zdánlivě chybějící instrukce LDRW a STRW jsou již obsaženy v základních instrukcích LDR a STR, pokud použijeme 32bitový registr (u LDR se horních 32 bitů vynuluje).

Mezi podporované adresovací režimy patří i použití offsetu vůči vybranému registru či SP.

4. Load-Store pro dvojici registrů

Již v předchozím článku jsme si řekli, že u čipů s instrukční sadou AArch64 nenalezneme instrukce LDM (Load Multiple) a STM (Store Multiple), které dokážou načíst nebo uložit libovolnou skupinu až šestnácti registrů specifikovaných bitovým polem (ovšem v určeném pořadí). Naproti tomu však máme k dispozici instrukce pro načtení páru registrů, přičemž se může jednat o libovolné registry (nemusí být uloženy za sebou atd.). Zajímavé je, že u těchto instrukcí existují dvě varianty, které dávají CPU informaci o tom, zda se jedná o dočasné (temporary) úložiště (zásobníkový rámec atd.) či spíše o trvalejší uložení dat. Tuto informaci je možné použít pro řízení přístupu ke cache atd.:

# Instrukce Stručný popis
1 LDP načtení registrového páru
2 LDPSW načtení dvou 32bitových slov, jejich znaménkové rozšíření a uložení do dvojice registrů
3 STP uložení registrového páru
     
4 LDNP jako LDP, ale paměťová oblast není považována za dočasnou (temporal)
5 STNP jako STP, ale paměťová oblast není považována za dočasnou (temporal)

5. Nepodmíněné skoky a skoky do subrutiny (branch with link)

U instrukční sady AArch64 je zajímavé (a současně i velmi užitečné), že základní skoková instrukce B neprovádí skok na zadanou absolutní adresu, ale na adresu relativní vůči aktuální hodnotě PC. Rozsah skoku je v takovém případě ±128 MB; větší konstantu není možné v dané konfiguraci instrukčního slova uložit. Dále pak instrukční soubor obsahuje instrukci pro skok do podprogramu s uložením návratové adresy do registru X30 (nikoli na zásobník, používáme RISCový čip) a skok na absolutní adresu uloženou ve vybraném registru. Tato instrukce existuje ve dvou variantách, které se od sebe odlišují pouze hintem pro CPU, zda se právě realizuje návrat z podprogramu (subrutiny) či obyčejný skok:

# Instrukce Stručný popis
1 B skok na adresu vypočtenou z offsetu vůči PC v rozsahu ±128 MB
2 BL branch and link, stejné jako předchozí instrukce, ovšem původní hodnota PC se uloží do X30
3 BR skok na adresu uloženou v registru s hintem, že se nejedná o výskok z podprogramu
4 RET jako BR, ovšem s hintem, že se jedná o výskok z podprogramu
5 BRL kombinace BR + BL, tj. skok na adresu uloženou v registru + původní PC do X30

6. Podmíněné skoky

Jak jsme se již dozvěděli v předchozí části tohoto seriálu, je instrukční sada AArch64 hned v několika ohledech odlišná od původní 32bitové RISCové instrukční sady ARM32 (či zkráceně pouze A32). Zásadní a na první pohled viditelná odlišnost spočívá v tom, že se zredukoval počet těch strojových instrukcí, u nichž je možné použít podmínkové bity. Jen ve stručnosti si připomeňme, že v instrukční sadě ARM32 jsou v každém instrukčním slovu (každé má bez výjimky konstantní šířku třiceti dvou bitů) rezervovány čtyři nejvyšší bity, v nichž je zapsán kód podmínky, při jejímž splnění se instrukce provede. Díky této vlastnosti bylo možné v mnoha algoritmech zredukovat počet podmíněných skoků, což je v případě (dnes už nejenom) RISCových procesorů poměrně důležité.

Obrázek 1: Formáty instrukčních slov u původní 32bitové architektury ARM. Povšimněte si, že v každém instrukčním slovu jsou nejvyšší čtyři bity vyhrazeny pro uložení kódu podmínky.

Všechny podmínky jsou vyhodnoceny na základě hodnoty jednoho či (častěji) kombinací většího množství příznaků (flags). První sada podmínkových kódů se používá pro provedení či naopak neprovedení instrukce na základě hodnoty jednoho z příznakových bitů Z (zero), V (overflow) či N (negative). Poslední podmínkový kód z této skupiny má název AL (Any/Always) a značí, že se instrukce provede v každém případě. Tento podmínkový kód se tudíž většinou v assembleru ani nezapisuje, protože je považován za implicitní:

Kód Přípona Význam Testovaná podmínka
0000 EQ Z == 1 rovnost při porovnání či nulový výsledek poslední ALU operace
0001 NE Z == 0 nerovnost při porovnání či nenulový výsledek poslední ALU operace
0100 MI N == 1 výsledek je záporný
0101 PL N == 0 výsledek je kladný či 0
0110 VS V == 1 nastalo přetečení
0111 VC V == 0 nenastalo přetečení
1110 AL Any/Always většinou se nezapisuje, implicitní podmínka

Další čtyři podmínkové kódy se většinou používají při porovnávání dvou celých hodnot bez znaménka (unsigned integer). V těchto případech se testují stavy příznakových bitů C (carry) a Z (zero), přesněji řečeno kombinace těchto bitů:

Kód Přípona Význam Testovaná podmínka
0010 CS/HS C == 1
0011 CC/LO C == 0 <
1000 HI C == 1 & Z == 0 >
1001 LS C == 0 | Z == 1

Poslední čtyři podmínkové kódy se používají pro porovnávání hodnot se znaménkem (signed). V těchto případech se namísto příznakových bitů © carry a (Z) zero testují kombinace bitů (N) negative, (V) overflow a (Z) zero:

Kód Přípona Význam Testovaná podmínka
1010 GE N == V
1011 LT N ≠ V <
1100 GT Z = 0, N = V >
1101 LE Z = 1, N ≠ V

Procesory s architekturou AArch64 sice používají shodné podmínkové bity, ty jsou ovšem použity jen v několika pečlivě vybraných instrukcích. Příznak přetečení je, podobně jako u mnoha dalších typů procesorů, používán při aritmetických operacích (ovšem ne implicitně – jen u instrukcí končících na S – set) a testy podmínkových bitů lze provádět především u podmíněných skoků, tj. u instrukcí, jejichž mnemotechnická zkratka začíná znakem B od slova „Branch“. Rozeznáváme následující typy nepodmíněných podmíněných skoků:

# Instrukce Alternativní zápis
1 B BAL
2 B.EQ BEQ
3 B.NE BNE
4 B.MI BMI
5 B.PL BPL
6 B.VS BVS
7 B.VC BVC
8 B.CS BCS
9 B.CC BCC
10 B.HI BHI
11 B.LS BLS
12 B.GE BGE
13 B.LT BLT
14 B.GT BGT
15 B.LE BLE

Poznámka: alternativní zápis je podporován například GNU Assemblerem, většinou však můžete používat obě varianty zápisu.

Další dva typy skoků jsou odvozeny od instrukcí, které známe z instrukční sady Thumb. Dochází zde k porovnání vybraného pracovního registru s nulou:

# Instrukce Stručný popis
1 CBZ Compare and Branch if Zero
2 CBNZ Compare and Branch if Not Zero

Existují ještě další dvě instrukce pro podmíněné skoky, které se jmenují TBZ (Test and Branch if Zero) a TBNZ (Test and Branch if Not Zero). Ty provádí test hodnoty vybraného bitu registru na nulu:

# Instrukce Stručný popis
1 TBZ Test and Branch if Zero
2 TBNZ Test and Branch if Not Zero

Způsob zápisu těchto instrukcí je následující:

TBZ  Xn, #konstanta, návěští
TBZ  Wn, #konstanta, návěští
TBNZ Xn, #konstanta, návěští
TBNZ Wn, #konstanta, návěští

Konstanta má šířku pouze šest bitů, protože je v ní uložen index bitu pracovního registru, který se testuje na nulu či jedničku (u registrů Wn by stačilo jen pět bitů). V případě instrukce TBZ – pokud je n-tý bit registru Xn/Wn nastavený na nulu, provede se skok, v opačném případě se řízení přenese na další instrukci. V případě instrukce TBNZ je bit testován na jedničku. Vzhledem k tomu, že v instrukčním slovu je nutné kromě adresy cíle (návěští) specifikovat i číslo pracovního registru a index bitu, je tento typ skoku omezen na rozsah ±32kB, což by ovšem v praxi mělo být více než dostačující (v opačném případě lze TBZ/TBNZ zkombinovat s absolutním skokem B).

7. Základní aritmetické instrukce

Mezi základní aritmetické instrukce samozřejmě patří součet a rozdíl. Existují vždy čtyři varianty každé z těchto operací, které se od sebe liší podle toho, zda se při výpočtu nastavují příznaky (všechny čtyři) a zda se po součtu či rozdílu ještě k výsledku přičte předchozí hodnota příznaku carry:

# Instrukce Stručný popis
1 ADD 32bitový či 64bitový součet
2 ADC 32bitový či 64bitový součet s carry
3 ADDS jako ADD, ovšem navíc nastaví příznakové bity
4 ADCS jako ADC, ovšem navíc nastaví příznakové bity
     
5 SUB 32bitový či 64bitový rozdíl
6 SBC rozdíl s přičtením carry a odečtením jedničky
7 SUBS jako SUB, ovšem navíc nastaví příznakové bity
8 SBCS jako SBC, ovšem navíc nastaví příznakové bity

Kromě toho existuje hned několik instrukčních aliasů, které je možné používat v assemblerech a které jsou rozpoznány i v disassemblerech a debuggerech. Tyto aliasy využívají registr WZR (32 bitů) či XZR (64 bitů). Připomeňme si, že tento registr je při čtení vždy nulový, což je v tomto případě výhodné, protože vlastně zadarmo získáme velké množství užitečných instrukcí:

# Instrukce Stručný popis
1 NEG alias pro SUB op1, xZR, op2 (op1 = 0 – op2)
2 NEGS alias pro SUBS op1, xZR, op2 (op1 = 0 – op2 + nastavení příznaků)
3 NGC alias pro SBC op1, xZR, op2 (op1 = 0 – op2 + carry – 1)
4 NGCS kombinace předchozích dvou instrukcí
     
5 CMP alias pro SUBS xZR, op1, op2 (tj.výsledek se zahodí, protože do registrů WZR/XZR se nezapisuje)
6 CMN alias pro ADDS xZR, op1, op2 (dtto jako předchozí instrukce)
     
7 MOV alias pro ADD reg1, reg2, #0 (platí je při přesunu dat mezi registry)

Poznámka: v praxi se setkáte především s aliasy CMP, CMN a hlavně pak MOV (resp. přesněji řečeno je toto jedna z mnoha variant pseudoinstrukce MOV).

8. Násobení a dělení

U čipů AArch64 nalezneme násobičku a děličku, která dokáže vynásobit jak 32bitové, tak i 64bitové operandy. Mezi podporovanými instrukcemi najdeme i obdobu DSP instrukcí Multiply-Accumulate, ovšem s tím rozdílem, že se namísto akumulátoru může použít odlišný vstupní a odlišný výstupní registr, což konkrétně znamená, že DSP operace:

acc += op2 × op3

dokáže AArch64 provést:

op1 = op2 × op3 + op4

Podívejme se nyní, které instrukce provádí násobička a dělička:

# Instrukce Stručný popis
1 MUL 32bitové či 64bitové násobení
2 MADD výsledek = op2 × op3 + op4
3 MSUB výsledek = op4 – op2 × op3
4 MNEG výsledek = – op2 × op3
     
5 SMULL násobení hodnot se znaménkem (32×32 → 64)
6 SMADDL MADD hodnot se znaménkem pro (32×32 → 64)
7 SMSUBL MSUB hodnot se znaménkem pro (32×32 → 64)
8 SMNEGL MNEG hodnot se znaménkem pro (32×32 → 64)
9 SMULH násobení 64×64, z výsledku se vezme jen horních 64 bitů ze 128
     
10 UMULL násobení hodnot bez znaménka (32×32 → 64)
11 UMADDL MADD hodnot bez znaménka pro (32×32 → 64)
12 UMSUBL MSUB hodnot bez znaménka pro (32×32 → 64)
13 UMNEGL MNEG hodnot bez znaménka pro (32×32 → 64)
14 UMULH násobení 64×64, z výsledku se vezme jen horních 64 bitů ze 128
     
15 SDIV 32bitové či 64bitové dělení hodnot se znaménkem
16 UDIV 32bitové či 64bitové dělení hodnot bez znaménka

Poznámka: ve skutečnosti je instrukce MUL, tedy „běžné násobení“ aliasem pro instrukci MADD, v níž je třetím vstupním operandem registr WZR či XZR, tedy „konstantní nula“. Totéž platí pro instrukci MNEG, která vznikla z instrukce MSUB, u níž je opět posledním vstupním operandem nulový registr.

9. Logické instrukce

Nesmíme samozřejmě zapomenout ani na instrukce pro provedení logických operací. Nalezneme zde klasickou trojici instrukcí pro logický součin bit po bitu, logický součet bit po bitu i logickou nonekvivalenci a navíc i instrukce, v nichž je druhý vstupní operand negován. Navíc se u všech instrukcí možné druhý operand i posunout o konstantu uloženou v instrukčním slovu:

# Instrukce Stručný popis
1 AND logický součin bit po bitu
2 ANDS logický součin bit po bitu + nastavení příznaků N a Z, vynulování C a V
3 ORR logický součet bit po bitu
4 EOR logická nonekvivalence bit po bitu
     
5 ORN logický součet bit po bitu, druhý vstupní operand je však negován
6 EON logická nonekvivalence bit po bitu, druhý vstupní operand je však negován

Povšimněte si, že pouze instrukce ANDS nastavuje příznaky.

Podobně jako u aritmetických operací, i u operací logických lze využít registru WZR a XZR pro vytvoření instrukčních aliasů, například druhého aliasu MOV (první byl implementován přes ADD), instrukce MOVI (načtení malé konstanty) a zejména pak užitečné pseudoinstrukce TST známé i z dalších architektur:

# Instrukce Stručný popis
1 MOVI alias pro ORR reg, xZR, konstanta (tj. provede se 0 or konstanta)
2 MOV alias pro ORR reg, xZR, reg (tj. provede se 0 or registr)
3 TST alias pro ANDS xZR, .., .. (výsledek AND se nikam neuloží, pouze se nastaví příznaky)

10. Znaménkové rozšíření operandu či rozšíření o nuly

Některé instrukce slouží k manipulaci se šestnáctibitovými konstantami, které se musí nějakým způsobem rozšířit na konstanty 32bitové a 64bitové. Jedná se o následující trojici instrukcí, které vždy obsahují jak již zmíněnou šestnáctibitovou konstantu, tak i druhou konstantu reprezentující posun doleva:

# Instrukce Stručný popis
1 MOVZ 16bitová konstanta může být posunuta doleva a uložena do registru
2 MOVN jako předchozí instrukce, ale pracuje se s negací konstanty (po posunutí)
3 MOVK načtení 16bitové konstanty, její posun a umístění do registru (bez ovlivnění dalších bitů)

Poznámka: při práci v assembleru většinou stačí použít pseudoinstrukci MOV, kterou assembler sám dokáže rozložit na ty instrukce, které CPU skutečně dokáže zpracovat.

Další šestice instrukcí dokáže provést znaménkové či naopak bezznaménkové rozšíření bajtu, šestnáctibitového slova (u AArch64 se používá termín halfword) či 32bitového slova (word) na 64bitovou hodnotu. Bezznaménkové rozšíření pouze vynuluje horní bity registru:

# Instrukce Stručný popis
1 SXTB alias pro SBFM, znaménkové rozšíření bajtu (B=byte)
2 SXTH alias pro SBFH, znaménkové rozšíření 16bitového slova (H=halfword)
3 SXTW alias pro SBFH, znaménkové rozšíření 32bitového slova (W=word)
     
4 UXTB alias pro UBFM, bezznaménkové rozšíření bajtu (B=byte)
5 UXTH alias pro UBFH, bezznaménkové rozšíření 16bitového slova (H=halfword)
6 UXTW alias pro UBFH, bezznaménkové rozšíření 32bitového slova (W=word)

11. Aritmetické a bitové posuny, bitová rotace

Množina instrukcí navržených pro provedení operací aritmetického či bitového (logického) posunu je celkem přehledná. Povšimněte si navíc poslední instrukce ROR určené pro bitovou rotaci. Neexistuje zde rotace vlevo, protože ta samozřejmě odpovídá rotaci vpravo, ovšem o odlišnou hodnotu (odečtenou od 63 či 31):

# Instrukce Stručný popis
1 ASR aritmetický posun doprava až o 31/63 bitů
2 LSL logický posun doleva až o 31/63 bitů
3 LSR logický posun doprava až o 31/63 bitů
4 ROR rotace doprava až o 31/63 bitů

U všech předchozích instrukcí byl posun specifikován konstantou, zatímco u dalších čtyř instrukcí je posun uložen v registru (druhý vstupní operand). Hodnota tohoto registru však není použita přímo, protože se v úvahu bere jen posledních pět či šest bitů podle toho, zda se jedná o 32bitovou či 64bitovou operaci:

# Instrukce Stručný popis
1 ASRV aritmetický posun doprava až o 31/63 bitů
2 LSLV logický posun doleva až o 31/63 bitů
3 LSRV logický posun doprava až o 31/63 bitů
4 RORV rotace doprava až o 31/63 bitů

Poznámka: instrukce ROR je ve skutečnosti aliasem instrukce EXTR popsané v patnácté kapitole.

12. Podmíněné zpracování dat

V této kapitole se seznámíme s následujícími instrukcemi:

# Instrukce Stručný popis
1 CSET Conditional Set
2 CSETM Conditional Set Mask

První zcela novou instrukcí uvedenou až na architektuře AArch64, je instrukce nazvaná CSET neboli Conditional Set. Tato instrukce vlastně přímo odpovídá požadavkům kladeným na datový typ boolean v mnoha programovacích jazycích, v nichž je hodnota true interně reprezentována jedničkou a hodnota false nulou. Tato instrukce existuje ve dvou variantách, přičemž první varianta pracuje s 32bitovým a druhá varianta s 64bitovým operandem):

CSET Wd, condition
CSET Xd, condition

Například:

CSET W3, EQ
CSET W4, MI
CSET X5, HI

Tato instrukce pracuje následujícím způsobem – v případě, že je podmínka zapsaná ve druhém operandu cond splněna, uloží se do cílového registru Wd či do registru Xd hodnota 1. Pokud podmínka naopak splněna není, uloží se do registru Wd či Xd hodnota 0:

cíl = condition ? 1 : 0;

Ve skutečnosti se v případě CSET jedná o alias pro instrukci CSINC popsanou dále (podmínka ovšem musí být v tomto případě negována):

CSINC Wd, WZR, WZR, invert(condition)
CSINC Xd, XZR, XZR, invert(condition)

neboli:

cíl = invert(condition) ? 0 : 0+1;

Opět zde tedy využíváme vlastnosti registru WZR a XZR.

V některých případech je však nutné ukládat pravdivostní hodnoty odlišným způsobem – true bude reprezentováno hodnotou, v níž jsou všechny bity 32bitového či 64bitového slova nastaveny na jedničku (v případě celých čísel se znaménkem to odpovídá hodnotě –1), false naopak hodnotou, v níž jsou všechny bity nulové. V tomto případě lze pro nastavení namísto CSET použít instrukci CSETM:

CSETM Wd, condition
CSETM Xd, condition

Ve vyšším programovacím jazyce by bylo možné napsat:

cíl = condition ? -1 : 0;

Poznámka: u 32bitového registru odpovídá –1 hodnotě 0×ffff ffff, u 64bitového registru pak hodnotě 0×ffff ffff ffff ffff.

Opět se v tomto případě jedná o aliasy, tentokrát ovšem na instrukci CSINV:

CSINV Wd, WZR, WZR, invert(condition)
CSINV Xd, XZR, XZR, invert(condition)

Poznámka: slovo „mask“ v názvu instrukce skutečně poměrně přesně odpovídá jednomu způsobu použití, protože pokud platí true=-1 a false=0, lze s těmito hodnotami provádět logický součin a součet bit po bitu, a to i v případě, kdy je druhým operandem odlišná hodnota.

13. Podmíněný výběr operandu

Mezi další instrukce, v nichž se vyhodnocuje podmínka, patří:

# Instrukce Stručný popis
1 CSEL Conditional Select
2 CSINV Conditional Select Invert
3 CSINC Conditional Select Increment
4 CSNEG Conditional Select Negate

Užitečnou instrukcí s podmínkou je instrukce zapisovaná mnemotechnickým kódem CSEL neboli Conditional Select. I tato instrukce existuje ve dvou variantách – 32bitové a 64bitové:

CSEL Wd, Wn, Wm, condition
CSEL Xd, Xn, Xm, condition

Tato instrukce pracuje následovně: pokud je podmínka splněna, uloží se do cílového registru Wd či Xd hodnota z prvního zdrojového registru Wn nebo Xn. Pokud podmínka splněna není, je do cílového registru Wd/Xd uložena hodnota z druhého zdrojového registru Wm/Xm.

Instrukce CSEL tedy nahrazuje programovou konstrukci typu:

cíl = condition ? zdroj1 : zdroj2;

Alternativní formou instrukce CSEL je instrukce CSINV neboli Conditional Select Invert:

CSINV Wd, Wn, Wm, condition
CSINV Xd, Xn, Xm, condition

Tato instrukce pracuje následovně: pokud je podmínka splněna, uloží se do cílového registru Wd či Xd hodnota z prvního zdrojového registru Wn nebo Xn. Pokud podmínka splněna není, je do cílového registru Wd/Xd uložena negovaná hodnota přečtená z druhého zdrojového registru Wm/Xm.

Instrukce CSINV tedy nahrazuje programovou konstrukci typu:

cíl = condition ? zdroj1 : ~zdroj2;

Poznámka: znak ~ je používán v programovacím jazyku C a od něj odvozených jazycích pro zápis unárního operátoru negace všech bitů (jedničkový doplněk).

Zajímavá je instrukce CSINC, která kombinuje možnosti instrukce CINC a CSEL:

CSINC Wd, Wn, Wm, condition
CSINC Xd, Xn, Xm, condition

Tato instrukce provádí následující činnost:

Wd = condition ? Wn : Wm+1;
Xd = condition ? Xn : Xm+1;

Touto instrukcí realizována již popsaná pseudoinstrukce CSET, a to tehdy, pokud jsou oba zdrojové registry nulové (WZR a XZR). V tomto případě se do cílového registru dosadí 0 či 0+1=1:

CSINC Wd, WZR, WZR, invert(condition)
CSINC Xd, XZR, XZR, invert(condition)

Instrukce nazvaná CSNEG se do jisté míry podobá instrukci CSINV, ovšem s tím rozdílem, že se namísto jedničkového doplňku (negace) používá při nesplnění podmínky dvojkový doplněk:

CSNEG Wd, Wn, Wm, condition
CSNEG Xd, Xn, Xm, condition

Tato instrukce pracuje následovně: pokud je podmínka splněna, uloží se do cílového registru Wd či Xd hodnota z prvního zdrojového registru Wn nebo Xn. Pokud podmínka splněna není, je do cílového registru Wd/Xd uložena hodnota přečtená z druhého zdrojového registru Wm/Xm, u které se nejdříve změní znaménko (onen zmíněný dvojkový doplněk).

Tato instrukce tedy nahrazuje programovou konstrukci typu:

cíl = condition ? zdroj1 : -zdroj2;

14. Další instrukce s podmínkou

Poslední tři instrukce ze sady AArch64, v nichž se vyhodnocuje podmínka, jsou vypsány v tabulce pod tímto odstavcem:

# Instrukce Stručný popis
1 CINC Conditional Increment
2 CINV Conditional Invert
3 CNEG Conditional Negate

Instrukce CINC je aliasem pro instrukci CSINC, ovšem s převrácenou podmínkou a shodnými zdrojovými registry:

CINC Wd, Wn, condition
CINC Xd, Xn, condition

Tato instrukce provádí následující činnost (je zde jen jediný zdrojový registr):

Wd = condition ? Wn+1 : Wn;
Xd = condition ? Xn+1 : Xn;

Použití této instrukce je různé, může se například použít pro realizaci příkazu continue v programovacím jazyku C.

Podobná instrukce taktéž s jedním zdrojovým registrem se jmenuje CINV:

CINV Wd, Wn, condition
CINV Xd, Xn, condition

Prováděná činnost je následující (tilda znamená negaci bit po bitu):

Wd = condition ? ~Wn : Wn;
Xd = condition ? ~Xn : Xn;

Ve skutečnosti se opět jedná o instrukční alias rozpoznávaný assemblery. V tomto případě lze CINV nahradit instrukcí CSINV s oběma zdrojovými registry totožnými:

CSINV Wd, Wn, Wn, invert(condition)
CSINV Xd, Xn, Xn, invert(condition)

Poslední instrukce, přesněji řečeno (opět) instrukční alias se jmenuje CNEG:

CNEG Wd, Wn, condition
CNEG Xd, Xn, condition

Prováděná činnost:

Wd = condition ? -Wn : Wn;
Xd = condition ? -Xn : Xn;

Tento alias je možné nahradit za CSNEG s totožnými zdrojovými registry a opačně zapsanou podmínkou:

UX DAy - tip 2

CSNEG Wd, Wn, Wn, invert(condition)
CSNEG Xd, Xn, Xn, invert(condition)

15. Extrakce dat

Poslední skupina instrukcí, o níž se dnes zmíníme, slouží k takzvané extrakci dat. Jak je z tabulky patrné, mají tyto instrukce čtyři operandy, přičemž posledním operandem je konstanta 0..31 pro první instrukci či 0..63 pro instrukci druhou. Tyto dvě instrukce nejprve pomyslně spojí oba vstupní registry Wn:Wm či Xn:Xm a následně z takto vytvořeného dočasného pseudoregistru s dvojnásobnou šířkou získají 32bitové či 64bitové slovo od zadané pozice lsb:

# Instrukce Stručný popis
1 EXTR Wd, Wn, Wm, #lsb Wd = Wn:Wm<lsb+31,lsb>
2 EXTR Xd, Xn, Xm, #lsb Xd = Xn:Xm<lsb+63,lsb>

Opět platí, že díky existenci registrů WZR a XZR je možné z těchto instrukcí vytvořit různé aliasy. Taktéž je možné mít oba zdrojové registry totožné – asi nejznámějším aliasem využívajícím dva shodné zdrojové registry je již popsaná instrukce ROR (stačí si představit, jak se z registrového páru Xn:Xn vybírá 63 bitů).

16. Odkazy na Internetu

  1. Comparison of ARMv8-A cores
    https://en.wikipedia.org/wi­ki/Comparison_of_ARMv8-A_cores
  2. A64 General Instructions
    http://www.keil.com/suppor­t/man/docs/armclang_asm/ar­mclang_asm_pge1427898258836­.htm
  3. ARMv8 (AArch64) Instruction Encoding
    http://kitoslab-eng.blogspot.cz/2012/10/armv8-aarch64-instruction-encoding.html
  4. Cortex-A32 Processor
    https://www.arm.com/produc­ts/processors/cortex-a/cortex-a32-processor.php
  5. Cortex-A35 Processor
    https://www.arm.com/produc­ts/processors/cortex-a/cortex-a35-processor.php
  6. Cortex-A53 Processor
    https://www.arm.com/produc­ts/processors/cortex-a/cortex-a53-processor.php
  7. Cortex-A57 Processor
    https://www.arm.com/produc­ts/processors/cortex-a/cortex-a57-processor.php
  8. Cortex-A72 Processor
    https://www.arm.com/produc­ts/processors/cortex-a/cortex-a72-processor.php
  9. Cortex-A73 Processor
    https://www.arm.com/produc­ts/processors/cortex-a/cortex-a73-processor.php
  10. Apple A7 (SoC založen na CPU Cyclone)
    https://en.wikipedia.org/wi­ki/Apple_A7
  11. System cally pro AArch64 na Linuxu
    https://github.com/torval­ds/linux/blob/master/inclu­de/uapi/asm-generic/unistd.h
  12. Architectures/AArch64 (FedoraProject.org)
    https://fedoraproject.org/wi­ki/Architectures/AArch64
  13. SIG pro AArch64 (CentOS)
    https://wiki.centos.org/Spe­cialInterestGroup/AltArch/A­Arch64
  14. The ARMv8 instruction sets
    http://infocenter.arm.com/hel­p/index.jsp?topic=/com.ar­m.doc.den0024a/ch05s01.html
  15. A64 Instruction Set
    https://developer.arm.com/pro­ducts/architecture/instruc­tion-sets/a64-instruction-set
  16. Switching between the instruction sets
    http://infocenter.arm.com/hel­p/index.jsp?topic=/com.ar­m.doc.den0024a/ch05s01.html
  17. The A64 instruction set
    http://infocenter.arm.com/hel­p/index.jsp?topic=/com.ar­m.doc.den0024a/ch05s01.html
  18. Introduction to ARMv8 64-bit Architecture
    https://quequero.org/2014/04/in­troduction-to-arm-architecture/
  19. MCU market turns to 32-bits and ARM
    http://www.eetimes.com/do­cument.asp?doc_id=1280803
  20. Cortex-M0 Processor (ARM Holdings)
    http://www.arm.com/produc­ts/processors/cortex-m/cortex-m0.php
  21. Cortex-M0+ Processor (ARM Holdings)
    http://www.arm.com/produc­ts/processors/cortex-m/cortex-m0plus.php
  22. ARM Processors in a Mixed Signal World
    http://www.eeweb.com/blog/arm/arm-processors-in-a-mixed-signal-world
  23. ARM Architecture (Wikipedia)
    https://en.wikipedia.org/wi­ki/ARM_architecture
  24. DSP for Cortex-M
    https://developer.arm.com/techno­logies/dsp/dsp-for-cortex-m
  25. Cortex-M processors in DSP applications? Why not?!
    https://community.arm.com/pro­cessors/b/blog/posts/cortex-m-processors-in-dsp-applications-why-not
  26. White Paper – DSP capabilities of Cortex-M4 and Cortex-M7
    https://community.arm.com/pro­cessors/b/blog/posts/white-paper-dsp-capabilities-of-cortex-m4-and-cortex-m7
  27. Q (number format)
    https://en.wikipedia.org/wi­ki/Q_%28number_format%29
  28. TriCore Architecture & Core
    http://www.infineon.com/cms/en/pro­duct/microcontroller/32-bit-tricore-tm-microcontroller/tricore-tm-architecture-and-core/channel.html?channel=ff80808112ab681d0112­ab6b73d40837
  29. TriCoreTM V1.6 Instruction Set: 32-bit Unified Processor Core
    http://www.infineon.com/dgdl/tc_v131_in­structionset_v138.pdf?file­Id=db3a304412b407950112b409b6dd0352
  30. TriCore v2.2 C Compiler, Assembler, Linker Reference Manual
    http://tasking.com/suppor­t/tricore/tc_reference_gu­ide_v2.2.pdf
  31. Infineon TriCore (Wikipedia)
    https://en.wikipedia.org/wi­ki/Infineon_TriCore
  32. C166®S V2 Architecture & Core
    http://www.infineon.com/cms/en/pro­duct/microcontroller/16-bit-c166-microcontroller/c166-s-v2-architecture-and-core/channel.html?channel=db3a304312bef5660112­c3011c7d01ae
  33. Comparing four 32-bit soft processor cores
    http://www.eetimes.com/au­thor.asp?section_id=14&doc_id=1286116
  34. RISC-V Instruction Set
    http://riscv.org/download­.html#spec_compressed_isa
  35. RISC-V Spike (ISA Simulator)
    http://riscv.org/download.html#isa-sim
  36. RISC-V (Wikipedia)
    https://en.wikipedia.org/wiki/RISC-V
  37. David Patterson (Wikipedia)
    https://en.wikipedia.org/wi­ki/David_Patterson_(compu­ter_scientist)
  38. OpenRISC (oficiální stránky projektu)
    http://openrisc.io/
  39. OpenRISC architecture
    http://openrisc.io/architecture.html
  40. Emulátor OpenRISC CPU v JavaScriptu
    http://s-macke.github.io/jor1k/demos/main.html
  41. OpenRISC (Wikipedia)
    https://en.wikipedia.org/wi­ki/OpenRISC
  42. OpenRISC – instrukce
    http://sourceware.org/cgen/gen-doc/openrisc-insn.html
  43. OpenRISC – slajdy z přednášky o projektu
    https://iis.ee.ethz.ch/~gmichi/a­socd/lecturenotes/Lecture6­.pdf
  44. Berkeley RISC
    http://en.wikipedia.org/wi­ki/Berkeley_RISC
  45. Great moments in microprocessor history
    http://www.ibm.com/develo­perworks/library/pa-microhist.html
  46. Microprogram-Based Processors
    http://research.microsoft.com/en-us/um/people/gbell/Computer_Struc­tures_Principles_and_Exam­ples/csp0167.htm
  47. Great Microprocessors of the Past and Present
    http://www.cpushack.com/CPU/cpu1.html
  48. A Brief History of Microprogramming
    http://www.cs.clemson.edu/~mar­k/uprog.html
  49. What is RISC?
    http://www-cs-faculty.stanford.edu/~ero­berts/courses/soco/projec­ts/2000–01/risc/whatis/
  50. RISC vs. CISC
    http://www-cs-faculty.stanford.edu/~ero­berts/courses/soco/projec­ts/2000–01/risc/risccisc/
  51. RISC and CISC definitions:
    http://www.cpushack.com/CPU/cpu­AppendA.html
  52. FPGA
    https://cs.wikipedia.org/wi­ki/Programovateln%C3%A9_hra­dlov%C3%A9_pole
  53. The Evolution of RISC
    http://www.ibm.com/develo­perworks/library/pa-microhist.html#sidebar1

Byl pro vás článek přínosný?