Obsah
1. Doplnění k předchozímu článku: absence stavového registru
2. Instrukce pro čtení stavů čítačů, časovačů a hodin reálného času
4. Implementace syscall a podpora pro ladění kódu
5. „M“ – rozšíření instrukční sady o násobení a dělení
8. Operace s hodnotami s plovoucí řádovou čárkou
9. Nové registry použité v matematickém koprocesoru
10. Instrukce pro zpracování hodnot s plovoucí řádovou čárkou
1. Doplnění k předchozímu článku: absence stavového registru
„This is an example of what is the most common misapprehension that I encounter, i.e., analyzing implementations while THINKing of really simple, non-pipelined designs (like the early 8-bit CPUs). Many features that work fine in such designs are famous for causing great pain in more aggressive designs; current CPUs do *not* work that way.“
John R. Mashey
Před popisem nových instrukcí, které je možné nalézt jak v základní instrukční sadě RV32I, tak i v různých rozšířeních této instrukční sady, se na chvíli vrátíme k jedné poměrně důležité vlastnosti, kterou procesorová jádra RISC-V zdědila od architektury MIPS a nepřímo i od dnes poněkud neprávem opomíjené architektury AMD Am29000. Všechny tři zmíněné mikroprocesorové architektury totiž nepoužívají stavový registr a tím pádem ani stavové bity. Naproti tomu většina architektur CISC a mnohé další architektury RISC stavový registr (a příznaky Zero, Carry, Overflow popř. i Signum a Parity) používají, a to jak pro provádění některých aritmetických operací (víceslovní aritmetika), tak i pro bitové posuny a zejména pro podmíněné skoky. Pokud je například nutné provést podmíněný skok za předpokladu, že se obsahy dvou registrů r0 a r1 rovnají, povede to k následující sekvenci instrukcí (mnemonické kódy se samozřejmě budou na různých architekturách odlišovat, základní myšlenka však zůstává zachována):
START: cmp r0, r1 ; výpočet rozdílu bez uložení výsledků, pouze nastavení příznaků ; Carry, Overflow, Signum (Negative) a Zero jz EQUALS ; provedení skoku za předpokladu, že výsledek byl nulový ... ... ... EQUALS: ... ; cíl podmíněného skoku
Podobně je možné provést podmíněný skok, pokud je obsah jednoho registru menší či naopak větší než obsah registru druhého:
START: cmp r0, r1 ; výpočet rozdílu bez uložení výsledků, pouze nastavení příznaků jgt GT ; provedení skoku za předpokladu, že r0 > r1 (či naopak, podle použité konvence) jlt LE ; provedení skoku za předpokladu, že r0 < r1 (či naopak, podle použité konvence) EQ: ; zde již víme, že oba registry obsahují stejnou hodnotu ... ... ... GT: .... ; cíl prvního podmíněného skoku ... ... ... LE: .... ; cíl druhého podmíněného skoku
U architektur RISC-V, MIPS a AMD Am29000 se naproti tomu žádný příznakový registr nepoužívá. Namísto toho jsou instrukce podmíněných skoků rozšířeny takovým způsobem, že se před provedením skoku porovnají obsahy dvou registrů a skok se provede na základě výsledku tohoto porovnání. Konkrétně u RISC-V jsou možné následující kombinace:
# | Instrukce | Význam |
---|---|---|
1 | BEQ | porovnání dvou registrů a skok při splnění podmínky „rovno“ |
2 | BNE | porovnání dvou registrů a skok při splnění podmínky „nerovno“ |
3 | BLT | porovnání dvou registrů a skok při splnění podmínky „menší než“ |
4 | BGE | porovnání dvou registrů a skok při splnění podmínky „větší nebo rovno“ |
5 | BLTU | porovnání dvou registrů a skok při splnění podmínky „menší než“ |
6 | BGEU | porovnání dvou registrů a skok při splnění podmínky „větší nebo rovno“ |
Navíc tato architektura obsahuje další dvě instrukce, které nastavují obsah vybraného (cílového) registru na hodnotu 0 či 1 na základě výsledku porovnání dvou zdrojových registrů:
# | Instrukce | Význam |
---|---|---|
1 | SLT | porovnání registrů na operaci < (se znaménkem), výsledek je 0 nebo 1 |
2 | SLTU | porovnání registrů na operaci < (bez znaménka), výsledek je 0 nebo 1 |
K čemu je možné tyto instrukce využít? Dobrým příkladem je implementace víceslovní aritmetiky, u níž se jinak skutečně dá s výhodou použít příznak Carry (minimálně při ruční optimalizaci na úrovni assembleru). Při absenci příznaku přetečení může kód pro přičtení dvojice operandů (každý má dvě slova) vypadat takto:
; operace typu z = x + y add z_low, x_low, y_low ; přičtení spodních slov sltu tmp, z_low, y_low ; tmp je buď 1 nebo 0: ; když z_low < y_low, tmp=1 jinak 0 add z_high, x_high, y_high ; přičtení horních slov (na out-of-order jádře se provádí paralelně) add z_high, z_high, tmp ; přičtení 1 v případě přetečení
Tento kód sice vypadá poměrně komplikovaně (určitě je minimálně delší než pouhé ADD + ADDC či CLC + ADDC + ADDC), ovšem absence příznakových bitů přináší mnohá zjednodušení a zrychlení procesoru:
- Pro klasická in-order jádra je jasné, že každá operace má jen jediný výsledek a tedy případný „RISCový“ bypass je ještě poměrně jednoduchý (není zapotřebí do bypassu přidávat stavový registr a už vůbec ne kontrolovat, jestli má být do bypassu vůbec zahrnut).
- Pro superskalární jádra je rozdíl ještě více evidentní, počet kolizí se zmenší (viz zmíněná dvojice ADD + ADDC, která na sobě závisí právě kvůli nutnosti „probublání“ příznaku přes nejvyšší bit). Navíc musí CPU rozhodnout, zda vůbec může paralelně spustit dvě ALU operace, když může nastat kolize při zápisu do stavových bitů.
- Lze použít jen dvouvstupovou ALU, což přináší (dnes již nepatrné) zjednodušení.
- Pro out-of-order jádra by se v případě použití příznakových bitů muselo provádět jak přejmenování registrů (register renaming), tak i přejmenování příznaků, což dále celé jádro komplikuje.
- Reakce na přerušení je obecně rychlejší, neboť není nutné na začátku a konci přerušení příznaky nikam ukládat, nastavovat a posléze obnovovat.
2. Instrukce pro čtení stavů čítačů, časovačů a hodin reálného času
Po malé odbočce k tématu, jemuž jsme se více věnovali v předchozím článku, se nyní vraťme k popisu těch instrukcí ze sady RV32I, které jsme si doposud podrobněji nepopsali. Následující šestice instrukcí slouží k přečtení čítačů, časovačů a taktéž hodin reálného času:
# | Instrukce | Stručný popis |
---|---|---|
1 | RDCYCLE | do určeného registru vloží spodních 32 bitů hodnoty počtu hodinových cyklů |
2 | RDCYCLEH | do určeného registru vloží horních 32 bitů hodnoty počtu hodinových cyklů |
3 | RDTIME | do určeného registru vloží spodních 32 bitů hodin reálného času |
4 | RDTIMEH | do určeného registru vloží horních 32 bitů hodin reálného času |
5 | RDINSTRET | do určeného registru vloží spodních 32 bitů čítače instrukcí |
6 | RDINSTRETH | do určeného registru vloží horních 32 bitů čítače instrukcí |
Zajímavé je, že tyto instrukce jsou pro implementaci jádra RISC-V vlastně povinné, což vychází z toho, že toto procesorové jádro je mj. určeno i k výzkumu nových způsobů implementace procesorů i pro výzkum možností překladačů. V obou případech je výhodné mít možnost si kdykoli přečíst počet cyklů trvání nějaké sekvence kódu či počet skutečně provedených instrukcí. U hodin reálného času je stanovena minimální přesnost 100 ns (10 MHz), což je důležitá informace i pro úpravu plánovačů operačních systémů apod. Bitová šířka čítačů i hodin reálného času je stanovena na 64 bitů, takže při použití běžných frekvencí vlastně nikdy nedojde k přetečení (žádný problém roku 2038 atd.).
Jak vypadá doporučená sekvence načtení obsahu jednoho 64 bitového čítače (či hodin reálného času) do libovolné dvojice registrů rx a ry?
AGAIN: rdcycleh x3 rdcycle x2 rdcycleh x4 ; pokud x3==x4, nedošlo k předečení rdcycle bne x3, x4, AGAIN ; při x3!=x4 došlo k pretečení, čteme znovu
Podmíněný skok v předchozím kódu zajišťuje správnou funkci (a malé zdržení) v tom nepravděpodobném okamžiku, kdy hodnota čítače přejde z 0×???????x_ffffffff na 0×???????(x+1)_00000000. Při použití 64bitové instrukční sady RV64I je situace ještě jednodušší, neboť se namísto šesti instrukcí použije pouze trojice instrukcí, z nichž každá načte celou 64bitovou hodnotu čítače či hodin, takže se zde obejdeme bez skoku.
3. Instrukce FENCE a FENCE.I
V případě, že na jednom čipu bude implementováno větší množství jader RISC-V, může při jejich souběžné práci docházet ke kolizím při přístupu do paměti či k periferním zařízením. Základní instrukční sada sice neobsahuje žádné instrukce určené pro synchronizaci ani pro atomické operace typu read-modify-write, ovšem základní mechanismus kooperace mezi vlákny je zde předepsán. Slouží k tomu instrukce FENCE a FENCE.I:
# | Instrukce | Stručný popis |
---|---|---|
1 | FENCE | garance pořadí operací přístupu do paměti či k periferním zařízením |
2 | FENCE.I | synchronizace instrukcí zápisu do paměti či I/O |
Instrukci FENCE je možné použít v případě, že je zapotřebí garantovat pořadí, ve kterém proběhnou specifikované operace s pamětí (čtení či zápis) či s periferními zařízeními (taktéž čtení či zápis). Pokud je instrukce FENCE použita, musí procesor zajistit, aby ostatní vlákna nejdříve „uviděla“ provedení instrukcí před FENCE a teprve poté provedení instrukcí za FENCE. Ve dvou bitových polích, které jsou součástí instrukčního slova, lze specifikovat, o které operace se má jednat:
- Čtení z RAM
- Zápis do RAM
- Čtení z I/O prostoru
- Zápis do I/O prostoru
Naproti tomu instrukce FENCE.I slouží k vynucení provedení operace zápisu do RAM či do I/O (periferního zařízení). Pokud se totiž provádí více zápisů, nemusí být jejich účinek hned viditelný, a to ani ve stejném vlákně. FENCE.I je tedy podobná souborové operaci flush() a skutečně se může jako flush cache implementovat (nebo je možné použít bypass v rámci jednoho vlákna atd.).
4. Implementace syscall a podpora pro ladění kódu
Ze základních čtyřiceti sedmi instrukcí ze sady RV32I nám zbývá si popsat jen dvě instrukce, které se jmenují SCALL a SBREAK. První z těchto instrukcí slouží k zavolání vybrané funkce operačního systému, přičemž způsob předávání parametrů a vracení hodnot či chybových kódů z jádra operačního systému není v dokumentaci mikroprocesorů RISC-V specifikováno – vše záleží na ABI operačního systému (s velkou pravděpodobností se budou parametry předávat přes pracovní registry, ostatně stejným způsobem, jako je tomu v Linuxu u x86, x86_64 i u ARMu). Poslední instrukce se jmenuje SBREAK. Tato instrukce slouží k zastavení běhu programu a vrácení řízení (daného vlákna) do debuggeru; jedná se tedy o instrukci určenou především pro ladění (podobně jako například BRK v osmibitových mikroprocesorech MOS 6502):
# | Instrukce | Stručný popis |
---|---|---|
1 | SCALL | zavolání nějaké funkce jádra operačního systému |
2 | SBREAK | přerušení běhu vlákna a vrácení řízení debuggeru |
5. „M“ – rozšíření instrukční sady o násobení a dělení
V mnoha typech zařízení je možné využít mikroprocesor obsahující pouze aritmeticko-logickou jednotku určenou pro základní práci s 32bitovými či 64bitovými operandy (opět si na tomto místě dovolím připomenout koncept Minion Cores, tj. jednoduchých 32bitových modulů RISC-V určených pro programové ovládání GPIO). Tato aritmeticko-logická jednotka dokonce ani nemusí obsahovat násobičku a děličku, což jsou relativně složité obvody, které navíc dobře nezapadají do konceptu jednoduché a rychlé architektury RISC. Ovšem pro některé účely, například pro obecně využitelné servery či desktopy, by absence hardwarové násobičky a děličky mohla znamenat poměrně razantní snížení výpočetního výkonu u těchto operací, takže tvůrci RISC-V navrhli i rozšíření základní instrukční sady nazvané jednoduše „M“ (od slova Multiply). Pokud procesor toto rozšíření podporuje, budou mít programátoři k dispozici několik dalších instrukcí, které pro zdrojové operandy i výsledek používají běžné pracovní registry (tj. ne nějaká speciální paměťová místa, jak je tomu například u klasického MIPS):
6. Násobička
Násobička provádí následující instrukce:
# | Instrukce | Stručný popis |
---|---|---|
1 | MUL | násobení 32×32 bitů, spodních 32bitů se uloží do dest |
2 | MULH | násobení 32×32 bitů signed × signed, horních 32bitů se uloží do dest |
3 | MULHU | násobení 32×32 bitů unsigned × unsigned, horních 32bitů se uloží do dest |
4 | MULHSU | násobení 32×32 bitů signed × unsigned, horních 32bitů se uloží do dest |
Povšimněte si, že neexistuje žádná instrukce, která by přímo vrátila 64bitový výsledek. Pokud je zapotřebí takovou operaci použít (většinou to potřeba není), doporučuje se násobení provádět v pořadí MULH+MUL, MULHU+MUL či MULHSU+MUL. V takovém případě by mikroarchitektura mohla provést jen jedinou operaci násobení, ale ve skutečnosti to není ve specifikaci vyžadováno a ani zaručeno.
7. Dělička
Dělička provádí následující instrukce:
# | Instrukce | Stručný popis |
---|---|---|
1 | DIV | dělení 32/32bitů, výsledek má taktéž 32bitů |
2 | DIVU | dtto, ovšem dělení bez znaménka |
3 | REM | zbytek po dělení 32/32bitů, výsledek je 32bitový |
4 | REMU | dtto, ovšem pro výpočet zbytku bez znaménka |
V případě, že se má provést jak dělení, tak i výpočet zbytku po dělení, doporučuje se tyto operace provádět v pořadí DIV+REM či DIVU+REMU. Mikroarchitektura by v tomto případě opět mohla provést dělení jen jednou a pouze uložit výsledky do dvou pracovních registrů.
U mnoha mikroprocesorů je možné zachytit případ dělení nulou (známé „Divide by Zero“) či přetečení při dělení (tj. operaci –231/-1 s výsledkem 231, který se do 32bitového slova se znaménkem již nevejde). Tyto operace mohou vést k vyvolání přerušení, ovšem u architektury RISC-V tomu tak není. Zde jsou „jen“ přesně specifikovány výsledky těchto operací s tím, že postačuje pouze použít podmíněný skok pro zjištění, jak operace dopadla (pokud je to ovšem nutné, opět někdy není):
Operace | Dělenec | Dělitel | DIVU | REMU | DIV | REM |
---|---|---|---|---|---|---|
Dělení nulou | x | 0 | 232-1 | x | –1 | x |
Přetečení | –231 | –1 | nenastane | nenastane | –231 | 0 |
8. Operace s hodnotami s plovoucí řádovou čárkou
Další rozšíření původní instrukční sady mikroprocesorových jader RISC-V pochopitelně souvisí s problematikou provádění operací s hodnotami s plovoucí řádovou čárkou. Ve skutečnosti existují dokonce dvě rozšíření původní ISA. První rozšíření se jmenuje „F“, protože specifikuje instrukce s hodnotami typu single/float, tj. s čísly s jednoduchou přesností podle normy IEEE 754–2008 (jedná se o zpřesnění původní slavné normy IEEE 754). Druhé rozšíření se podle očekávání jmenuje „D“, protože předepisuje operace s hodnotami typu double, tj. s čísly s přesností dvojitou. Proč však došlo k rozdělení funkcí matematického koprocesoru na dvě části? Existují totiž aplikace, kde postačuje pracovat s typem single/float, takže by v tomto případě podpora dvojnásobné přesnosti pouze přinášela komplikace v realizaci mikroprocesoru (ostatně i tak jsou obecně operace s plovoucí řádovou čárkou pomalejší než celočíselné operace RISCové aritmeticko-logické jednotky). Dokonce existují i aplikace vyžadující malý a rychlý mikroprocesor s nativní podporou typu half-float, což jsou 16bitová čísla se znaménkem, mantisou i exponentem (zavedeny byly například v Cg).
9. Nové registry použité v matematickém koprocesoru
Pro rozšíření „F“ se používá nová sada pracovních registrů. Tyto registry jsou pojmenovány f0 až f31 a každý z těchto registrů má šířku 32 bitů. Navíc se u většiny operací používá i stavový a řídicí registr nazvaný fcrs. K dispozici jsou pseudoinstrukce FRCSR a FSCSR sloužící pro přenos obsahu stavového a řídicího registru do libovolného pracovního registru celočíselné části mikroprocesoru (tedy samozřejmě kromě nulového registru). Registr fcsr obsahuje následující řídicí a stavové bity:
Index bitu(ů) | Jméno | Význam |
---|---|---|
0 | NX | inexact, nepřesný výsledek |
1 | UF | podtečení |
2 | OF | přetečení |
3 | DZ | dělení nulou |
4 | NV | invalid, neplatná operace |
5–7 | frm | vybraný zaokrouhlovací režim (5 možností) |
Podobně jako tomu bylo u celočíselné děličky, i u FP operací nedochází nikdy k výjimce, a to ani při dělení nulou, ani při jiných operacích (dělení dvou NaN, 0/0 apod.). Je tedy nutné sledovat stavové bity a podle jejich aktuálního nastavení provádět příslušné testy.
10. Instrukce pro zpracování hodnot s plovoucí řádovou čárkou
Jen ve stručnosti si popišme instrukce, které jsou předepsány v rozšíření instrukční sady „F“, tj. instrukce pro zpracování numerických hodnot typu single/float:
# | Instrukce | Význam |
---|---|---|
1 | FLW | načtení FP hodnoty z paměti (adresa rs+offset) |
2 | FSW | uložení FP hodnoty do paměti (adresa rs+offset) |
3 | FADD.S | součet dvou FP hodnot (tříadresový kód) |
4 | FSUB.S | rozdíl dvou FP hodnot |
5 | FMUL.S | součin dvou FP hodnot |
6 | FDIV.S | podíl dvou FP hodnot |
7 | FMIN.S | vrací menší z obou FP hodnot |
8 | FMAX.S | vrací větší z obou FP hodnot |
9 | FSQRT.S | druhá odmocnina (použity jsou jen dva registry) |
10 | FMADD.S | rs1×rs2+rs3 (multiply-add, čtyřadresový kód!) |
11 | FMSUB.S | rs1×rs2-rs3 |
12 | FNMADD.S | -(rs1×rs2+rs3) |
13 | FNMSUB.S | -(rs1×rs2-rs3) |
14 | FCVT.W.S | převod FP na integer |
15 | FCVT.S.W | převod integer na FP |
16 | FCVT.WU.S | převod FP na unsigned integer |
17 | FCVT.S.WU | převod unsigned integer na FP |
18 | FMV.X.S | pouze přesun mezi integer registrem a FP registrem (nikoli konverze) |
19 | FMV.S.X | pouze přesun mezi FP registrem a integer registrem (nikoli konverze) |
20 | FLT.S | porovnání dvou FP hodnot, zápis 0 či 1 do integer registru |
21 | FLE.S | porovnání dvou FP hodnot, zápis 0 či 1 do integer registru |
22 | FEQ.S | porovnání dvou FP hodnot, zápis 0 či 1 do integer registru |
21 | FCLASS | zjistí „třídu“ FP hodnoty a nastaví deset bitů podle následující tabulky |
Výsledek instrukce FCLASS zapsaný do vybraného integer registru:
Index bitu | Význam |
---|---|
0 | záporné nekonečno |
1 | záporné číslo (normalizovaná hodnota) |
2 | záporné číslo (nelze normalizovat) |
3 | záporná nula |
4 | kladná nula |
5 | kladné číslo (nelze normalizovat) |
6 | kladné číslo (normalizovaná hodnota) |
7 | kladné nekonečno |
8 | NaN (signaling) |
9 | NaN (quiet, lze je předat do mnoha instrukcí) |
11. Odkazy na Internetu
- Carry bits, The Architect's Trap
http://yarchive.net/comp/carry_bit.html - Microprocessor Design/ALU Flags
https://en.wikibooks.org/wiki/Microprocessor_Design/ALU_Flags - Flags register in an out-of-order processor
http://cs.stackexchange.com/questions/42095/flags-register-in-an-out-of-order-processor - AMD Am29000
https://en.wikipedia.org/wiki/AMD_Am29000 - Status register
https://en.wikipedia.org/wiki/Status_register - AMD Am29000 microprocessor family
http://www.cpu-world.com/CPUs/29000/ - AMD 29k (Streamlined Instruction Processor) ID Guide
http://www.cpushack.com/Am29k.html - AMD Am29000 (Wikipedia)
http://en.wikipedia.org/wiki/AMD_Am29000 - AMD K5 („K5“ / „5k86“)
http://www.pcguide.com/ref/cpu/fam/g5K5-c.html - Comparing four 32-bit soft processor cores
http://www.eetimes.com/author.asp?section_id=14&doc_id=1286116 - RISC-V Instruction Set
http://riscv.org/download.html#spec_compressed_isa - RISC-V Spike (ISA Simulator)
http://riscv.org/download.html#isa-sim - RISC-V (Wikipedia)
https://en.wikipedia.org/wiki/RISC-V - David Patterson (Wikipedia)
https://en.wikipedia.org/wiki/David_Patterson_(computer_scientist) - OpenRISC (oficiální stránky projektu)
http://openrisc.io/ - OpenRISC architecture
http://openrisc.io/architecture.html - Emulátor OpenRISC CPU v JavaScriptu
http://s-macke.github.io/jor1k/demos/main.html - OpenRISC (Wikipedia)
https://en.wikipedia.org/wiki/OpenRISC - OpenRISC – instrukce
http://sourceware.org/cgen/gen-doc/openrisc-insn.html - OpenRISC – slajdy z přednášky o projektu
https://iis.ee.ethz.ch/~gmichi/asocd/lecturenotes/Lecture6.pdf - Maska mikroprocesoru RISC 1
http://www.cs.berkeley.edu/~pattrsn/Arch/RISC1.jpg - Maska mikroprocesoru RISC 2
http://www.cs.berkeley.edu/~pattrsn/Arch/RISC2.jpg - C.E. Sequin and D.A.Patterson: Design and Implementation of RISC I
http://www.eecs.berkeley.edu/Pubs/TechRpts/1982/CSD-82–106.pdf - Berkeley RISC
http://en.wikipedia.org/wiki/Berkeley_RISC - Great moments in microprocessor history
http://www.ibm.com/developerworks/library/pa-microhist.html - Microprogram-Based Processors
http://research.microsoft.com/en-us/um/people/gbell/Computer_Structures_Principles_and_Examples/csp0167.htm - Great Microprocessors of the Past and Present
http://www.cpushack.com/CPU/cpu1.html - A Brief History of Microprogramming
http://www.cs.clemson.edu/~mark/uprog.html - What is RISC?
http://www-cs-faculty.stanford.edu/~eroberts/courses/soco/projects/2000–01/risc/whatis/ - RISC vs. CISC
http://www-cs-faculty.stanford.edu/~eroberts/courses/soco/projects/2000–01/risc/risccisc/ - RISC and CISC definitions:
http://www.cpushack.com/CPU/cpuAppendA.html - FPGA
https://cs.wikipedia.org/wiki/Programovateln%C3%A9_hradlov%C3%A9_pole - The Evolution of RISC
http://www.ibm.com/developerworks/library/pa-microhist.html#sidebar1 - SPARC Processor Family Photo
http://thenetworkisthecomputer.com/site/?p=243 - SPARC: Decades of Continuous Technical Innovation
http://blogs.oracle.com/ontherecord/entry/sparc_decades_of_continuous_technical - The SPARC processors
http://www.top500.org/2007_overview_recent_supercomputers/sparc_processors - Reduced instruction set computing (Wikipedia)
http://en.wikipedia.org/wiki/Reduced_instruction_set_computer - MIPS architecture (Wikipedia)
http://en.wikipedia.org/wiki/MIPS_architecture - Very long instruction word (Wikipedia)
http://en.wikipedia.org/wiki/Very_long_instruction_word - Classic RISC pipeline (Wikipedia)
http://en.wikipedia.org/wiki/Classic_RISC_pipeline - R2000 Microprocessor (Wikipedia)
http://en.wikipedia.org/wiki/R2000_(microprocessor) - R3000 Microprocessor (Wikipedia)
http://en.wikipedia.org/wiki/R3000 - R4400 Microprocessor (Wikipedia)
http://en.wikipedia.org/wiki/R4400 - R8000 Microprocessor (Wikipedia)
http://en.wikipedia.org/wiki/R8000 - R10000 Microprocessor (Wikipedia)
http://en.wikipedia.org/wiki/R10000 - SPARC (Wikipedia)
http://en.wikipedia.org/wiki/Sparc - CPU design (Wikipedia)
http://en.wikipedia.org/wiki/CPU_design - Control unit (Wikipedia)
http://en.wikipedia.org/wiki/Control_unit