Hlavní navigace

Programovací jazyk Forth a zásobníkové procesory (18)

10. 5. 2005
Doba čtení: 12 minut

Sdílet

V předchozích dvou dílech tohoto seriálu jsme si popsali čtyři typické představitele šestnáctibitových zásobníkových procesorů, které byly určeny zejména pro různé vestavěné systémy, u nichž hraje jednu z rozhodujících rolí celková cena těchto systémů. V dnešním pokračování se již budeme zabývat zásobníkovými procesory, jejichž zásobníky i ALU mají bitovou šířku plných 32 bitů, což dále rozšiřuje možnosti nasazení těchto čipů v různých řídicích systémech.

Obsah

1. Vlastnosti třicetidvoubitových zásobníkových procesorů
2. Zásobníkový mikroprocesor FRISC 3
3. Hardwarová konfigurace mikroprocesoru FRISC 3
4. Zásobníky a jejich řízení
5. Instrukční sada mikroprocesoru FRISC 3
6. Zásobníkový mikroprocesor RTX 32P
7. Hardwarová konfigurace mikroprocesoru RTX 32P
8. Instrukční sada mikroprocesoru RTX 32P
9. Obsah dalšího pokračování

1. Vlastnosti třicetidvoubitových zásobníkových procesorů

Třicetidvoubitové zásobníkové procesory ve své podstatě představují logické pokračování či rozšíření zásobníkových procesorů šestnáctibitových (osmibitové zásobníkové procesory se, jak již víme z předchozích dílů tohoto seriálu, příliš nerozšířily). Větší šířka jednotlivých elementů obou zásobníků i aritmeticko-logické jednotky umožňuje urychlení a současně i zjednodušení mnoha aplikací, které nebylo možné na šestnáctibitových procesorech úspěšně provozovat. Zatímco šestnáctibitové zásobníkové procesory jsou určeny především pro vestavěné systémy (kde jsou v mnoha případech nezastupitelné, zejména díky své nízké ceně, spotřebě a rychlosti reakce na přerušení), možnosti třicetidvoubitových procesorů jsou mnohem větší – uplatňují se například v kosmickém programu (družice, řídicí a signalizační systémy raketoplánů), pro správu databází, aplikačních webových serverů, některé z těchto procesorů lze najít i ve webových boxech atd.

Popišme si tedy některé výhody třicetidvoubitových zásobníkových procesorů oproti jejich „tenčím“ kolegům. Zásadní předností je plně 32bitová aritmetika, kdy se již nemusí výpočty v tomto bitovém rozsahu provádět pomocí sekvencí několika operací. Také se podstatně zlepšují možnosti adresace paměti, odpadá tak určitá schizofrenie některých šestnáctibitových procesorů, které prováděly adresní aritmetiku na více bitech, než měla jejich ALU – čistě šestnáctibitové procesory jsou omezeny na adresování 64 kB resp. 128 kB operační paměti. Kromě toho je u těchto procesorů někdy přímo na jádře přítomna i jednotka pro provádění výpočtů v pohyblivé řádové čárce (FPU – Floating Point Unit), jejíž umístění přímo v jádře je umožněno díky mnohem větší integraci logických prvků. Taktovací frekvence je obecně větší než v případě šestnáctibitových zásobníkových procesorů, přičemž však zůstává zachován konstantní kmitočet provádění instrukcí: jedna instrukce za takt, stejně tak jako slučování více operací do jedné instrukce.

Použití třicetidvoubitových zásobníkových procesorů však přináší i některé nevýhody, z nichž jmenujme například vyšší cenu těchto procesorů (ta je pro vestavěné systémy mnohdy kritická), problém se šestnáctibitovými Forthy, které jsou velmi rozšířené, a problémy s nasazením čipů vyšší integrace v kosmickém prostředí (i z tohoto důvodu se například do mnoha družic kromě zásobníkových procesorů používají i historické procesory 80386). Zvýšení bitové šířky u datových položek obou zásobníků způsobuje problémy při jejich implementaci, protože se samozřejmě zvětšuje i potřebná kapacita paměti, která musí být pro tyto zásobníky alokována. Tento problém se obecně řeší třemi metodami: ponecháním separátní paměti či pamětí pro jednotlivé zásobníky, uložením celých zásobníků přímo na čip či uložením vrcholů zásobníků (TOS) na čipu, zbytek je alokován v operační paměti. Každá z těchto možností má své výhody a nevýhody, zejména si musíme uvědomit fakt, že současné technologie neumožňují na jednom čipu libovolně kombinovat logické členy (hradla a klopné obvody) s dynamickými paměťovými buňkami, což omezuje kapacity zásobníků vytvořených přímo na čipu mikroprocesoru.

V následujících kapitolách si popíšeme dva typické zástupce starší generace třicetidvoubitových zásobníkových mikroprocesorů: FRISC 3 a RTX 32P. Poznámka: novější generace zásobníkových mikroprocesorů je představována zejména procesory přizpůsobenými pro běh javovského bytekódu, zaměření na optimální provádění forthovských operací se tedy pomalu vytrácí.

2. Zásobníkový mikroprocesor FRISC 3

Třicetidvoubitový zásobníkový mikroprocesor FRISC 3 byl vyvinut na Univerzitě Johna Hopkinse v Laboratoři aplikované fyziky (Johns Hopkins University/Applied Physics Laboratory – JHU/APL). Samotné označení tohoto mikroprocesoru vychází ze slov Forth Reduced Instruction Set Computer, a jak již tento název napovídá, jedná se o procesor ze „staré školy“, který je optimalizován pro běh aplikací vytvořených v programovacím jazyce Forth. Na výše zmíněné univerzitě byly navrženy i další zásobníkové mikroprocesory, FRISC 1 a FRISC 2. Ty však byly vyrobeny pouze v testovacích sériích, k jejich hromadné výrobě nikdy nedošlo. Procesor FRISC 3 byl vytvořen především pro vesmírný program, kde byl také skutečně použit, zejména v úspěšném projektu Space Shuttle a v neposlední řadě také v několika družicích. Vzhledem k úspěšnosti těchto programů byly práva na výrobu tohoto procesoru odkoupeny komerční firmou Silicon Composers, která je po úpravě prodávala pod názvem SC32.

Ve třetí kapitole bude stručně popsána hardwarová konfigurace tohoto procesoru, čtvrtá kapitola je věnována zásobníkům a jejich řízení a kapitola pátá instrukční sadě, která je vytvořena podobným způsobem jako u dříve popsaných šestnáctibitových zásobníkových procesorů.

3. Hardwarová konfigurace mikroprocesoru FRISC 3

Architektura tohoto mikroprocesoru se v mnohém podobá jeho šestnáctibitovým předchůdcům, s tím rozdílem, že do jádra procesoru jsou přidány další důležité funkční bloky. Přímo v jádře jsou vytvořeny dvě interní sběrnice, které jsou označeny jako ABUS a BBUS – obdobu těchto sběrnic nalezneme i v dalších zásobníkových procesorech. Na tyto sběrnice je napojena aritmeticko-logická jednotka a blok pro provádění bitových posunů, který běží nezávisle na ALU. Kromě toho je v jádře vytvořeno i několik registrů, které jsou pomocí některých instrukcí přímo přístupné programátorům.

Jedná se zejména o čtyři uživatelské registry, dále o registr PC, který se mění pomocí skokových instrukcí a instrukcí pro návrat z podprogramu, registr FL obsahující jeden ze šestnácti volitelných příznaků a velmi zajímavý registr ZERO, který na interní sběrnici vždy posílá nulovou hodnotu – je trošku škoda, že nelze programově nastavit hodnotu tohoto registru, pro některé aplikace by byl rychlý přístup k jedné konstantě jistě výhodný, což je ostatně patrné i z instrukční sady zásobníkových procesorů určených pro běh Javy.

Aritmeticko-logická jednotka kromě své základní funkce slouží i pro výpočet efektivní adresy, a dovoluje tak provádět adresování typu ukazatel+offset, což je výhodné zejména při práci s poli.

4. Zásobníky a jejich řízení

Podobně jako u jiných zásobníkových procesorů jsou i zde zásobník operandů a zásobník návratových adres vytvořeny identicky, tj. skládají se ze stejných funkčních bloků. Paměť pro zásobníky (či jejich část) je vytvořena jako kruhový buffer o šestnácti třicetidvoubitových položkách přímo v jádře procesoru, k zásobníkům se přitom přistupuje pomocí logiky, která již na hardwarové úrovni zajistí, že nikdy nedojde k přetečení či podtečení těchto bufferů – v případě nutnosti se provede přesun dat z a do operační paměti, kde je uložen zbytek obsahu zásobníků. Tato logika nebyla na dříve popisovaných zásobníkových procesorech použita, což mohlo vést k nekorektní práci běžících aplikací v případě, že došlo k přetečení interních zásobníků.

Kruhové buffery tak slouží jako zásobníková vyrovnávací paměť, se kterou se setkáme i v dalším pokračování tohoto seriálu, kde jsou popisovány javovské zásobníkové procesory. Kromě přístupu k nejvrchnějším položkám zásobníků pomocí známých instrukcí typu push, pop, dup, drop, over a rot je možné přímo adresovat čtyři nejvrchnější elementy zásobníků, čímž se možnosti zásobníků blíží možnostem obecných registrů (či je dokonce převyšují, díky automatickému posunu jednotlivých hodnot při přidávání a ubírání hodnot ze zásobníků).

5. Instrukční sada mikroprocesoru FRISC 3

Všechny instrukce zásobníkového mikroprocesoru FRISC 3 mají délku 32 bitů a jejich formát je horizontální, podobně jako u dříve popsaných šestnáctibitových procesorů. Instrukce mohou být čtyřech typů: skoky (podmíněné i nepodmíněné), práce s pamětí, operace s ALU a bitové posuny. Jednotlivé typy instrukcí si nyní zevrubně popíšeme.

Skokové instrukce se vyznačují tím, že nejvyšší tři bity instrukčního kódu specifikují typ skoku a zbývající bity jsou rezervovány pro adresu instrukce. Pokud jsou první tři bity nastaveny na hodnotu 000, jedná se o skok do podprogramu, při hodnotě 001 se jedná o nepodmíněný skok a při hodnotě 010 o skok, který se provede v případě, že je registr FL nastaven na nulu. To kupodivu postačuje, protože registr FL může být naplňován mnoha způsoby při ALU operacích – ostatně způsob práce s tímto registrem je asi nejzajímavější věcí, kterou tvůrci procesoru FRISC 3 implementovali.

Instrukce přístupu do paměti se poznají tak, že nejvyšší tři bity jsou nastaveny na některou z hodnot 100, 101, 110 či 111. Podle toho se pozná, zda se má provést čtení, či zápis do paměti. Zbylé dvě kombinace jsou určeny pro načtení horního či dolního adresního slova (konstanta je totiž kódována přímo v dolních šestnácti bitech instrukce). Dále je možné zvolit, do kterého zásobníku či registru se hodnota načte – je možné adresovat jednu z nejvyšších čtyřech buněk každého zásobníku, dále jeden ze čtyř uživatelských registrů, registr PC apod. Kromě toho je jeden bit v instrukci rezervován na provedení návratu z podprogramu (return), který tak může být proveden paralelně k běžící operaci.

ALU operace patří k velmi zajímavým, protože je pomocí nich možné provádět i poměrně komplikované výpočty. Nejvyšší čtyři bity musí být nastaveny na hodnotu 0110. Podobně jako u předchozího typu instrukce je i zde možné specifikovat zdrojové operandy a uložení výsledku. Kromě toho se specifikují základní operace s oběma zásobníky (push, pop atd.), jedna z celkem 28 (!) ALU operací a jeden ze šestnácti způsobů naplnění podmínkového registru FL, který tak nahrazuje vícebitový registr FLAGS známý z jiných typů procesorů.

Bitové posuny mohou být poměrně komplikované, neboť do jejich průběhu může zasahovat i obsah registru FL. Pomocí dvou bitů z instrukčního kódu se specifikuje, zda se provádí běžné bitové posuny, nebo posuny upravené pro operace násobení a dělení. Obsah registru FL může být změněn buď pomocí bitu, který je bitovým posunem „vysunut“ ze zpracovávaného slova, nebo se může nad výsledkem operace provést jedna ze šestnácti podmínek, na jejichž výsledku je posléze naplnění provedeno (tyto podmínky jsou stejné jako v případě ALU operací).

Všechny výše zmíněné typy instrukcí jsou vytvořeny tak, aby se provedly v jednom instrukčním cyklu, což zajišťuje velkou rychlost provádění operací. Výjimkou jsou samozřejmě instrukce pro čtení či zápis do paměti, které pro své provedení vyžadují cykly dva. Skok do podprogramu zabere pouze jeden takt, což je jistě, zejména v porovnání s procesory řady x86, velmi zajímavé. Návrat z podprogramu se dokonce provede současně s probíhající instrukcí, protože se nejedná o samostatnou instrukci, ale pouze o jeden bit instrukčního slova.

V následující tabulce jsou ukázána některá základní slova programovacího jazyka Forth, která lze přímo zakódovat pomocí jedné instukce procesoru FRISC 3:

0                        >R
0<                       @
0=                       AND
0>                       BRANCH
0BRANCH                  CALL
1                        DROP
1+                       DUP
1-                       EXIT
2*                       LITERAL
2+                       NEGATE
2/                       NOT
4+                       OR
+                        OVER
-1                       R>
-                        R@
<                        S->D
<>                       U<

=                        U>
>                        XOR 

Podobně jako u předchozích zásobníkových procesorů, i zde je možné do jedné instrukce zakódovat více slov jazyka Forth (popisované zásobníkové procesory jsou v tomto ohledu podobné jako procesory typu VLIW):

LIT + @              (adresa posunutá o offset)
LIT + !              (adresa posunutá o offset)
<variable> @         (načtení proměnné)

<variable> !         (uložení proměnné)
2 PICK               (kopie třetí položky uložené na zásobníku operandů)
3 PICK               (kopie čtvrté položky uložené na zásobníku operandů)

R> DROP                  R@ <
SWAP DROP                OVER OVER +
LIT +                    DROP LIT
OVER +                   DUP LIT +
OVER -                   DROP DUP
DUP +                    DROP OVER
DUP AND                  OVER @
DUP XOR                  2 PICK @
DUP 1+                   3 PICK @
OVER +                   OVER !
2 PICK +                 2 PICK !
3 PICK +                 3 PICK !
R@ +                     + >R
R> +                     DUP >R
DUP <                    DUP R> DROP
DUP >                    R> DROP DUP 

Tomuto zásobníkovému procesoru je podobný třicetidvoubitový zásobníkový procesor RTX 32P, který je popsán v následujících kapitolách.

6. Zásobníkový mikroprocesor RTX 32P

Zásobníkový procesor RTX 32P je prototypovým procesorem firmy Harris Semiconductor, která na něm postavila i své další komerční produkty založené na třicetidvoubitových zásobníkových procesorech. Procesor je primárně určen pro běh aplikací napsaných v programovacím jazyce Forth, avšak vzhledem k možnosti dynamické změny instrukční sady je možné velmi efektivním způsobem používat i aplikace napsané v některém jiném programovacím jazyce, například v C-čku, Pascalu, ale i v LISPu a Prologu.

7. Hardwarová konfigurace mikroprocesoru RTX 32P

Zajímavé na tomto procesoru je především to, že jádro používá mikroinstrukce, které jsou uloženy přímo na čipu v poměrně velké paměti RAM. Změna instrukční sady je tedy velmi jednoduchá, což umožňuje optimalizaci procesoru pro různé aplikace a programovací jazyky. Podobně jako u předchozího procesoru jsou i zde zásobníky vytvořeny přímo na čipu, což nemalým způsobem urychluje přístup k jejich obsahu. Vzhledem k tomu, že je kapacita pamětí pro mikroinstrukce a pro jednotlivé zásobníky poměrně velká, rozhodli se tvůrci celý procesor pro testovací účely vytvořit na dvou čipech, v komerčních verzích se však samozřejmě přešlo k jednočipovému řešení, které je levnější.

Vzhledem k tomu, že díky velkému zrychlování logických prvků dochází k soustavnému urychlování práce procesorů, je procesor RTX 32P vytvořen tak, že aritmeticko-logická jednotka může zpracovat dvě operace při jednom přístupu do operační paměti. Tato paměť tak může být až dvakrát tak pomalejší než vlastní procesor bez toho, aby bylo znatelné zpomalení běhu programu. To samozřejmě vyžaduje, aby bylo možné do jedné instrukce zakódovat více operací (prováděných pomocí mikroinstrukcí), což není, vzhledem k horizontálnímu instrukčnímu kódu, problematické. Samotné mikroinstrukce jsou na čipu uloženy v paměti RAM, tj. po resetu mikroprocesoru již musí být tato paměť naplněna, což se v testovací verzi procesoru dělo z připojeného řídicího počítače.

Zásobník operandů i zásobník návratových adres jsou vytvořeny přímo na procesoru. Každý ze zásobníků obsahuje 512 položek, pro jejich adresování slouží dva devítibitové čítače, které podle použité operace se zásobníkem mohou čítat nahoru i dolů (up/down counters). Ukazatele na vrchol zásobníku je možné programově přečíst i změnit, čímž je umožněno pracovat i s položkami umístěnými ve větší hloubce zásobníků (to odpovídá sémantice forthovských slov pick a roll).

Na tomto procesoru je však nejzajímavější skutečnost, že neobsahuje registr PC (Program Counter) ani žádnou jeho obdobu. Místo toho si s sebou každá instrukce nese adresu instrukce následující, což umožňuje provádění častých skoků, které jsou pro programy vytvořené ve Forthu typické. Nejedná se sice o první procesor bez čítače instrukcí, ale i tak jde o poměrně vzácnou vlastnost, která může být plně využita pouze ve forthovských (a částečně i LISPovských) programovacích jazycích.

8. Instrukční sada mikroprocesoru RTX 32P

Mikroprocesor RTX 32P má pouze jeden formát instrukcí, které mají konstantní délku 32 bitů. V bitech 23–31 je uložen operační kód instrukce, bity 2–22 obsahují adresu další instrukce (zde existuje možnost provádění skoků či zavolání podprogramů). Pomocí bitů 0–1 je specifikováno, jak se má chápat uložená adresa: 00-přímý skok, 01-návrat z podprogramu, 10-volání podprogramu, 11-není použito. Pomocí jedné instrukce lze provést následující forthovská slova:

!                        DDROP
+                        DDUP
+!                       DNEGATE
-                        DROP
0                        DSWAP
0<                       DUP
0=                       I
0BRANCH                  I'
1+                       J
1-                       LEAVE
2*                       LIT
2/                       NEGATE
<                        NOP
PICK                     NOT
ROLL                     OR
=                        OVER
>R                       R>
?DUP                     R@
@                        ROT
ABS                      S->D
AND                      SWAP
BRANCH                   U*
D!                       U/MOD
D+                       XOR
D@ 

Samozřejmě je možné vytvořit i jiný formát instrukcí, a to nahráním jiných mikroinstrukčních kódů do paměti mikroinstrukcí. V současné době existují sady instrukcí, které jsou vhodné pro provádění programů napsaných v programovacích jazycích C, Pascal a ADA, případně i předkompilovaného LISPu a Prologu.

CS24_early

9. Obsah dalšího pokračování

V dalším, už předposledním pokračování tohoto seriálu si popíšeme funkci třicetidvoubitových zásobníkových mikroprocesorů, které jsou určeny pro běh javovského bytekódu. Tyto procesory měly ve své době představovat základ pro takzvaný Network computer, jehož myšlenka se však prozatím příliš neujala.

Byl pro vás článek přínosný?

Autor článku

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