Architektura procesorů rodiny „Intel P6“
Procesory rodiny P6 byly představeny firmou Intel roku 1995. Prvním zástupcem této skupiny byl procesor Pentium Pro. Při vývoji procesorů rodiny P6 bylo jedním z prvořadých cílů významně překročit výkon procesoru Pentium s použitím stejné výrobní technologie, a to znamenalo, že zvýšení výkonu bylo možné docílit pouze vylepšením mikroarchitektury.
Procesory rodiny P6 jsou třícestně (three-way) superskalární, zřetězené (pipelined) architektury. Šílený termín „třícestně superskalární“ stručně znamená, že použitím paralelních technik bylo docíleno toho, aby byl procesor schopen dekódovat, připravit a kompletně provést průměrně tři instrukce za jeden hodinový cyklus. Aby bylo dosaženo takové propustnosti, procesory rodiny P6 jsou tvořeny dvanáctistupňovým zřetězením (12-stage superpipeline), které podporuje tzv. out-of-order vykonávání, tedy provádění instrukcí v pořadí, které nemusí nutně odpovídat tomu, jak instrukce do procesoru dorazily. (Integrita dat musí pochopitelně zůstat zachována.)
Obrázek znázorňuje koncepční pohled na toto zřetězení rozdělené do čtyř jednotek:
- Jednotka volání a dekódování instrukcí (Fetch/Decode Unit)
- Jednotka odesílání a vykonávání instrukcí (Dispatch/Execute Unit)
- Jednotka Retire (Retire Unit)
- Banka dekódovaných instrukcí (Instruction Pool či Reorder Buffer)
Nyní se pokusím takříkajíc „po lopatě“ vysvětlit, co jednotlivé chlívky na obrázku znamenají a jak celý procesor zhruba funguje. Důraz budiž kladen zejména na záležitosti týkající se souběžného zpracovávání.
Bus Interface Unit
Instrukce a data jsou do procesoru dodávány prostřednictvím jednotky rozhraní sběrnice (Bus Interface Unit). Tato jednotka zprostředkovává styk procesoru se systémovou sběrnicí. Pro překlenutí rozdílu mezi rychlým procesorem a relativně pomalou sběrnicí používá BIU navíc tzv. L2 cache paměť pro uchování údajů, u kterých je pravděpodobné, že je bude brzy potřebovat.
Procesor používá ještě jednu cache paměť – L1. Ta je již rozdělena na dva kousky. V první části se uchovávají instrukce a ve druhé data.
Fetch/Decode Unit
Jednotka volání a dekódování instrukcí (Fetch/Decode Unit) se stará o předzpracování instrukcí. Tato část procesoru čte z L1 instrukční cache paměti proud instrukcí a dekóduje je na tzv. mikroinstrukce. Mikroinstrukce jsou potom poslány do banky dekódovaných instrukcí (Instruction Pool), kde čekají na zpracování dalšími jednotkami procesoru.
Abychom pochopili rozdíl mezi instrukcí a mikroinstrukcí, můžeme si instrukci na chvíli představit jako kartičku s názvem nějaké operace. Mnoho instrukcí je samo o sobě elementárních a potom odpovídají právě jedné mikroinstrukci. Některé instrukce však pojmenovávají natolik složité operace, že procesor není schopen je provést v jednom jediném kroku. Potom se taková instrukce dekóduje na celou sadu mikroinstukcí, které v souhrnu provádějí kýženou operaci.
Dekodér instrukcí tedy čte postupně jednu „kartičku“ s názvem operace za druhou a podle svých tabulek dává na svůj výstup proud „menších“ kartiček (mikroinstrukcí), které již představují nejjednodušší možné operace procesoru.
Uvnitř jednotky volání a dekódování instrukcí jsou ještě zabudovány různé další složité mechanismy, které se snaží zpracování instrukcí optimalizovat. Asi nejzajímavějším nástrojem je předpovídání větvení programu. Jednotka „se dívá“ hluboko dopředu na instrukce, které následují za právě zpracovávanou, a už dopředu se je snaží dekódovat. Problémem však jsou různé příkazy větvení, které realizují různé skoky do jiných částí programu. Mechanismus předpovídání větvení se snaží uhodnout, kterou cestou se zpracovávání programu bude ubírat, a zrovna tyto instrukce nabídnout dekodéru k předzpracování.
Samotný dekodér se skládá ze tří paralelních částí: dvou dekodérů jednoduchých instrukcí (Simple-instruction Decoders) a jednoho dekodéru složitých instrukcí (Complex Instruction Decoder). Každý dekodér zkonvertuje instrukci architektury Intel na jednu nebo více mikroinstrukcí. V každém taktu procesoru tak může dekodér vygenerovat až šest mikroinstrukcí – jednu každým ze dvou dekodérů jednoduchých instrukcí a až čtyři dekodérem složitých instrukcí.
Instruction Pool
Dekódované mikroinstrukce putují do již zmíněné banky dekódovaných instrukcí (Instruction Pool). Instruction Pool je v podstatě sada čtyřiceti speciálních registrů, přičemž do každého z nich se vejde právě jedna mikroinstrukce.
Dispatch/Execute Unit
Z banky instrukcí jsou jednotlivé mikroinstrukce čteny jednotkou provádění instrukcí (Dispatch/Execute Unit), která je tvořena dvěma celočíselnými jednotkami (Integer Units), dvěma jednotkami pro operace s plovoucí čárkou (Floating-point Units) a jednou jednotkou pro přístup do paměti (Memory Interface Unit) – tím se umožní paralelní provádění až pěti mikroinstrukcí najednou.
Důležitý na vykonávání mikroinstrukcí je fakt, že z banky dekódovaných instrukcí mohou být čteny v jiném pořadí (out-of-order), než v jakém do Poolu přišly. Tím se velice zvyšuje propustnost celého systému, protože se mohou provádět mikroinstrukce podle toho, jaké exekuční jednotky jsou volné, a ne nutně podle pořadí jednotlivých mikroinstrukcí. Pochopitelně se tím ale zvyšuje složitost systému, protože si Dispatch/Execute Unit musí dávat pozor na datové závislosti mezi instrukcemi.
Retire Unit
Zpracovaná mikroinstrukce se vrací zpátky do banky instrukcí, kde čeká na své definitivní dokončení – promítnutí změn do zbytku systému. Jednotka Retire lineárně prohledává Instruction Pool na vykonané instrukce, které už nemají žádné závislosti na jiných instrukcích či neurčených větveních. Jakmile takovou najde, odevzdá výsledky k promítnutí do stavu systému: uloží je do paměti či do univerzálních registrů procesoru (EAX, EBX, …). Výsledky se realizují v originálním pořadí (tedy v takovém, v jakém instrukce přicházely do procesoru). Takto zpracované instrukce se nakonec z banky dekódovaných instrukcí odstraní.
Architektura procesorů Intel je pochopitelně o mnoho složitější, než jsem tady popsal. Z našeho pohledu si však všimneme zejména paralelnosti zpracování, která se v procesoru objevuje na každém kroku. Co všechno se provede v jednom taktu procesorových hodin?
- Načtou se až tři nové instrukce z vyrovnávací paměti (L1 cache), dekódují se na mikroinstrukce a uloží se do banky dekódovaných instrukcí (Instruction Pool).
- Spustí se provádění až pěti mikroinstrukcí uložených v Instruction Poolu z minulých dekódování.
- Instrukce zpracované v předchozím taktu se promítnou do univerzálních registrů a stavu systému.
Přitom nestačí jen takové hrubé zřetězení, jak jsem ho v tomto článku popsal. Jednotlivé jednotky se uvnitř dále dělí na menší paralelní části, které jsou často navíc v procesoru násobně. Viz například dekodér, který je v procesoru ztrojený nebo vykonávací jednotka, která se skládá z pěti částí schopných pracovat souběžně.
Doufám, že tento článek dal čtenáři alespoň zevrubný pohled do světa nejdůležitějších částí počítačů – procesorů. Příště u hardwaru ještě zůstaneme. Budeme se bavit o architekturách paralelních strojů.
Můj dík za spoluúčast při tvorbě obsahu tohoto článku patří Jiřímu Lenertovi a Janu Bošotovi.