Co je mikroarchitektura
V předchozích dvou dílech jsme probrali návrh ISA, architektury instrukční sady, definující, jak se CPU jeví z pohledu programátora. Nyní se budeme zabývat mikroarchitekturou procesoru, tedy konkrétní implementací ISA v hardwaru. Zdrojové kódy ve VHDL pro celý počítač MB50 jsou v jednom adresáři na GitHubu. Soubory, které jsou součástí implementace CPU, mají jména ve tvaru mb5016_*.vhd
.
Procesor je zapojen do zbytku počítače pomocí signálů. Pokud by existoval jako samostatný integrovaný obvod, tyto signály by byly připojeny na vývody (piny) jeho pouzdra.
Význam jednotlivých signálů:
Clk
je vstup hodinového signálu o frekvenci 50 MHzDataBusRd, DataBusWr
je 8bitová datová sběrnice. FPGA sice podporuje obousměrné fyzické I/O piny, ale interní signály mohou být pouze jednosměrné. Proto je datová sběrnice rozdělená na vstupní část pro čtení z paměti a výstupní část pro zápis do paměti.Rst
je signál pro reset procesoru.Run
spustí běh procesoru (vykonávání instrukcí) nastavením na logickou 1. Když je hodnota 0, procesor stojí a externí ladicí rozhraní může číst a měnit jeho interní stav, např. hodnoty v registrech.Irq
je pět vstupů přerušení. Aktuálně se používají pouze dva, pro systémové hodiny a klávesnici.RegIdx, RegWr, RegCsr, RegDataWr, RegRd, RegDataRd
používá ladicí rozhraní pro čtení a zápis hodnot v obecných a řídicích registrech.Busy, Halted, Breakpoint
slouží k signalizaci aktuálního stavu procesoru: vykonává instrukci, zastaven výjimkou při zakázaném přerušení, zastaven instrukcíbrk
.AddrBus
je 16bitová adresová sběrnice.Rd
zahajuje čtení z paměti nastavením na logickou 1. NaAddrBus
musí zároveň nastavit adresu, za dva takty se naDataBusRd
objeví bajt přečtený z paměti.Wr
provádí zápis do paměti. Při nastavení na logickou 1 musí zároveň naAddrBus
nastavit adresu a naDataBusWr
zapisovaný bajt.
Registry
Sada 16 obecných 16bitových registrů r0...r15
je implementována VHDL entitou mb5016_registers
v souboru mb5016_registers.vhd. Obsahuje jak paměťové buňky pro zapamatování jednotlivých bitů (celkem 256), tak i multiplexory a demultiplexory, jež podle zadaného čísla registru připojují na čtecí a zápisové signály příslušný registr.
Na implementaci registrů si můžeme demonstrovat typický problém při návrhu digitálních logických obvodů, totiž hledání kompromisu mezi složitostí obvodu a rychlostí zpracování. Při vykonávání instrukce se obvykle musí přečíst jeden (např. v instrukcích MV, INC1
) nebo dva ( EXCH,
ADD
) operandy z registrů, jejich hodnoty poslat na vstupy aritmeticko-logické jednotky (ALU), která spočítá jednu ( MV, ADD
) nebo dvě ( EXCH, MULUU
) výstupní hodnoty a nové hodnoty příznakových bitů. Tyto hodnoty se musí zapsat zpět do registrů.
Všechny tyto kroky lze provést v jednom taktu hodin, což ale vyžaduje dva multiplexory pro čtení z registrů, dva demultiplexory pro zápis do registrů, obvod pro zápis příznakových bitů v registru f
a logiku pro řešení konfliktů, pokud je pro zápis zvolen registr f
nebo dva stejné registry.
Alternativně bychom mohli použít pouze jeden multiplexor a jeden demultiplexor. Na vstupy a výstupy ALU bychom museli přidat pomocné registry a výpočet pomocí ALU bychom rozdělili do několika taktů, např. tímto způsobem:
- Načteme první operand z registru do pomocného registru.
- Připojíme pomocný registr a registr obsahující druhý operand na vstupy ALU. Výstupy z ALU zapíšeme do dvou pomocných registrů. Zároveň připojíme registr
f
na příznakový výstup ALU a zapíšeme nové hodnoty příznakových bitů. - Obsah prvního pomocného registru zapíšeme do vybraného registru.
- Obsah druhého pomocného registru zapíšeme do (jiného) vybraného registru.
Tento algoritmus bychom přidali do stavového automatu řídicího vykonávání instrukcí v řadiči procesoru. Možná bychom tím ušetřili několik logických elementů za cenu prodloužení času na vykonání instrukce o tři takty. Velikost úspory závisí na detailech zapojení registrů a řadiče a na optimalizacích prováděných při syntéze obvodu. Obecně se dá předpokládat, že rozdíl mezi oběma variantami by vzrostl, pokud bychom přidávali další registry nebo zvětšovali šířku (počet bitů) jednotlivých registrů.
Protože jsme nenarazili na omezení dané celkovým dostupným počtem logických elementů, je v procesoru MB5016 použita rychlejší jednotaktová implementace registrů. Jestliže instrukce chce zapsat dvě hodnoty do stejného registru, konflikt se vyřeší zápisem pouze první hodnoty a zahozením druhé. Jestliže je použit příznakový registr jako cílový registr instrukce, nezapisují se změny příznaků, ale pouze výsledek. To je důležité pro možnost manipulace s jednotlivými příznaky pomocí logických operací, které normálně mění příznaky podle výsledku operace.
Podobně jako obecné registry jsou implementované řídicí registry csr0...csr15
entitou mb5016_csr
v souboru mb5016_csr.vhd. Jejich implementace je jednodušší, protože jsou využívány pouze první čtyři registry, vždy se čte nebo zapisuje pouze jeden registr a nemusíme řešit ukládání příznaků. I tak se jedná o netriviální obvod, jak je vidět na obrázku.

Výřez schématu implementace řídicích registrů, každý obdélník v prostředním sloupci představuje jednobitový registr obsažený v logickém elementu FPGA
Aritmeticko-logická jednotka
Procesor MB5016 obsahuje 16bitovou aritmeticko-logickou jednotku (arithmetic-logic unit, ALU). Příslušná entita mb5016_alu
je v souboru mb5016_alu.vhd. Jedná se o čistě kombinační obvod. To znamená, že nemá žádné interní registry a požadovanou operaci počítá v jednom taktu. ALU má dva 16bitové vstupy pro operandy, vstup pro výběr operace, dva 16bitové výstupy pro výsledky a čtyři jednobitové výstupy s hodnotami příznaků Zero, Carry, Sign a Overflow.
Kromě aritmetických ( ADD, SUB, SHL,
atd.) a logických instrukcí ( NOT, AND, OR, XOR
) se ALU používá i při přesunech dat mezi registry ( MV, EXCH, CSRR, CSRW
) a z/do paměti ( LD, LDB, STO,
STOB
). Pro tyto instrukce se využívají pouze multiplexory a demultiplexory zapojené mezi registry a ALU. Operace prováděná v těchto případech je prosté kopírování vstupů na výstupy. ALU se také používá na generování vybraných konstant, jako je nula nebo kódy příčin výjimek.
Při implementaci ALU hodně pomáhá, že nemusíme skládat obvody počítající aritmetické a logické operace z jednotlivých logických elementů. Syntetizér umí vygenerovat zapojení přímo z použitých operátorů v jazyce VHDL. Například implementace sčítačky včetně přidání bitu pro přenos se tak redukuje na jednoduchý zápis OutA := ('0' & InA) + ('0' & InB);
Řadič
Řadič (Control Unit, CU) je implementovaný entitou mb5016_cu
v souboru mb5016_cu.vhd. Úkolem řadiče je koordinovat všechny ostatní části CPU a řídit vykonávání instrukcí. Jádrem řadiče je konečný automat, viz obrázek, který na začátku vykonávání každé instrukce začíná ve stavu Init a po dokončení instrukce se do tohoto stavu opět vrací.
Zpracování instrukce začíná testem, zda není nastavený příznak přerušení. Pokud ano, místo původní instrukce se provede volání obslužné rutiny přerušení. V opačném případě se z paměti přečtou dva bajty tvořící instrukci. Následně se zavolá funkce decode_opcode
, která dekóduje operační kód instrukce z prvního bajtu, a proceduroudecode_regs
se extrahují čísla zdrojového a cílového registru z druhého bajtu instrukce.
Dekodér obsahuje tabulku popisující vlastnosti jednotlivých instrukcí:
- instrukce je/není implementovaná,
- instrukce je/není podmíněná, tedy prováděné akce závisí na výsledku testu bitu z příznakového registru,
- volba operace v ALU,
- uložení nebo zahození příznakových bitů,
- přečtení 0, 1, nebo 2 bajtů z paměti před provedením operace v ALU,
- zápis 0, 1, nebo 2 bajtů do paměti po provedení operace v ALU.
Následně automat prochází dalšími stavy podle výsledku dekódování a provádí jednotlivé dílčí akce: test podmínky, čtení z paměti, použití ALU, zápis do paměti. Některé instrukce vyžadují další akce, jež nezapadají do obecného schématu. Pro ty jsou pak v kódu konečného automatu definované speciální větve.
Propojení všech částí CPU
Jednotlivé části procesoru jsou propojeny entitou mb5016_cpu
v souboru mb5016_cpu.vhd. Zde jsou definované instance entit pro registry, řídicí registry, ALU a řadič. Jejich signály jsou navzájem propojené s minimem přidané logiky. Jedná se o kombinaci strukturního (skládání z částí) a data flow (přiřazování signálů a jejich kombinace pomocí operátorů) přístupu k popisu obvodu ve VHDL. Hlavní entita CPU také řídí externí signály procesoru, vyjmenované na začátku tohoto článku.
Obsah následujícího dílu
V následujícím dílu si ukážeme další obvody potřebné pro postavení celého počítače MB50. Nakonec CPU MB5016 a všechny další části poskládáme dohromady.
(Autorem obrázků je Martin Beran.)