Hlavní navigace

Architektura mikroprocesorů OpenRISC

1. 11. 2018
Doba čtení: 25 minut

Sdílet

 Autor: Derrick Coetzee, podle licence: Public Domain CC0
V dnešním článku si podrobněji popíšeme programátorský model mikroprocesorů s architekturou OpenRISC. Jedná se o specifikaci procesorů s modulární a modifikovatelnou instrukční sadou, jejichž design je dostupný pod licencí LGPL.

Obsah

1. Architektura mikroprocesorů OpenRISC

2. Programátorský model OpenRISC

3. Funkce registrů při volání funkcí (dohodnutá konvence)

4. Registry se speciálními funkcemi

5. Nejdůležitější registry se speciální funkcí

6. Zjištění verze CPU, jeho architektury a dostupných jednotek

7. Přečtení konkrétních informací o možnostech nabízených mikroprocesorem

8. Příznakové bity

9. Instrukční sady použité v projektu OpenRISC

10. Formát slov v instrukční sadě ORBIS32

11. Instrukce v instrukční sadě ORBIS32

12. Aritmetické a logické instrukce

13. Příznakový bit F a instrukce pro práci s ním

14. Instrukce podmíněných i nepodmíněných skoků

15. Jednotka MAC

16. Branch delay sloty

17. Seznam všech instrukcí v sadě ORBIS32

18. Obsah pokračování článku

19. Odkazy na Internetu

1. Architektura mikroprocesorů OpenRISC

S projektem OpenRISC jsme se velmi stručně na stránkách Rootu již seznámili v článku Otevřené RISCové architektury OpenRISC a RISC-V . Od doby vydání tohoto článku již uplynula poměrně dlouhá doba (alespoň na poměry panující v IT) a navíc byl projekt OpenRISC prozatím popsán pouze povrchně, protože jsme se zaměřili spíše na „konkurenční“ jádra RISC V. Ovšem i OpenRISC se mezitím dále vyvinul a vznikly i jeho zajímavé alternativy, například šestnáctibitový procesor, který je na myšlenkách OpenRISCu založen. Proto se s touto zajímavou a potenciálně užitečnou mikroprocesorovou platformou znovu seznámíme v dnešním článku, který bude zaměřen především na popis architektury procesorů OpenRISC z programátorského hlediska. V navazujícím článku si navíc popíšeme referenční platformu nazvanou ORPSoC neboli OpenRISC Reference Platform System on Chip.

Připomeňme si, o jaký projekt se v případě OpenRISCu jedná. V rámci tohoto projektu byl především zveřejněn design procesoru, který byl uvolněn pod licencí LGPL. Případný firmware je pak k dispozici pod licencí GPL. To je – alespoň podle mého názoru – docela dobrý kompromis mezi zajištěním otevřenosti celé platformy a současně to umožňuje komerční využití, i když ne v takové míře, jako je tomu u RISC-V. Projekt počítá jak s možností implementace „pouhých“ 32bitových čipů, tak i čipů s 64bitovými sběrnicemi a aritmeticko-logickou jednotkou. Navíc je možné si při implementaci zvolit, zda bude mikroprocesor obsahovat i matematický koprocesor (pro hodnoty s plovoucí řádovou čárkou typu float/single, double či obojí), popř. je možné na čip s mikroprocesorem přidat i koprocesor určený pro zpracování hodnot uložených v krátkých vektorech (toto rozšíření se nazývá SIMD či DSP, protože v něm jsou obsaženy i některé typické instrukce používané při zpracování signálů).

Poznámka: specifikace umožňuje, aby konkrétní CPU byly buď typu little endian či big endian. Tento rozdíl se dotýká především způsobu použití pracovních registrů při volání funkcí a předávání návratových hodnot z volaných funkcí. Podrobnosti si řekneme níže, bližší informace o little a big endian naleznete například na Wikipedii.

2. Programátorský model OpenRISC

Popišme si nyní programátorský model mikroprocesorů OpenRISC. Podobně, jako tomu bylo u známé a stále používané architektury MIPS, i zde mají programátoři k dispozici šestnáct či (mnohem častěji) 32 pracovních registrů, každý o šířce 32 bitů popř. 64 bitů. Registry jsou pojmenované r0r15 (r31), což jsou opět jména v oblasti RISCů obvyklá. V následující tabulce jsou vypsány funkce jednotlivých pracovních registrů, ovšem s tou poznámkou, že tyto funkce jsou založeny pouze na konvenci (kromě prvního registru, který je při správné inicializaci CPU konstantně nulový, opět viz popis architektury MIPS):

Registr Alternativní jméno Význam
r0 Zero tento registr obsahuje konstantně nulu, díky němu lze do značné míry zjednodušit instrukční sadu
r1 SP stack pointer, používá se jako ukazatel na vrchol zásobníku
r2 FP frame pointer, používá se jako ukazatel na zásobníkový rámec
r9 LR link register, používá se pro uchování návratové adresy volající subrutiny
r11 RV return register, používá se pro předání návratové hodnoty do volající subrutiny
r12 RVH return register, používá se pro předání návratové hodnoty do volající subrutiny
Poznámka: zajímavé je, že registr r0 sice skutečně prakticky za všech okolností obsahuje nulu, ovšem toto nastavení (vynulování) musí být provedeno při inicializaci CPU. Obecně se tedy nemusí jednat o konstantu, která je v mikroprocesoru „zadrátována“.

Registry r11+r12 resp. RV+RVH se používají pro předání návratové hodnoty do volané funkce. Dvojice registrů je vyžadována například na 32bitových CPU v případě, že se má vracet typ long. Ovšem pozor – to, který z těchto registrů bude obsahovat vyšších 32 bitů a který nižších 32 bitů, záleží na tom, zda se jedná o CPU s pořadím bajtů little endian nebo big endian (alternativní jména těchto dvou registrů tedy mohou být poněkud matoucí).

Poznámka: šířka všech zmíněných registrů je buď 32 bitů nebo plných 64 bitů, v závislosti na implementaci konkrétního jádra. Prozatím pro jednoduchost předpokládejme, že se používá 32bitová architektura.

3. Funkce registrů při volání funkcí (dohodnutá konvence)

Kromě šesti pracovních registrů, o nichž jsme se explicitně zmínili v předchozí kapitole, existuje dohodnutá (resp. přesněji řečeno specifikovaná) konvence pro funkci ostatních dvaceti šesti pracovních registrů. Tyto registry se obecně dělí do tří skupin:

  1. Registry použité pro předání parametrů volané funkci.
  2. Registry, u nichž je zaručeno, že se po návratu z volané funkce nezmění jejich obsah.
  3. Registry, které naopak po návratu z volané funkce mohou mít odlišnou hodnotu a volající funkce tedy musí s tímto chováním počítat.
Poznámka: na tomto místě je vhodné si uvědomit, že RISCové procesory jsou typicky optimalizovány na operace/instrukce prováděné s pracovními registry, nikoli na operace nad hodnotami uloženými na zásobníkovém rámci nebo na haldě (heapu). Proto je vhodné některé registry „obětovat“ s tím, že mohou být změněny ve volané funkci/funkcích (ostatně 32 registrů by mohlo být dosti velké množství pro většinu běžných úloh). Pokud funkce potřebuje použít větší množství registrů, není samozřejmě problém využít i registry se sudým indexem – pouze je nutné obnovit jejich původní obsah před návratem z funkce.
Registry Zachován při volání Funkce
r3, r4, r5, r6, r7, r8 ne parametry předávané volané funkci
r10, r14, r16, r18, r20, r22, r24, r26, r28, r30 ano registry, které se po návratu z funkce nezmění
r13, r15, r17, r19, r21, r23, r25, r27, r29, r31 ne pracovní registry, mohou se změnit

Tato konvence by měla být dodržována všemi dostupnými překladači.

4. Registry se speciálními funkcemi

Mimo obecných pracovních registrů, o nichž jsme se zmínili v předchozích dvou kapitolách, je ve specifikaci popsáno i několik desítek registrů se speciálními funkcemi. Tyto registry se souhrnně označují zkratkou SPR, která vznikla z jejich pojmenování special-purpose registers. Ne všechny dále popsané registry ovšem musí být implementovány všemi procesorovými jádry. Pokud některý registr není implementován (například se jedná o čip bez MMU, což je v případě MCU nebo DSP legitimní), musí být zaručeno, že čtení takového registru vrátí nulu a zápis do něj nebude mít žádný viditelný efekt (nejedná se ovšem ani o chybu ani o výjimku). Registry se speciálními funkcemi jsou rozděleny do skupin (groups), přičemž implementována by měla být alespoň nultá skupina, přesněji řečeno vybrané registry z této skupiny. To, které skupiny registrů jsou skutečně k dispozici, je určeno bitovým polem uloženým do speciálního registru nazvaného UPR:

Skupina Význam
0 stavové a řídicí registry
1 řízení MMU (memory management unit) pro data
2 řízení MMU (memory management unit) pro instrukce
3 vyrovnávací paměť pro data (stav a řízení)
4 vyrovnávací paměť pro instrukce (stav a řízení)
5 jednotka MAC popsaná dále
6 jednotka použitá pro ladění (debug)
7 čítače použité při měření výkonu, doby trvání instrukcí atd.
8 power management
9 řadič přerušení (PIC – Programmable Interrupt Controller)
10 časovače
11 registry používané matematickým koprocesorem
12–23 rezervováno, prozatím nepřiřazeno žádné funkci
24–31 skupiny registrů, které lze využít dalšími moduly na čipu (SoC apod.)

Pro práci s těmito speciálními registry se používají dvě strojové instrukce:

# Instrukce Význam
1 l.mtspr zápis hodnoty z pracovního registru do registru se speciální funkcí
2 l.mfspr přečtení hodnoty z registru speciální funkcí a zápis této hodnoty do pracovního registru
Poznámka: u obou zmíněných instrukcí je zajímavé, že index registru se speciální funkcí je určen bitovou operací OR mezi konstantou (součást instrukčního slova) a obsahem zvoleného pracovního registru. Můžeme zde využít faktu, že pracovní registr r0 vrací při čtení vždy nulu a tudíž se při jeho použití vlastně využije přímo zapsaná šestnáctibitová konstanta.

5. Nejdůležitější registry se speciální funkcí

Index každého registru se speciální funkcí (SPR) je složen ze dvou částí. V bitech 11 až 15 je uloženo číslo skupiny (tj. hodnota 0..31) a v bitech 0 až 10 pak číslo registru v rámci skupiny. To mj. znamená, že v každé skupině může být definováno až 2048 registrů. Celkem je teoreticky možné použít 65536 registrů se speciální funkcí, ovšem této hodnoty samozřejmě prakticky nikdy nedosáhneme. V následující tabulce jsou popsány ty SPR registry, s nimiž se setká běžný programátor (pravda: používající assembler a OpenRISC – takže úplně běžný programátor to není). Vynechám asi sto registrů určených pro konfiguraci MMU, ladění, čítačů atd. I tyto registry jsou samozřejmě důležité a užitečné, ovšem ne při psaní aplikací běžících v uživatelském prostoru:

Skupina Registr Stručný popis
0 0 VR obsahuje verzi (model) procesoru + číslo revize, používat by se měl VR2 a AVR
0 1 UPR bitové pole popisující existující jednotky čipu
0 1 CPUCFGR konfigurace CPU
0 9 VR2 novější registr s verzí, nahrazuje funkci registru VR
0 10 AVR verze architektury čipu, nahrazuje funkci registru VR
0 12 AECR řízení obsluhy výjimek při aritmetických operacích
0 13 AESR stav výjimek aritmetických operací
0 16 NPC programový čítač (další hodnota PC)
0 17 SR supervisor registr + příznaky ALU
0 18 PPC programový čítač (předchozí hodnota PC)
0 20 FPCSR řízení matematického koprocesoru, stav matematického koprocesoru
       
5 1 MACLO použito jednotkou pro MAC, viz další text s popisem MACu
5 2 MACHI použito jednotkou pro MAC, viz další text s popisem MACu
Poznámka: povšimněte si především registru pojmenovaného UPR (Unit Present Register), o jehož funkci jsme se zmínili v předchozí kapitole. Jednotlivé bity tohoto registru určují, které skupiny registrů jsou k dispozici:
Bit Význam
0 UPR je/není k dispozici
1 DCP – datová cache
2 ICP – instrukční cache
3 DPM – MMU pro data
4 IPM – MMU pro instrukce
5 MP – jednotka MAC
6 DUP – jednotka pro ladění
7 PCUP – jednotka s čítači
8 PICP – řadič přerušení PIC
9 PMP – jednotka pro řízení spotřeby
10 TTP – přesné čítače
11–23 rezervováno
23–31 CUP – custom unit/pro dále nespecifikované jednotky

Hned nultý bit určuje, zda je vůbec UPR k dispozici. Připomeňme si, že při čtení jakéhokoli neexistujícího registru by se měla vrátit nula, takže i tento bit by byl nulový, čímž je potvrzeno, že GPR skutečně neexistuje.

6. Zjištění verze CPU, jeho architektury a dostupných jednotek

Vzhledem k tomu, že OpenRISC je navržen takovým způsobem, aby byl velmi flexibilní a rozšiřitelný, znamená to, že je nutné nějakým způsobem programátorům sdělit všechny důležité instrukce o konkrétním čipu, na nichž jejich program v daném okamžiku běží (tyto informace bude potřebovat loader jádra, samotné jádro a popř. obdoba BIOSu). K tomuto účelu původně sloužil registr nazvaný VR (Version Register), ovšem podle novější specifikace by se namísto tohoto registru měla použít dvojice registrů VR2 společně s registrem AVR. Oba zmíněné registry VR2+AVR jsou dostupné v režimu „supervisor“, tj. zejména pro loader jádra a taktéž pro samotné jádro (popř. i pro již zmíněnou obdobu BIOSu, pokud systém BIOS vyžaduje).

Obsah registru VR2:

Bity Označení Význam
31–24 CPUID unikátní číslo specifikující konkrétní čip
23–0 VER postupně se zvyšující číslo verze čipu definovaného přes CPUID
Poznámka: označením CPUID je zde skutečně myšleno osm bitů, které by mělo jednoznačně identifikovat konkrétní čip popř. jeho dodavatele. Na platformě x86 je ovšem stejným názvem CPUID označena strojová instrukce (s velmi podobným významem). Dolních 24 bitů obsahuje verzi/revizi CPU, což je více než dostačující rozsah.

Obsah registru AVR:

Bity Označení Význam
31–24 MAJ verze architektury (majoritní číslo před tečkou)
23–16 MIN verze architektury (minoritní číslo za tečkou)
15–8 REV revize (číslo za druhou tečkou)
7–0 × rezervováno

Obsah tohoto registru by měl co nejpřesněji určit, které instrukce jsou implementovány a jaké je jejich přesné chování. Ovšem aby program nemusel používat složité tabulky, může namísto toho využít registr CPUCFGR popsaný v navazující kapitole.

7. Přečtení konkrétních informací o možnostech nabízených mikroprocesorem

Informace o konkrétních možnostech CPU, na kterém právě běží nějaký program, se zjistí přečtením registru nazvaného jednoduše CPUCFGR. V tomto 32bitovém registru je prozatím definováno celkem 15 bitů s následujícím významem:

Bity Označení Význam
0..3 NSGF počet tzv. stínových registrů GPR
4 CGF velikost skupiny zákaznických GPR (méně nebo více než 32)
5 OB32S podpora instrukční sady ORBIS32 (tu si popíšeme dnes)
6 OB64S podpora instrukční sady ORBIS64
7 OF32S podpora instrukční sady ORFPX32
8 OF64S podpora instrukční sady ORFPX64
9 OV64S podpora instrukční sady ORVDX64
10 ND indikace, zda se při skocích používá branch delay slot či nikoli
11 AVRP existence registru AVR popsaného výše
12 EVBARP existence registru Exception Vector Base Address
13 ISRP existence registrů implementačně závislých na daném CPU
14 AECSRP existence registru Arithmetic Exception Control
15..31 × rezervováno

8. Příznakové bity

V kontextu programátorského modelu je důležitý především registr nazvaný SR (supervision register) patřící do nulté skupiny a mající index 17. Tento registr obsahuje mimo jiné i tyto tři jednobitové příznaky:

# Zkratka Příznak Význam
1 CY carry příznak přenosu při aritmetických operacích
2 OV overflow příznak přetečení při aritmetických operacích (typ signed)
3 F flag/branch příznak použitý pro implementaci podmíněných skoků

Zajímavé je, že pro podmíněné skoky lze přímo využít jen příznak flag resp. branch. Ten je nastavován některou instrukcí pro porovnání dvou registrů, takže podmíněný skok je v praxi implementován vždy dvěma instrukcemi. Záleží hlavně na překladači, jak instrukce přeskládá, aby instrukce podmíněného skoku nemusela čekat na výsledek porovnání (připomeňme si, že dnešní čipy mají většinou pipeline se čtyřmi nebo s pěti řezy).

9. Instrukční sady použité v projektu OpenRISC

Vzhledem k tomu, že se předpokládá použití mikroprocesorových jader s architekturou OpenRISC v různých zařízeních, od jednodušších řídicích systémů (mikrořadiče – MCU) přes zpracování signálů (DSP) až například po servery, je instrukční sada OpenRISCu navržena modulárně. V současnosti existuje pět základních „sad“ instrukcí s předpokladem, že další sady bude možné navrhnout a implementovat v budoucnosti. Jediné, s čím se v architektuře OpenRISC přímo nepočítá (alespoň prozatím), je podpora instrukcí proměnné délky, tj. obdoby sad Thumb známých z konkurenční architektury ARM či podobné sady, kterou známe z RISC-V. V následující tabulce je vypsáno všech pět prozatím oficiálně popsaných sad instrukcí architektury OpenRISC:

# Zkratka Celé jméno Stručný popis
1 ORBIS32 OpenRISC Basic Instruction Set zpracování 32bitových operandů, skoky, podmínky, bitové operace
2 ORBIS64 OpenRISC Basic Instruction Set rozšíření na 64bitové operandy
3 ORFPX32 OpenRISC Floating Point eXtension operace s numerickými hodnotami typu float/single (jednoduchá přesnost)
4 ORFPX64 OpenRISC Floating Point eXtension operace s numerickými hodnotami typu double (dvojitá přesnost)
5 ORVDX64 OpenRISC Vector/DSP eXtension zpracování hodnot uložených v 64bitových vektorech

Pro vytvoření reálně pracujícího mikroprocesoru postačuje implementovat pouze první sadu, tj. ORBIS32, samozřejmě s tím omezením, že zpracování 64bitových celých čísel či reálných čísel typu single a double bude prováděno softwarově (za pomoci subrutin). Základními vlastnostmi této instrukční sady se budeme zabývat v navazující kapitole.

10. Formát slov v instrukční sadě ORBIS32

Základní instrukční sada ORBIS32 se v několika ohledech podobá například instrukční sadě mikroprocesorů MIPS. I zde totiž najdeme instrukce s konstantní šířkou třiceti dvou bitů, které jsou v operační paměti vždy zarovnány na adresu dělitelnou čtyřmi. Díky tomu se u skoků nemusí specifikovat nejnižší dva bity adresy či offsetu, neboť tyto bity jsou vždy nulové. Tak, jako je tomu u MIPS, i zde mají instrukční slova tři formáty. První formát se označuje písmenem R a používá se pro většinu aritmetických, logických a porovnávacích operací prováděných se dvěma zdrojovými registry a jedním registrem cílovým. Další formát se jmenuje I a používá se pro instrukce, v nichž se pracuje se dvěma registry (zdrojový+cílový) a šestnáctibitovou konstantou. Třetí formát se jmenuje J a používá se u skoků, neboť součástí instrukčního slova je mj. i 26bitová konstanta (to postačuje, neboť nemusíme specifikovat spodní dva bity).

Formát R:

  +-----+------+--------+--------+--------+------------------+
  |31 30|29  26| 25  21 | 20  16 | 15  11 | 10             0 |
  +-----+------+--------+--------+--------+------------------+
  |třída|opcode| rD (5) | rA (5) | rB (5) | druhá část opcode|
  +-----+------+--------+--------+--------+------------------+
Můžeme vidět, že tento formát instrukcí obsahuje v nejvyšších dvou bitech tzv. třídu instrukce. Následuje operační kód uložený ve čtyřech bitech, který může být doplněn bity 0 až 10 s doplňujícím kódem. Důležitá je trojice bitových polí rD, rA a rB, které obsahují indexy pracovních registrů, jenž jsou instrukcí použity. Vidíme, že se zde využívá takzvaný tříadresový kód se dvěma registry zdrojovými a jedním registrem cílovým.

Formát I:

  +-----+------+--------+--------+---------------------------+
  |31 30|29  26| 25  21 | 20  16 | 15                      0 |
  +-----+------+--------+--------+---------------------------+
  |třída|opcode| rD (5) | rA (5) | offset/konstanta (16)     |
  +-----+------+--------+--------+---------------------------+
I v tomto formátu můžeme vidět, že v nejvyšších dvou bitech je uložena třída instrukce a následuje čtyřbitový operační kód. Instrukce formátu I pracují s dvojicí registrů specifikovaných v bitových polích rD a rA. Taktéž se specifikuje šestnáctibitový offset nebo šestnáctibitová konstanta. Podle typu instrukce je tato konstanta chápána bez znaménka (unsigned) nebo se znaménkem (signed) a bývá rozšířena na plných 32 či dokonce 64 bitů (opět v závislosti na tom, o jakou instrukci se jedná).

Formát J:

  +-----+------+---------------------------------------------+
  |31 30|29  26| 25                                        0 |
  +-----+------+---------------------------------------------+
  |třída|opcode| adresa (26)                                 |
  +-----+------+---------------------------------------------+
Tento formát je nejjednodušší, protože obsahuje pouze tři bitová pole. Po již známých bitových polích se specifikací třídy instrukce a operačního kódu následuje adresa, která je zakódována do 26 bitů. Nejnižší dva bity reálné adresy jsou nulové, protože instrukce jsou zarovnány na adresy dělitelné čtyřmi. Samotná adresa je zadána buď absolutně nebo relativně, podle typu instrukce. Relativní adresa se bude vždy vztahovat k aktuální hodnotě registru PC (program counter).

Pro porovnání si ukažme formáty instrukčních slov tak, jak jsou implementovány na klasickém 32bitovém MIPSu:

Formát R:

  +------------+--------+--------+--------+-------+----------+
  | 31  26     | 25  21 | 20  16 | 15  11 | 10  6 | 5      0 |
  +------------+--------+--------+--------+-------+----------+
  | opcode (6) | rs (5) | rt (5) | rd (5) | shift | operace  |
  +------------+--------+--------+--------+-------+----------+

Formát I:

  +------------+-----------------+---------------------------+
  | 31  26     | 25  21 | 20  16 | 15                      0 |
  +------------+-----------------+---------------------------+
  | opcode (6) | rs (5) | rt (5) | offset/konstanta (16)     |
  +------------+-----------------+---------------------------+

Formát J:

  +------------+---------------------------------------------+
  | 31  26     | 25                                        0 |
  +------------+---------------------------------------------+
  | opcode (6) | adresa (26)                                 |
  +------------+---------------------------------------------+

11. Instrukce v instrukční sadě ORBIS32

Vzhledem k tomu, že všechny aritmetické a logické operace pracují s hodnotami uloženými v registrech, je množina instrukcí pro přesuny dat do a z paměti poměrně malá. OpenRISC podporuje instrukce typu load a store, které mohou zpracovávat bajty, 16bitová slova či 32bitová slova. Při načítání bajtů a 16bitových slov se provádí rozšíření na plných 32 bitů se znaménkem (doplnění podle nejvyššího bitu načítané hodnoty) či bez znaménka (doplnění nul). To je v mnoha ohledech praktické, neboť i ty nejmodernější 64bitové mikroprocesory mnohdy tráví většinu času zpracováním řetězců.

# Instrukce Význam
1 l.extbs znaménkové rozšíření bajtu na 32bitové slovo
2 l.extbz bezznaménkové rozšíření bajtu na 32bitové slovo
3 l.exths znaménkové rozšíření 16bitového slova na 32bitové slovo
4 l.exthz bezznaménkové rozšíření 16bitového slova na 32bitové slovo
5 l.extws pouhý přesun dat (32bit) nebo rozšíření 32bit na 64bit
6 l.extwz pouhý přesun dat (32bit) nebo rozšíření 32bit na 64bit
     
7 l.lbs načtení bajtu z operační paměti se znaménkovým rozšířením
8 l.lbz načtení bajtu z operační paměti s bezznaménkovým rozšířením
9 l.lhs načtení 16bitového slova se znaménkovým rozšířením
10 l.lhz načtení 16bitového slova s bezznaménkovým rozšířením
11 l.ld načtení dvouslova (jen 64bitová CPU)
12 l.lwa atomické načtení slova
13 l.lws načtení slova se znaménkovým rozšířením
14 l.lwz načtení slova s bezznaménkovým rozšířením
15 l.movhi načtení 16bitové konstanty a její uložení do horních 16bitů registru
     
16 l.sb uložení bajtu
17 l.sh uložení 16bitového slova
18 l.sw uložení 32bitového slova
19 l.swa atomické uložení 32bitového slova
20 l.sd uložení dvouslova (jen 64bitová CPU)

12. Aritmetické a logické instrukce

Mezi aritmetickými instrukcemi najdeme například sčítání s carry či bez carry, násobení a dělení (se znaménkem či bez znaménka), operace typu „multiply and accumulate“ a „multiply and subtract“ a dokonce instrukce ff1 (find first 1) a fl1 (find last 1). Už na tomto krátkém výčtu je patrné, že instrukční sada je poměrně rozsáhlá a implementace „na křemíku“ patřičně komplikovaná (měřeno plochou čipu).

Základní aritmetické instrukce:

# Instrukce Význam
1 l.add součet registrů
2 l.addc součet (s dalším přičtením přenosu)
3 l.addi přičtení konstanty
4 l.addic přičtení konstanty (s dalším přičtením přenosu)
     
5 l.sub
     
6 l.mul násobení (se znaménkem)
7 l.mulu násobení (bez znaménka)
8 l.muli násobení konstantou (se znaménkem)
9 l.muld násobení s přesunem výsledku do MAC
10 l.muldu násobení s přesunem výsledku do MAC
     
11 l.div celočíselné dělení (se znaménkem)
12 l.divu celočíselné dělení (bez znaménka)
     
13 l.ff1 nalezení první jedničky ve slově
14 l.fl1 nalezení poslední jedničky ve slově

Logické instrukce:

# Instrukce Význam
1 l.and logický součin bit po bitu
2 l.andi logický součin registru s konstantou
3 l.or logický součet bit po bitu
4 l.ori logický součet registru s konstantou
5 l.xor logická nonekvivalence bit po bitu
6 l.xori logická nonekvivalence registru s konstantou

Logické posuny a rotace:

# Instrukce Význam
1 l.ror rotace doprava
2 l.rori rotace doprava o konstantu
     
3 l.sll logický posun doleva
4 l.slli logický posun doleva o konstantu
5 l.srl logický posun doprava
6 l.srli logický posun doprava o konstantu
     
7 l.sra aritmetický posun doprava
8 l.srai aritmetický posun doprava o konstantu

13. Příznakový bit F a instrukce pro práci s ním

Za zmínku stojí taktéž instrukce začínající prefixem sf. Tyto instrukce nastavují příznakový bit branch/F na základě výsledku porovnání dvou registrů či porovnání registru s šestnáctibitovou konstantou. Hodnota příznakového bitu je následně využita v podmíněném skoku. Příkladem může být instrukce sfeq nastavující F←1 jen tehdy, pokud mají oba registry shodnou hodnotu. Nezapomeňme navíc na registr r0 s „trvalou nulou“, díky jehož existenci automaticky získáváme instrukce sfzero. Alternativou k sfeq je instrukce sfeqi pro porovnání registru s konstantou. Existují i další alternativy, kde se namísto „eq“ používá „gt“ (větší než), „ge“ (větší nebo rovno) atd.

# Instrukce Význam
1 l.sfeq nastavení F po porovnání dvou registrů na rovnost
2 l.sfeqi nastavení F po porovnání registru s konstantou na rovnost
3 l.sfges porovnání na relaci „větší nebo rovno“ (se znaménkem)
4 l.sfgesi porovnání na relaci „větší nebo rovno“ (se znaménkem)
5 l.sfgeu porovnání na relaci „větší nebo rovno“ (bez znaménka)
6 l.sfgeui porovnání na relaci „větší nebo rovno“ (bez znaménka)
7 l.sfgts porovnání na relaci „větší než“ (se znaménkem)
8 l.sfgtsi porovnání na relaci „větší než“ (se znaménkem)
9 l.sfgtu porovnání na relaci „větší než“ (bez znaménka)
10 l.sfgtui porovnání na relaci „větší než“ (bez znaménka)
11 l.sfles porovnání na relaci „menší nebo rovno“ (se znaménkem)
12 l.sflesi porovnání na relaci „menší nebo rovno“ (se znaménkem)
13 l.sfleu porovnání na relaci „menší nebo rovno“ (bez znaménka)
14 l.sfleui porovnání na relaci „menší nebo rovno“ (bez znaménka)
15 l.sflts porovnání na relaci „menší než“ (se znaménkem)
16 l.sfltsi porovnání na relaci „menší než“ (se znaménkem)
17 l.sfltu porovnání na relaci „menší než“ (bez znaménka)
18 l.sfltui porovnání na relaci „menší než“ (bez znaménka)
19 l.sfne nastavení F po porovnání dvou registrů na nerovnost
20 l.sfnei nastavení F po porovnání registru s konstantou na nerovnost

14. Instrukce podmíněných i nepodmíněných skoků

Formát skokových instrukcí jsme si již popsali, takže si jen připomeňme, že tyto instrukce používají 26bitovou adresu, která je buď absolutní nebo relativní. Podmíněné skoky využívají příznak F zmíněný ve třinácté kapitole. Mezi skokové instrukce patří zejména:

# Instrukce Význam
1 l.j běžný skok na adresu PC+konstanta
2 l.jal skok na adresu PC+konstanta, návratová adresa se uloží do registru r9
3 l.jr skok na adresu uloženou ve specifikovaném registru
4 l.jalr kombinace jal+jr (skok na adresu v registru, návratová adresa → r9)
5 l.bf skok na PC+konstanta pokud je F nastaven
6 l.bnf skok na PC+konstanta pokud je F vynulován
7 l.rfe návrat z obsluhy výjimky

Poslední instrukcí, o níž se v této kapitole zmíníme, je instrukce l.cmov používající taktéž tříadresový kód (indexy tří registrů). Tato instrukce může v některých případech nahradit podmíněné skoky:

  1. Pokud je F==1, proveď mov D,A
  2. Pokud je F==0, proveď mov D,B

15. Jednotka MAC

Čipy s architekturou OpenRISC mohou obsahovat i jednotku MAC provádějící operace označované stejně: MAC neboli Multiply-Accumulate. Jedná se o základní operace používané při zpracování signálů. Pokud je jednotka MAC skutečně implementována (zjistíme z registru UPR), bude k dispozici těchto šest specializovaných instrukcí:

# Instrukce Význam
1 l.mac operace MAC (se znaménkem)
2 l.macu operace MAC (bez znaménka)
3 l.maci operace MAC s konstantou
3 l.macrc operace MAC s přenosem výsledku do pracovních registrů a vymazáním MAC registrů
5 l.msb operace multiply-subtract (se znaménkem)
6 l.msbu operace multiply-subtract (bez znaménka)

Jednotka MAC používá vlastní dva registry nazvané MACHI a MACLO, do nichž se ukládají mezivýsledky. To je důležité, protože takto může MAC pracovat nezávisle na zbytku CPU a v průběhu výpočtu je tedy možné například vyhodnocovat adresy dalších operandů atd.

16. Branch delay sloty

Pro některé RISCové procesory (jmenujme například asi nejtypičtější MIPS, PA-RISC či SPARC) je poměrně obvyklé taktéž použití technologie takzvaných branch delay slotů, kterou můžeme najít i u zde popisovaných čipů s architekturou OpenRISC. Tyto čipy totiž mohou být navrženy tak, aby obsahovaly jeden delay slot, což znamená, že instrukce uložená ihned za instrukcí podmíněného či nepodmíněného skoku bude vykonána vždy, bez ohledu na výsledek skoku (zda se provede či neprovede). Díky existenci této technologie se může lépe využít instrukční pipeline, neboť pipeline není nutno celou vyprazdňovat po každém skoku, což znamená zdržení až čtyři takty v závislosti na konkrétních možnostech pipeline. Použití branch delay slotů je sice na první pohled poměrně jednoduché (ostatně většinu práce odvede překladač), ovšem může způsobit problémy ve chvíli, kdy dojde k výjimce v instrukci umístěné do delay slotu; navíc ještě záleží na tom, zda výjimka nastane už při dekódování instrukce nebo později. U OpenRISC lze existenci branch delay slotů zjistit přečtením bitu ND z registru CPUCFGR.

ict ve školství 24

17. Seznam všech instrukcí v sadě ORBIS32

V následující tabulce jsou vypsány všechny instrukce, které jsou v současnosti součástí specifikace instrukční sady ORBIS32:

Instrukce Instrukce Instrukce Instrukce Instrukce
l.add l.j l.mtspr l.sfgesi l.sra
l.addc l.jal l.msync l.sfgeu l.srai
l.addi l.jalr l.mtspr l.sfgeui l.srl
l.addic l.jr l.mul l.sfgts l.srli
l.and l.lbs l.muld l.sfgtsi l.sub
l.andi l.lbz l.muldu l.sfgtu l.sw
l.bf l.ld l.muli l.sfgtui l.swa
l.bnf l.lhs l.mulu l.sfles l.sys
l.cmov l.lhz l.nop l.sflesi l.trap
l.csync l.lwa l.or l.sfleu l.xor
l.div l.lws l.ori l.sfleui l.xori
l.divu l.lwz l.psync l.sflts  
l.extbs l.mac l.rfe l.sfltsi  
l.extbz l.maci l.ror l.sfltu  
l.exths l.macrc l.rori l.sfltui  
l.exthz l.macu l.sb l.sfne  
l.extws l.mfspr l.sd l.sfnei  
l.extwz l.movhi l.sfeq l.sh  
l.ff1 l.msb l.sfeqi l.sll  
l.fl1 l.msbu l.sfges l.slli  
Poznámka: ve skutečnosti není nutné, aby byly na CPU implementovány všechny instrukce vypsané v předchozí tabulce. Pouze musí být zaručeno, že jsou implementovány instrukce spadající do první skupiny (group I).

18. Obsah pokračování článku

V navazující části tohoto článku si popíšeme referenční architekturu nazvanou ORPSoC neboli OpenRISC Reference Platform System on Chip. Dále se zmíníme o dalších instrukčních sadách, zejména o instrukcích určených pro matematický koprocesor a pro DSP. Nezapomeneme ani na poměrně zajímavý projekt – menší 16bitový procesor založený na podobných principech jako OpenRISC.

19. Odkazy na Internetu

  1. OpenRISC (oficiální stránky)
    http://openrisc.io/
  2. OpenRISC architecture
    http://openrisc.io/architecture.html
  3. Emulátor OpenRISC CPU v JavaScriptu
    http://s-macke.github.io/jor1k/demos/main.html
  4. OpenRISC (Wikipedia)
    https://en.wikipedia.org/wi­ki/OpenRISC
  5. OpenRISC – instrukce
    http://sourceware.org/cgen/gen-doc/openrisc-insn.html
  6. OpenRISC – slajdy z přednášky
    https://iis.ee.ethz.ch/~gmichi/a­socd/lecturenotes/Lecture6­.pdf
  7. OpenRISC System-on-Chip Design Emulation
    https://arxiv.org/pdf/1602.03095.pdf
  8. Open cores
    https://opencores.org/
  9. Projekt OpenRISC 2000
    https://opencores.org/project/or2k
  10. OpenRISC na GitHubu
    https://github.com/openrisc
  11. OpenRISC 1200
    https://en.wikipedia.org/wi­ki/OpenRISC_1200
  12. OpenRISC 1200 IP Core Specification (Preliminary Draft)
    https://opencores.org/ocsvn/o­penrisc/openrisc/trunk/or1200/doc/o­penrisc1200_spec.pdf
  13. Comparing four 32-bit soft processor cores
    http://www.eetimes.com/au­thor.asp?section_id=14&doc_id=1286116
  14. RISC-V Instruction Set
    http://riscv.org/download­.html#spec_compressed_isa
  15. RISC-V Spike (ISA Simulator)
    http://riscv.org/download.html#isa-sim
  16. RISC-V (Wikipedia)
    https://en.wikipedia.org/wiki/RISC-V
  17. David Patterson (Wikipedia)
    https://en.wikipedia.org/wi­ki/David_Patterson_(compu­ter_scientist)
  18. Maska mikroprocesoru RISC 1
    http://www.cs.berkeley.edu/~pat­trsn/Arch/RISC1.jpg
  19. Maska mikroprocesoru RISC 2
    http://www.cs.berkeley.edu/~pat­trsn/Arch/RISC2.jpg
  20. C.E. Sequin and D.A.Patterson: Design and Implementation of RISC I
    http://www.eecs.berkeley.e­du/Pubs/TechRpts/1982/CSD-82–106.pdf
  21. Berkeley RISC
    http://en.wikipedia.org/wi­ki/Berkeley_RISC
  22. Great moments in microprocessor history
    http://www.ibm.com/develo­perworks/library/pa-microhist.html
  23. Microprogram-Based Processors
    http://research.microsoft.com/en-us/um/people/gbell/Computer_Struc­tures_Principles_and_Exam­ples/csp0167.htm
  24. Great Microprocessors of the Past and Present
    http://www.cpushack.com/CPU/cpu1.html
  25. A Brief History of Microprogramming
    http://www.cs.clemson.edu/~mar­k/uprog.html
  26. What is RISC?
    http://www-cs-faculty.stanford.edu/~ero­berts/courses/soco/projec­ts/2000–01/risc/whatis/
  27. RISC vs. CISC
    http://www-cs-faculty.stanford.edu/~ero­berts/courses/soco/projec­ts/2000–01/risc/risccisc/
  28. RISC and CISC definitions:
    http://www.cpushack.com/CPU/cpu­AppendA.html
  29. FPGA
    https://cs.wikipedia.org/wi­ki/Programovateln%C3%A9_hra­dlov%C3%A9_pole
  30. The Evolution of RISC
    http://www.ibm.com/develo­perworks/library/pa-microhist.html#sidebar1
  31. SPARC Processor Family Photo
    http://thenetworkisthecom­puter.com/site/?p=243
  32. SPARC: Decades of Continuous Technical Innovation
    http://blogs.oracle.com/on­therecord/entry/sparc_deca­des_of_continuous_technical
  33. The SPARC processors
    http://www.top500.org/2007_o­verview_recent_supercompu­ters/sparc_processors
  34. Reduced instruction set computing (Wikipedia)
    http://en.wikipedia.org/wi­ki/Reduced_instruction_set_com­puter
  35. MIPS architecture (Wikipedia)
    http://en.wikipedia.org/wi­ki/MIPS_architecture
  36. Very long instruction word (Wikipedia)
    http://en.wikipedia.org/wi­ki/Very_long_instruction_word
  37. Classic RISC pipeline (Wikipedia)
    http://en.wikipedia.org/wi­ki/Classic_RISC_pipeline
  38. R2000 Microprocessor (Wikipedia)
    http://en.wikipedia.org/wi­ki/R2000_(microprocessor)
  39. R3000 Microprocessor (Wikipedia)
    http://en.wikipedia.org/wiki/R3000
  40. R4400 Microprocessor (Wikipedia)
    http://en.wikipedia.org/wiki/R4400
  41. R8000 Microprocessor (Wikipedia)
    http://en.wikipedia.org/wiki/R8000
  42. R10000 Microprocessor (Wikipedia)
    http://en.wikipedia.org/wiki/R10000
  43. SPARC (Wikipedia)
    http://en.wikipedia.org/wiki/Sparc
  44. CPU design (Wikipedia)
    http://en.wikipedia.org/wi­ki/CPU_design
  45. Control unit (Wikipedia)
    http://en.wikipedia.org/wi­ki/Control_unit
  46. CPUID na x86–64
    http://www.felixcloutier.com/x86/CPU­ID.html
  47. Endianness
    https://en.wikipedia.org/wi­ki/Endianness
  48. Otevřené RISCové architektury OpenRISC a RISC-V
    https://www.root.cz/clanky/otevrene-riscove-architektury-openrisc-a-risc-v/
  49. Instrukční sada procesorových jader s otevřenou architekturou RISC-V
    https://www.root.cz/clanky/instrukcni-sada-procesorovych-jader-s-otevrenou-architekturou-risc-v/
  50. Rozšíření instrukční sady procesorových jader s otevřenou architekturou RISC-V
    https://www.root.cz/clanky/rozsireni-instrukcni-sady-procesorovych-jader-s-otevrenou-architekturou-risc-v/
  51. Instrukční sady procesorových jader s otevřenou architekturou RISC-V (dokončení)
    https://www.root.cz/clanky/instrukcni-sady-procesorovych-jader-s-otevrenou-architekturou-risc-v-dokonceni/
  52. RISCové mikroprocesory s komprimovanými instrukčními sadami
    https://www.root.cz/clanky/riscove-mikroprocesory-s-komprimovanymi-instrukcnimi-sadami/
  53. RISCové mikroprocesory s komprimovanými instrukčními sadami (2)
    https://www.root.cz/clanky/riscove-mikroprocesory-s-komprimovanymi-instrukcnimi-sadami-2/

Autor článku

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