Specifické vlastnosti procesorů AArch64: přenos bloků dat a instrukce s podmínkou

15. 3. 2022
Doba čtení: 30 minut

Sdílet

 Autor: Raspberry Pi Foundation
Článek je věnován dvěma důležitým tématům: přenosům dat a taktéž problematice provedení některých operací za předpokladu, že je splněna nějaká podmínka. AArch64 nabízí kromě podmíněných skoků i celou řadu dalších instrukcí s podmínkou.

Obsah

1. Problematika blokových přenosů dat

2. Blokový přenos po jednotlivých bajtech

3. Blokový přenos po 64bitových slovech

4. Přenos po dvojici 64bitových slov – instrukce LDPSTP

5. Výsledky benchmarků

6. Problematika provedení instrukcí při splnění určité podmínky

7. Nové instrukce s podmínkami

8. Instrukce CSET – Conditional Set

9. Instrukce CSETM – Conditional Set Mask

10. Instrukce CSEL – Conditional Select

11. Instrukce CSINV – Conditional Select Invert

12. Instrukce CSINC – Conditional Select Increment

13. Instrukce CSNEG – Conditional Select Negate

14. Instrukce CINC – Conditional Increment

15. Instrukce CINV – Conditional Invert

16. Instrukce CNEG – Conditional Negate

17. Instrukce TBZ a TBNZ (Test and Branch…)

18. Repositář s demonstračními příklady

19. Předchozí články o architektuře AArch64

20. Odkazy na Internetu

1. Problematika blokových přenosů dat

V závěrečné části předchozího článku jsme si ukázali, jakým způsobem je možné přenášet blok dat z jedné oblasti operační paměti do oblasti jiné. Připomeňme si, že jsme si pro tento účel vytvořili pomocné makro, které tuto operaci provede. Toto makro přenáší data po jednotlivých bajtech a lze ho použít vícekrát, protože návěští (label) loop je doplněno automaticky generovaným pořadovým číslem:

.macro moveBlockByBytes from, to, length
        ldr   x1, =\from        // adresa bloku pro čtení
        ldr   x2, =\to          // adresa bloku pro zápis
        mov   x4, #\length      // počet bajtu
loop\@:
        ldrb  w3, [x1], 1       // čtení bajtu
        strb  w3, [x2], 1       // zápis bajtu
        sub   x4, x4, #1        // zmenšení počitadla
        cbnz  x4, loop\@        // pokud jsme se nedostali k nule, skok na zacatek smycky
.endm

Ze zápisu tohoto makra je patrné, že smyčka, v níž k přenosu dochází, obsahuje čtveřici instrukcí. První dvě instrukce načtou bajt, který následně uloží (písmeno b na konci jména instrukce určuje, že se pracuje jen s osmi bity registru w3). Současně jsou zvýšeny i hodnoty registrů x1 a x2 obsahujících adresu dalšího čteného resp. zapisovaného bajtu. Třetí instrukce snižuje hodnotu počitadla (počet zbývajících bajtů, které se mají přenést) a poslední instrukcí je podmíněný skok – v případě, že je hodnota registru x4 (tedy počitadla) nenulová, provede se další iterace.

2. Blokový po jednotlivých bajtech

Přenos dat je proveden po jednotlivých bajtech, což i přes (relativní) krátkost programové smyčky znamená, že se ani zdaleka nevyužijí možnosti nabízené 64bitovým mikroprocesorem, který je mnohdy vybaven plnohodnotnou 64bitovou externí datovou sběrnicí. Bylo by tedy dobré zjistit rychlost blokových přenosů. K tomuto účelu si vytvoříme jednoduchý benchmark, který bude přenášet větší blok (ideálně o délce dělitelné šestnácti), a to tolikrát, aby bylo možné dobu běhu změřit standardním nástrojem time. Na konkrétním počítači, na němž byl benchmark odladěn, je přenos řízen touto počítanou programovou smyčkou:

        mov   x10, #50000       // počet opakování blokového přesunu
        lsl   x10, x10, #8      // ještě zvětšíme počet opakování
loop:
        moveBlockByBytes hello_lbl, buffer, rep_count
        sub   x10, x10, #1      // snížení hodnoty počitadla
        cbnz  x10, loop         // pokud se nedosáhlo nuly, opakovat
Poznámka: instrukce typu mov registr, #konstanta dokáže pracovat pouze s omezenou velikostí konstanty přenášené do registru – tato konstanta může být jen 16bitová (viz též úvodní článek). Z tohoto důvodu zapisovanou konstantu (50000) navíc ještě posuneme o osm bitů doleva, tedy ji osmkrát vynásobíme dvěma. Výsledný počet opakování smyčky je roven 12800000. Přenáší se blok o velikosti 448 bajtů, celkově se tedy přenese 5,34 GB.

Úplný zdrojový kód prvního benchmarku vypadá následovně:

# asmsyntax=as
 
# Přesun bloku dat po jednotlivých bajtech.
#
# Autor: Pavel Tišnovský
 
 
 
# Linux kernel system call table
sys_exit=93
sys_write=64
 
# List of syscalls for AArch64:
# https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/unistd.h
 
# počet bajtu pro blokové přesuny
rep_count  = 448
 
 
# Deklarace makra pro ukončení aplikace
.macro exit
        mov  x8, #sys_exit      // číslo sycallu pro funkci "exit"
        mov  x0, #0             // exit code = 0
        svc  0                  // volání Linuxového kernelu
.endm
 
 
 
# Deklarace makra pro vytištění zprávy na standardní výstup
.macro writeMessage message, messageLength
        mov  x8, #sys_write       // číslo sycallu pro funkci "write"
        mov  x0, #1               // standardní výstup
        ldr  x1, =\message        // adresa řetězce, který se má vytisknout
        mov  x2, #\messageLength  // počet znaků, které se mají vytisknout
        svc  0                    // volání Linuxového kernelu
.endm
 
 
 
# Deklarace makra pro přesun bloku po bajtech
.macro moveBlockByBytes from, to, length
        ldr   x1, =\from        // adresa bloku pro čtení
        ldr   x2, =\to          // adresa bloku pro zápis
        mov   x4, #\length      // počet bajtu
loop\@:
        ldrb  w3, [x1], 1       // čtení bajtu
        strb  w3, [x2], 1       // zápis bajtu
        sub   x4, x4, #1        // zmenšení počitadla
        cbnz  x4, loop\@        // pokud jsme se nedostali k nule, skok na začátek smyčky
.endm
 
 
.balign 8
 
#-----------------------------------------------------------------------------
.section .data
 
hello_lbl:
        .string "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
        do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
        ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
        aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit
        in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        Excepteur sint occaecat cupidatat non proident, sunt in culpa qui
        officia deserunt mollit anim id est laborum<pad>"
 
 
#-----------------------------------------------------------------------------
.section .bss
 
        .lcomm buffer, rep_count     // rezervace bufferu pro výstup
 
 
 
#-----------------------------------------------------------------------------
.section .text
        .global _start          // tento symbol má být dostupný i linkeru
 
_start:
        writeMessage buffer, rep_count
 
        mov   x10, #50000       // počet opakování blokového přesunu
        lsl   x10, x10, #8      // ještě zvětšíme počet opakování
loop:
        moveBlockByBytes hello_lbl, buffer, rep_count
        sub   x10, x10, #1      // snížení hodnoty počitadla
        cbnz  x10, loop         // pokud se nedosáhlo nuly, opakovat
 
        writeMessage buffer, rep_count
 
        exit

3. Blokový přenos po 64bitových slovech

Plného využití možností 64bitových mikroprocesorů s 64bitovou externí sběrnicí dosáhneme pouze tehdy, pokud budeme blokové přenosy provádět po 64bitových slovech a nikoli po jednotlivých bajtech. Nejprve je vhodné zajistit zarovnání dat assemblerem:

.balign 8

Následně můžeme makro pro blokový přenos upravit takovým způsobem, aby se data přenášela po celých slovech, konkrétně přes registr x3. Povšimněte si, že adresy v registrech x1 a x2 zvyšujeme po osmi a počitadlo smyčky naopak snižujeme o konstantu 8. Jedinou další úpravou je náhrada instrukcí LDRP a STRP za „plnohodnotné“ 64bitové instrukce LDR a STR:

# Deklarace makra pro přesun bloku po osmi bajtech
.macro moveBlockByWords from, to, length
        ldr   x1, =\from        // adresa bloku pro čtení
        ldr   x2, =\to          // adresa bloku pro zápis
        mov   x4, #\length      // počet bajtů, které se mají přenést
loop\@:
        ldr   x3, [x1], 8       // čtení osmi bajtů
        str   x3, [x2], 8       // zápis osmi bajtů
        sub   x4, x4, #8        // zmenšení počitadla
        cbnz  x4, loop\@        // pokud jsme se nedostali k nule, skok na začátek smyčky
.endm

Další změny v benchmarku již není nutné provádět, ale stejně si pro jistotu ukažme jeho plnou verzi:

# asmsyntax=as
 
# Presun bloku dat po osmi bajtech.
#
# Autor: Pavel Tišnovský
 
 
 
# Linux kernel system call table
sys_exit=93
sys_write=64
 
# List of syscalls for AArch64:
# https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/unistd.h
 
# počet bajtů pro blokové přesuny
rep_count  = 448
 
 
# Deklarace makra pro ukončení aplikace
.macro exit
        mov  x8, #sys_exit      // číslo sycallu pro funkci "exit"
        mov  x0, #0             // exit code = 0
        svc  0                  // volání Linuxového kernelu
.endm
 
 
 
# Deklarace makra pro vytištění zprávy na standardní výstup
.macro writeMessage message, messageLength
        mov  x8, #sys_write       // číslo sycallu pro funkci "write"
        mov  x0, #1               // standardní výstup
        ldr  x1, =\message        // adresa řetězce, který se má vytisknout
        mov  x2, #\messageLength  // počet znaků, které se mají vytisknout
        svc  0                    // volání Linuxového kernelu
.endm
 
 
 
# Deklarace makra pro presun bloku po osmi bajtech
.macro moveBlockByWords from, to, length
        ldr   x1, =\from        // adresa bloku pro čtení
        ldr   x2, =\to          // adresa bloku pro zápis
        mov   x4, #\length      // počet bajtu
loop\@:
        ldr   x3, [x1], 8       // čtení osmi bajtů
        str   x3, [x2], 8       // zápis osmi bajtů
        sub   x4, x4, #8        // zmenšení počitadla
        cbnz  x4, loop\@        // pokud jsme se nedostali k nule, skok na začátek smyčky
.endm
 
 
.balign 8
 
#-----------------------------------------------------------------------------
.section .data
 
hello_lbl:
        .string "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
        do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
        ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
        aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit
        in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        Excepteur sint occaecat cupidatat non proident, sunt in culpa qui
        officia deserunt mollit anim id est laborum<pad>"
 
 
#-----------------------------------------------------------------------------
.section .bss
 
        .lcomm buffer, rep_count     // rezervace bufferu pro výstup
 
 
 
#-----------------------------------------------------------------------------
.section .text
        .global _start          // tento symbol má byt dostupný i linkeru
 
_start:
        writeMessage buffer, rep_count
 
        mov   x10, #50000       // počet opakování blokového přesunu
        lsl   x10, x10, #8      // ještě zvětšíme počet opakování
loop:
        moveBlockByWords hello_lbl, buffer, rep_count
        sub   x10, x10, #1      // snížení hodnoty počitadla
        cbnz  x10, loop         // pokud se nedosáhlo nuly, opakovat
 
        writeMessage buffer, rep_count
 
        exit

4. Přenos po dvojici 64bitových slov – instrukce LDPSTP

Mikroprocesory s architekturou AArch64 obsahují i dvojici instrukcí určených pro načtení dvou 32bitových nebo 64bitových slov do dvojice zvolených pracovních registrů a taktéž pro uložení dvojice 32bitových a 64bitových registrů do paměti. Tyto instrukce mají mnemotechnické zkratky LDP (Load Pair) a STP (Store Pair). Jedná se o instrukce, které je možné využít k mnoha účelům – typicky při ukládání operandů do paměti před voláním funkce, v přerušovacích rutinách atd. Důležité přitom je, že volba, o jakou dvojici registrů se jedná, je zcela libovolná – může se tedy například jednat o registry, jejichž indexy nejsou sousední atd.

Poznámka: na architektuře AArch64 neexistují instrukce LDM a STM, které u klasických 32bitových ARMů mohly sloužit k načtení nebo uložení pracovních registrů R0 až R15. O jaké registry se jednalo bylo určeno obsahem bitového pole. To tedy znamenalo, že se mohlo například jednat o registry R0, R6 a R10, ovšem pořadí již nebylo možné specifikovat. Instrukce LDP a STP tedy na jednu stranu umožňují práci jen s dvojicí registrů, ovšem nabízí větší flexibilitu (například prohození obsahu dvou slov v paměti lze vyřešit dvojicí LDP+STP, zatímco u 32bitových ARMů je množství potřebných instrukcí vyšší).

Podívejme se nyní na to, jakým způsobem jsou vlastně instrukce LDP a STP zakódovány. Tyto instrukce musí v instrukčním slovu obsahovat indexy trojice pracovních registrů – jeden z těchto registrů je použit při adresování, další dva registry pak budou obsahovat načtená slova (instrukce LDP) či naopak poslouží jako zdroj dat (konkrétně dvou slov), která se budou ukládat do operační paměti (instrukce STP). Navíc je v instrukčním slovu uložena i relativně krátká (sedmibitová) konstanta. Existují tři různé varianty těchto instrukcí, které se liší podle toho, jakým způsobem je tato konstanta využita:

  1. Konstanta je použita pro zvýšení obsahu adresovacího registru po provedení operace (post-inkrement, post-dekrement)
  2. Konstanta je použita pro zvýšení obsahu adresovacího registru před provedením operace (pre-inkrement, pre-dekrement)
  3. Konstanta je použita ve funkci offsetu, který je přičten k registru použitému pro adresování

Kódování instrukcí s post-inkrementem a post-dekrementem:

31      23 22 21    15 14 10 9   5 4    0
+---------+---+-------+-----+-----+-----+
|101010001| L |iiiiiii| R2  | Rn  | R1  |
+---------+---+-------+-----+-----+-----+

Bit L slouží k volbě instrukce 0-STP a 1-LDP. Samotná konstanta je sedmibitová a je uložena v bitovém poli iiiiiii.

Kódování instrukcí s pre-inkrementem a pre-dekrementem:

31      23 22 21    15 14 10 9   5 4    0
+---------+---+-------+-----+-----+-----+
|101010011| L |iiiiiii| R2  | Rn  | R1  |
+---------+---+-------+-----+-----+-----+

Kódování instrukcí s offsetem:

31      23 22 21    15 14 10 9   5 4    0
+---------+---+-------+-----+-----+-----+
|101010010| L |iiiiiii| R2  | Rn  | R1  |
+---------+---+-------+-----+-----+-----+

Se znalostí instrukcí LDP a STP můžeme upravit makro pro blokové přenosy dat takovým způsobem, aby se v každé iteraci smyčky přenesla dvojice 64bitových slov, tedy dohromady šestnáct bajtů. Samozřejmě se musí příslušným způsobem pracovat i s počitadlem smyčky, změnou adresy atd:

# Deklarace makra pro presun bloku po dvou slovech
.macro moveBlockByTwoWords from, to, length
        ldr   x1, =\from        // adresa bloku pro čtení
        ldr   x2, =\to          // adresa bloku pro zápis
        mov   x5, #\length      // počet bajtu
loop\@:
        ldp   x3, x4, [x1], 16  // čtení 2x osmi bajtů
        stp   x3, x4, [x2], 16  // zápis 2x osmi bajtů
        sub   x5, x5, #16       // zmenšení počitadla
        cbnz  x5, loop\@        // pokud jsme se nedostali k nule, skok na začátek smyčky
.endm

V případě, že je zaručeno zarovnání bloků na hranice šestnácti bajtů, lze náš demonstrační příklad převést do podoby:

# asmsyntax=as
 
# Presun bloku dat po 2x osmi bajtech.
#
# Autor: Pavel Tišnovský
 
 
 
# Linux kernel system call table
sys_exit=93
sys_write=64
 
# List of syscalls for AArch64:
# https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/unistd.h
 
# počet bajtu pro blokove presuny
rep_count  = 448
 
 
# Deklarace makra pro ukončení aplikace
.macro exit
        mov  x8, #sys_exit      // číslo sycallu pro funkci "exit"
        mov  x0, #0             // exit code = 0
        svc  0                  // volání Linuxového kernelu
.endm
 
 
 
# Deklarace makra pro vytištění zprávy na standardní výstup
.macro writeMessage message, messageLength
        mov  x8, #sys_write       // číslo sycallu pro funkci "write"
        mov  x0, #1               // standardní výstup
        ldr  x1, =\message        // adresa řetězce, který se má vytisknout
        mov  x2, #\messageLength  // počet znaků, které se mají vytisknout
        svc  0                    // volání Linuxového kernelu
.endm
 
 
# Deklarace makra pro presun bloku po dvou slovech
.macro moveBlockByTwoWords from, to, length
        ldr   x1, =\from        // adresa bloku pro čtení
        ldr   x2, =\to          // adresa bloku pro zápis
        mov   x5, #\length      // počet bajtu
loop\@:
        ldp   x3, x4, [x1], 16  // čtení 2x osmi bajtů
        stp   x3, x4, [x2], 16  // zápis 2x osmi bajtů
        sub   x5, x5, #16       // zmenšení počitadla
        cbnz  x5, loop\@        // pokud jsme se nedostali k nule, skok na začátek smyčky
.endm
 
 
.balign 16
 
#-----------------------------------------------------------------------------
.section .data
 
hello_lbl:
        .string "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
        do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
        ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
        aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit
        in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        Excepteur sint occaecat cupidatat non proident, sunt in culpa qui
        officia deserunt mollit anim id est laborum<pad>"
 
 
#-----------------------------------------------------------------------------
.section .bss
 
        .lcomm buffer, rep_count     // rezervace bufferu pro výstup
 
 
 
#-----------------------------------------------------------------------------
.section .text
        .global _start          // tento symbol ma byt dostupny i linkeru
 
_start:
        writeMessage buffer, rep_count
 
        mov   x10, #50000       // počet opakování blokového přesunu
        lsl   x10, x10, #8      // ještě zvětšíme počet opakování
loop:
        moveBlockByTwoWords hello_lbl, buffer, rep_count
        sub   x10, x10, #1      // snížení hodnoty počitadla
        cbnz  x10, loop         // pokud se nedosáhlo nuly, opakovat
 
        writeMessage buffer, rep_count
 
        exit

5. Výsledky benchmarků

Všechny tři demonstrační příklady, které jsme si prozatím popsali, provádí opakovaný přenos stejného bloku dat, přičemž počet opakování přenosu (a tím pádem i celkový počet přenesených bajtů) je stále stejný. Můžeme tudíž porovnat časy běhu všech příkladů a zjistit, do jaké míry je přenos po slovech nebo „dvojslovech“ rychlejší, než přenos po jednotlivých bajtech.

Využití makra pro blokový přenos po bajtech:

$ time ./move5
 
real    0m3.909s
user    0m3.908s
sys     0m0.000s
Poznámka: z výsledků je patrné, že celý přenos celkem 5,34 GB byl v tomto případě dokončen za necelé čtyři sekundy.

Využití makra pro blokový přenos po 64bitových slovech:

$ time ./move6
 
real    0m0.498s
user    0m0.498s
sys     0m0.000s
Poznámka: nyní byl přenos proveden v 64bitových slovech, což by teoreticky mělo znamenat osminásobnou rychlost (ovšem z pohledu datové sběrnice a paměti tomu tak zdaleka být nemusí). Reálně naměřené urychlení je 7,83×, což poměrně přesně koresponduje s očekávanou hodnotou.

Využití makra pro blokový přenos po dvojici 64bitových slov:

$ time ./move7
 
real    0m0.258s
user    0m0.257s
sys     0m0.000s
Poznámka: toto je poměrně zajímavá situace, protože jsme oproti předchozímu příkladu dosáhli přibližně 1,9× násobného urychlení, i když jsme byli stále omezení (externí) datovou sběrnicí i rychlostí (nebo spíše pomalostí) operační paměti a cache. Ovšem počet provedení operací LOAD+STORE+SUB+CBNZ se zmenšil na polovinu.

6. Problematika provedení instrukcí při splnění určité podmínky

Ve druhé části dnešního článku se zaměříme na prozatím relativně novou oblast. Jedná se o speciální instrukce implementované na moderní mikroprocesorové architektuře AArch64, které provádí specifikovanou činnost (nastavení registru na určitou hodnotu, inverze obsahu registru atd.), ale pouze za předpokladu, že je splněna nějaká zadaná podmínka (kód podmínky je přitom součástí instrukčního slova). Připomeňme si, že na rozdíl od původní 32bitové architektury ARM (dnes označované ARM32 nebo též jen A32) nemají všechny instrukce na AArch64 rezervovány čtyři nejvyšší bity pro specifikaci podmínky. Tato vlastnost byla na základě analýzy existujících programových strojových kódů, které za dobu existence platformy ARM vznikly, zrušena a podmínky je tak možné použít pouze u vybrané množiny instrukcí. Do této množiny byly zahrnuty i zcela nové instrukce, které na původní platformě ARM32 nenalezneme, což je opět důsledek analýzy stávajících strojových kódů, ale i studia funkce překladačů.

Poznámka: podle některých vývojářů může mít extenzivní použití příznakových bitů negativní vliv na výkonnost procesoru, což je však téma, které je řešeno nejenom na AArch64, ale i na platformě x86–64 (výjimkou je například architektura MIPS, která příznakové bity nepoužívá).

Připomeňme si, že na procesorové architektuře AArch64 je použito celkem čtrnáct různých podmínek, k nimž se někdy přidává i pseudopodmínka AL neboli Any/Always. V tomto případě se samozřejmě o žádnou skutečnou podmínku nejedná, neboť je instrukce provedena v každém případě, tedy nezávisle na aktuálním stavu příznakových bitů.

Prvních šest podmínek testuje hodnotu pouze jediného bitového příznaku, a to N (negative), Z (zero) či V (overflow):

Kód Přípona Význam Testovaná podmínka
0000 EQ Z = 1 rovnost po porovnání (či nulový výsledek)
0001 NE Z = 0 nerovnost po porovnání (či nenulový výsledek)
0100 MI N = 1 výsledek je záporný
0101 PL N = 0 výsledek je kladný či nulový
0110 VS V = 1 nastalo přetečení (overflow)
0111 VC V = 0 nenastalo přetečení (overflow)
1110 AL Any/Always většinou se nezapisuje, implicitní podmínka
Poznámka: příznakové bity jsou nastavovány jak 32bitovými, tak i 64bitovými operacemi, a to naprosto stejným způsobem.

Další čtyři podmínkové kódy se většinou používají při porovnávání dvou hodnot bez znaménka (unsigned). 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

Důležité přitom je, že všechny dále popsané instrukce podporují všechny výše zmíněné podmínky. Výjimku tvoří minule popsané instrukce CBZ a CBNZ, které pouze testovaly nulovost či naopak nenulovost vybraného pracovního registru.

Instrukce Stručný popis instrukce
B.podmínka návěští podmíněný skok po splnění podmínky na zadané návěští (kódy podmínek byly uvedeny výše)
CBZ Wn, návěští pokud platí Wn=0, skok na zadané návěští
CBZ Xn, návěští pokud platí Xn=0, skok na zadané návěští
CBNZ Wn, návěští pokud platí Wn≠0, skok na zadané návěští
CBNZ Xn, návěští pokud platí Xn≠0, skok na zadané návěští
Poznámka: tyto instrukce jsou (ve své variantě s 32bitovými registry) zpětně kompatibilní s instrukcemi známými z 32bitové architektury ARM32.

7. Nové instrukce s podmínkami

Mezi nové instrukce s podmínkou, které lze použít na architektuře AArch64, patří především:

Instrukce Význam mnemotechnického kódu instrukce Kapitola
CSET Conditional Set 8
CSETM Conditional Set Mask 9
CSEL Conditional Select 10
CSINV Conditional Select Invert 11
CSINC Conditional Select Increment 12
CSNEG Conditional Select Negate 13
CINC Conditional Increment 14
CINV Conditional Invert 15
CNEG Conditional Negate 16
TBZ Test and Branch if Zero 17
TBNZ Test and Branch if not zero 17

Kromě instrukcí TBZ a TBNZ mají ostatní instrukce prakticky shodné instrukční slovo, které je rozděleno do několika bitových polí:

31 30 29 28    21 20 16 15   12   9    5 4    0
+--+--+-+--------+-----+-----+---+-----+-----+
|sf|op|S|11010100| Rm  |cond |op2| Rn  | Rd  |
+--+--+-+--------+-----+-----+---+-----+-----+

Povšimněte si, že v instrukčním slovu je určena trojice pracovních registrů, z nichž dva obsahují zdrojové operandy a třetí pak výsledek činnosti instrukce.

Podle bitů v bitových polích sf, op, S a op2 se rozlišuje, o jakou instrukci se jedná a taktéž, zda se jedná o 32bitovou variantu (s registry Wx) nebo o variantu 64bitovou (s registry Xx):

sf op S op2 Instrukce Varianta
0 0 0 00 CSEL 32 bitů
0 0 0 01 CSINC 32 bitů
0 1 0 00 CSINV 32 bitů
0 1 0 01 CSNEG 32 bitů
1 0 0 00 CSEL 64 bitů
1 0 0 01 CSINC 64 bitů
1 1 0 00 CSINV 64 bitů
1 1 0 01 CSNEG 64 bitů

Instrukční slova instrukcí TBZ a TBNZ mají odlišný formát, s nímž se seznámíme v sedmnácté kapitole.

8. Instrukce CSET – Conditional Set

První novou instrukcí s podmínkou, s níž se v dnešním článku seznámíme, je instrukce nazvaná CSET, což je mnemotechnická zkratka celého názvu 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. Zápis této instrukce v assembleru (včetně GNU Assembleru) může vypadat následovně:

CSET Wd, podmínka
CSET Xd, podmínka

Například (ukázka pro různé podmínky):

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 (tedy pokud mají podmínkové/příznakové bity očekávané hodnoty), uloží se do cílového 32bitového registru Wd či do 64bitového 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ě instrukce 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(podmínka)
CSINC Xd, XZR, XZR, invert(podmínka)

neboli:

cíl = invert(condition) ? 0 : 0+1;
Poznámka: opět zde můžeme vidět, že zavedení registrů WZR a XZR, které (pro operaci čtení) vždy vrací nulu, umožňuje do instrukční sady prakticky zadarmo přidávat nové zajímavé a užitečné instrukce.

9. Instrukce CSETM – Conditional Set Mask

V některých případech je nutné ukládat pravdivostní hodnoty true a false odlišným způsobem – pravdivostní hodnota true bude reprezentována konstantou, v níž jsou všechny bity nastaveny na jedničku (v případě celých čísel se znaménkem to odpovídá hodnotě –1), hodnota false naopak konstantou, v níž jsou všechny bity nulové. V tomto případě je možné pro nastavení pravdivostní hodnoty na základě podmínky použít instrukci s mnemotechnickou zkratkou CSETM neboli Conditional Set Mask:

CSETM Wd, podmínka
CSETM Xd, podmínka

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

cíl = condition ? -1 : 0;
Poznámka: u 32bitového registru odpovídá dekadická hodnota –1 hexadecimální hodnotě 0×ffff ffff, u 64bitového registru pak hodnotě 0×ffff ffff ffff ffff.

V případě instrukce CSETM se opět jedná o aliasy, tentokrát ovšem na instrukci CSINV a nikoli CSINC:

CSINV Wd, WZR, WZR, invert(podmínka)
CSINV Xd, XZR, XZR, invert(podmínka)
Poznámka: slovo „mask“ v názvu instrukce skutečně poměrně přesně odpovídá jednomu způsobu jejího 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.

10. Instrukce CSEL – Conditional Select

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

CSEL Wd, Wn, Wm, podmínka
CSEL Xd, Xn, Xm, podmínka

Instrukce CSEL pracuje následovně: v případě, že 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 = podmínka ? zdroj1 : zdroj2;
Poznámka: je vhodné si uvědomit, jak by se tato operace musela řešit v případě, že by instrukce CSEL neexistovala. Musela by být nahrazena (přibližně) tímto kódem, který v každém případě vede k jedné instrukci skoku:
if:
        B.neg_podmínka else
        MOV Wd, Wn
        B endif
else:
        MOV Wd, Wm
endif:

11. Instrukce CSINV – Conditional Select Invert

Alternativní formou instrukce CSEL popsané v předchozí kapitole je instrukce s mnemotechnickou zkratkou CSINV neboli Conditional Select Invert:

CSINV Wd, Wn, Wm, podmínka
CSINV Xd, Xn, Xm, podmínka

Tato instrukce pracuje následovně: v případě, že je zapsaná 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. Opět by pochopitelně bylo možné tuto instrukci nahradit složitějším kódem, v němž by byl použit nepodmíněný skok B i skok podmíněný B.podmínka.

Instrukce CSINV tedy nahrazuje programovou konstrukci typu:

cíl = podmínka ? 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).

12. Instrukce CSINC – Conditional Select Increment

Zajímavá je instrukce CSINC, která kombinuje možnosti instrukce CINC a CSEL. Zápis této instrukce v assembleru vypadá následovně:

CSINC Wd, Wn, Wm, podmínka
CSINC Xd, Xn, Xm, podmínka

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

Wd = podmínka ? Wn : Wm+1;
Xd = podmínka ? Xn : Xm+1;

Jak jsme si již řekli v osmé kapitole, je touto instrukcí realizována i pseudoinstrukce CSET, a to tehdy, pokud jsou oba zdrojové registry nulové (WZR a XZR). V tomto případě se totiž do cílového registru dosadí buď hodnota 0 nebo hodnota 0+1=1:

CSINC Wd, WZR, WZR, invert(podmínka)
CSINC Xd, XZR, XZR, invert(podmínka)

13. Instrukce CSNEG – Conditional Select Negate

Instrukce nazvaná CSNEG se do jisté míry podobá již popsané 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. Opět je možné použít 32bitovou či 64bitovou variantu této instrukce:

CSNEG Wd, Wn, Wm, podmínka
CSNEG Xd, Xn, Xm, podmínka

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 naopak 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 (tedy vypočte se onen zmíněný dvojkový doplněk).

Tato instrukce tedy nahrazuje programovou konstrukci typu:

cíl = podmínka ? zdroj1 : -zdroj2;

14. Instrukce CINC – Conditional Increment

Instrukce CINC je jmenným aliasem pro instrukci CSINC, ovšem s převrácenou podmínkou a shodnými zdrojovými registry. Zápis této instrukce v assembleru:

CINC Wd, Wn, podmínka
CINC Xd, Xn, podmínka

Tato instrukce provádí následující činnost (povšimněte si, že je zde pouze jediný zdrojový registr):

Wd = podmínka ? Wn+1 : Wn;
Xd = podmínka ? 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.

15. Instrukce CINV – Conditional Invert

Podobná instrukce taktéž s jedním zdrojovým registrem se jmenuje CINV a v assembleru se zapisuje následovně:

CINV Wd, Wn, podmínka
CINV Xd, Xn, podmínka

Prováděná činnost je následující (připomeňme si, že tilda znamená negaci bit po bitu):

Wd = podmínka ? ~Wn : Wn;
Xd = podmínka ? ~Xn : Xn;

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

CSINV Wd, Wn, Wn, invert(podmínka)
CSINV Xd, Xn, Xn, invert(podmínka)

16. Instrukce CNEG – Conditional Negate

Poslední instrukce ze skupiny přenosových instrukcí s podmínkou, přesněji řečeno (opět) instrukční alias se jmenuje CNEG:

CNEG Wd, Wn, podmínka
CNEG Xd, Xn, podmínka

Činnost prováděná touto instrukcí je následující:

Wd = podmínka ? -Wn : Wn;
Xd = podmínka ? -Xn : Xn;

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

CSNEG Wd, Wn, Wn, invert(podmínka)
CSNEG Xd, Xn, Xn, invert(podmínka)

17. Instrukce TBZ a TBNZ (Test and Branch…)

Poslední dvě instrukce, které si dnes popíšeme, spadají do kategorie podmíněných skoků. Tyto instrukce se jmenují TBZ (Test and Branch if Zero) a TBNZ (Test and Branch if Not Zero). Způsob zápisu těchto instrukcí v assembleru 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á v případě těchto instrukcí šířku pouze šesti 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 nulu. 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):

ict ve školství 24

31 30   25 24 23  19 18           5 4    0
+--+------+--+------+--------------+-----+
|b5|011011|op|b4..b0| immediate 14 | Rt  |
+--+------+--+------+--------------+-----+
Poznámka: index testovaného bitu je v instrukčním slovu rozdělen na dvě části: nejvyšší bit b5 a spodních pět bitů b4..b0 (instrukční kódy AArch64 ani zdaleka nejsou dobře zapamatovatelné).

18. Repositář s demonstračními příklady

Všechny minule i dnes popisované demonstrační příklady byly společně s podpůrným souborem Makefile určeným pro jejich překlad či naopak pro disassembling, uloženy do GIT repositáře dostupného na adrese https://github.com/tisnik/pre­sentations/. Všechny příklady jsou určeny pro standardní GNU Assembler a používají výchozí syntaxi procesorů AArch64. Následuje tabulka s odkazy na zdrojové kódy příkladů i na již zmíněné podpůrné skripty:

# Příklad Popis Zdrojový kód
1 template.s šablona pro programy psané v assembleru https://github.com/tisnik/pre­sentations/blob/master/as­sembler/aarch64/template.s
2 template2.s šablona pro programy psané v assembleru, založeno na makrech https://github.com/tisnik/pre­sentations/blob/master/as­sembler/aarch64/template.s
3 hello_world1.s základní podoba programu typu „Hello, world!“ https://github.com/tisnik/pre­sentations/blob/master/as­sembler/aarch64/hello_wor­ld1.s
4 hello_world2.s přepis tištěného řetězce https://github.com/tisnik/pre­sentations/blob/master/as­sembler/aarch64/hello_wor­ld2.s
5 hello_world3.s refaktoring, použití maker https://github.com/tisnik/pre­sentations/blob/master/as­sembler/aarch64/hello_wor­ld3.s
6 aritmetic1.s základní aritmetické operace https://github.com/tisnik/pre­sentations/blob/master/as­sembler/aarch64/aritmetic1­.s
7 infinite_loop.s nekonečná programová smyčka realizovaná instrukcí b https://github.com/tisnik/pre­sentations/blob/master/as­sembler/aarch64/infinite_lo­op.s
8 loop1-aarch64-v1.s základní varianta počítané programové smyčky https://github.com/tisnik/pre­sentations/blob/master/as­sembler/aarch64/loop1-aarch64-v1.s
9 loop1-aarch64-v2.s optimalizace – odstranění instrukce CMP https://github.com/tisnik/pre­sentations/blob/master/as­sembler/aarch64/loop1-aarch64-v2.s
10 loop1-aarch64-v3.s optimalizace – použití instrukce CBNZ https://github.com/tisnik/pre­sentations/blob/master/as­sembler/aarch64/loop1-aarch64-v3.s
11 loop1-aarch64-v4.s automatické zvýšení adresy (ukazatele) https://github.com/tisnik/pre­sentations/blob/master/as­sembler/aarch64/loop1-aarch64-v4.s
12 move1.s přesun bloku dat https://github.com/tisnik/pre­sentations/blob/master/as­sembler/aarch64/move1.s
13 move2.s přepis s využitím maker https://github.com/tisnik/pre­sentations/blob/master/as­sembler/aarch64/move2.s
14 move3.s problém s vícenásobným použitím makra https://github.com/tisnik/pre­sentations/blob/master/as­sembler/aarch64/move3.s
15 move4.s vyřešení předchozího problému https://github.com/tisnik/pre­sentations/blob/master/as­sembler/aarch64/move4.s
16 move5.s jednoduchý benchmark – přesun bloků po bajtech https://github.com/tisnik/pre­sentations/blob/master/as­sembler/aarch64/move5.s
17 move6.s jednoduchý benchmark – přesun bloků po slovech https://github.com/tisnik/pre­sentations/blob/master/as­sembler/aarch64/move6.s
18 move7.s jednoduchý benchmark – přesun bloků po dvojicích slov https://github.com/tisnik/pre­sentations/blob/master/as­sembler/aarch64/move7.s
19      
20 Makefile soubor pro překlad všech příkladů nástrojem make https://github.com/tisnik/pre­sentations/blob/master/as­sembler/aarch64/Makefile

19. Předchozí články o architektuře AArch64

S architekturou AArch64 jsme se již na stránkách Roota setkali, a to konkrétně v následujících článcích, z nichž dnes vycházíme:

  1. 64bitové mikroprocesory s architekturou AArch64
    https://www.root.cz/clanky/64bitove-mikroprocesory-s-architekturou-aarch64/
  2. Instrukční sada AArch64
    https://www.root.cz/clanky/instrukcni-sada-aarch64/
  3. Instrukční sada AArch64 (2.část)
    https://www.root.cz/clanky/instrukcni-sada-aarch64–2-cast/
  4. Tvorba a ladění programů v assembleru mikroprocesorů AArch64
    https://www.root.cz/clanky/tvorba-a-ladeni-programu-v-assembleru-mikroprocesoru-aarch64/
  5. Instrukční sada AArch64: technologie NEON
    https://www.root.cz/clanky/instrukcni-sada-aarch64-technologie-neon/
  6. Specifické vlastnosti procesorů AArch64: základní instrukce
    https://www.root.cz/clanky/specificke-vlastnosti-procesoru-aarch64-zakladni-instrukce/
  7. Specifické vlastnosti procesorů AArch64: podmíněné a nepodmíněné skoky, adresování dat
    https://www.root.cz/clanky/specificke-vlastnosti-procesoru-aarch64-podminene-a-nepodminene-skoky-adresovani-dat/

20. Odkazy na Internetu

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

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.