První program
Všechny programy, které si dnes představíme, jsou na GitHubu v adresáři mb50/mb50sw. Dají se rozběhat způsobem popsaným minule. Nejprve je potřeba vybraný program přeložit do strojového kódu assemblerem mb50as a následně pomocí debuggeru mb50dbg nahrát do počítače MB50 a spustit.
Úplně první program pro počítač MB50 je v souboru first_program.s. Jeho binární verze je v mb50.mif, což je soubor definující počáteční obsah paměti. Je tedy připraven vždy po spuštění počítače. Ve skutečnosti se jedná už o druhou verzi. Předchozí verze, zachovaná ve starším commitu v Gitu, ten opravdu historicky první program spuštěný na MB50, obsahovala pouze první tři instrukce. Obě verze původně vznikly ručním zapsáním hexadecimálních kódů instrukcí do souboru MIF, protože jsou starší než assembler. Dokonce vznikly dříve než debugger a pro jejich spuštění se použilo nedokončené řídicí a ladicí rozhraní počítače, jež spustilo procesor i bez příkazu přijatého po sériovém portu.
Tento první program, ve své delší variantě, rozbliká první dva bloky 8×8 pixelů na obrazovce vlevo nahoře, nakreslí 16 pixelů dlouhou vodorovnou čáru od bodu se souřadnicemi x=0, y=2 a nastaví barvu okraje obrazovky. Následně procesor načte instrukci s nulovým prvním bajtem (opcode), vyvolá výjimku a zastaví se. Není to žádný oslnivý program, ale konečně počítač něco dělá!
Prvním programem začala i skončila éra programování ve strojovém kódu. Další programy už vznikaly pohodlnějším způsobem po dokončení debuggeru a assembleru.
Na tomto místě je vhodné zmínit jednu zajímavou zkušenost z programování počítače MB50. Normálně, když nám něco nefunguje, hledáme chybu přednostně v našem vlastním kódu. Málokdy se stává, že chyba je v implementaci překladače programovacího jazyka, zvlášť když se jedná o tak jednoduchý jazyk, jako je assembler. Ještě méně pravděpodobné je, že narazíme na chybu v procesoru. U MB50 to bylo jinak. Docela často se mi stávalo, že jsem nemohl najít chybu v assemblerovém kódu a nakonec jsem zjistil, že tam opravdu není. Místo toho jsem musel opravit assembler, nebo se dokonce ponořit až na úroveň hardwaru, najít a opravit chybu ve VHDL kódu procesoru.
Programy v repozitáři
V adresáři mb50/mb50sw jsou tři podadresáře, obsahující tři skupiny zdrojových kódů v assembleru. V podadresáři test jsou jednoduché testovací prográmky, které obvykle nepoužívají celou systémovou knihovnu ani neprovádí kompletní inicializaci systému, např. nepovolují přerušení. Tyto programy vznikly v různých fázích vývoje za účelem testování hardwaru a vývojových nástrojů.
Podadresář sys obsahuje systémovou knihovnu. Tu si blíže popíšeme v dalším textu. V posledním podadresáři app se nachází několik ukázkových programů, demonstrujících použití různých funkcí systémové knihovny a operace s periferními zařízeními, konkrétně čtení vstupu z klávesnice PS/2 a zobrazování textu a barev na připojeném VGA monitoru.
Systémová knihovna
V adresáři mb50sw/sys jsou zdrojové kódy systémové knihovny rozdělené do několika souborů. Do hlavního programu se přidávají pomocí assemblerové direktivy $use. Fungování systémové knihovny si popíšeme pouze v hrubých obrysech. Zájemci mohou najít další podrobnosti přímo ve zdrojových souborech.
Soubor constants.s obsahuje definice řady užitečných konstant pomocí direktiv $const. Jsou zde symbolicky pojmenované jednotlivé bity příznakového registru, systémové parametry (např. frekvence hodin a rozsahy adres v paměti), rozlišení monitoru, adresy obrazové paměti, barvy a adresy řídicích registrů řadiče klávesnice.
V souboru macros.s jsou definované pseudoinstrukce a další užitečná makra. Často používané jsou set (uložení konstanty zapsané v programu do registru), lda (načtení hodnoty z adresy zapsané jako konstanta v programu) a řada maker implementujících nepodmíněné i podmíněné skoky, volání a návraty z podprogramu. Připomeňme si, že procesor MB5016 nemá pro tyto akce speciální instrukce. Registr pc je zařazen mezi obecné registry, proto se k řízení toku programu používají instrukce jako MV, EXCH, LD,
LDIS a jejich podmíněné varianty. Další skupinu tvoří makra pro ukládání registrů na zásobník. K dispozici jsou také makra pro povolení a zákaz přerušení.
Různé užitečné podprogramy jsou k dispozici v souboru stdlib.s. Zahrnují vyplnění úseku paměti zadanou hodnotou, převod hodnoty v registru na řetězec dekadických číslic, celočíselné dělení a několik funkcí pro zobrazování řetězců, dekadických a hexadecimálních čísel. Také je zde definovaný podprogram pro výpis hodnot všech registrů, standardně volaný z obslužné rutiny výjimek.
Se zobrazováním souvisí soubor font.s obsahující tabulku pro zobrazování viditelných znaků ze znakové sady ASCII. Obsahuje znaky s kódy 0×20 až 0×7e. Každý znak je definován v matici 8×8 pixelů pomocí osmi bajtů.
Další tři soubory jsou zaměřeny na obsluhu přerušení a hardwaru. První z nich je dev_clk.s, ovladač systémových hodin. Obsahuje obsluhu přerušení generovaných hodinami, převod hardwarového čítače hodin na sekundy a milisekundy, rutinu pro zjištění aktuálního času a podprogram sleep pro čekání po zadanou dobu.
Druhý je ovladač klávesnice dev_kbd.s. Ten čte scan kódy přicházející z klávesnice a konvertuje je na kódy znaků a speciálních kláves. Také se stará o rozsvěcení a zhasínání LED na klávesnici.
Třetí soubor interrupts.s se stará o obsluhu přerušení. Definuje hlavní handler přerušení, který pak volá handlery pro jednotlivé typy přerušení a výjimek. Obsahuje také podprogram intr_init zajišťující inicializaci systému přerušení při startu počítače. Obsluha přerušení, včetně ukládání registrů na zásobník, testování a nulování příznakových bitů jednotlivých typů přerušení, je asi část kódu s nejsložitější logikou.
Poslední dva soubory se používají pro počáteční inicializaci na začátku programu. V souboru init.s se provádí počáteční inicializace systému. Ta zahrnuje inicializaci zásobníku, smazání obrazovky, inicializaci a povolení přerušení. Na závěr zobrazí uvítací obrazovku.
Soubor start.s obsahuje pouze skok na vstupní bod uživatelského programu, který musí být označen návěštím main . Vzhledem k fungování direktiv$use je většinou celý kód systémové knihovny na začátku adresového prostoru před uživatelským aplikačním kódem. Počítač normálně startuje s hodnotou 0 v registru pc , tedy od adresy 0. Většina obsahu souborů tvořících systémovou knihovnu není určena k tomu, aby se jejich obsah vykonával během inicializace. Proto je typicky na začátku souboru instrukce.jmp _skip_this_file zajišťující přeskočení zbytku souboru.
Demonstrační program
Cílem projektu MB50 bylo především navrhnout a implementovat procesor MB5016, doplnit ho dalšími komponentami a demonstrovat, že takto získaný počítač MB50 funguje a dá se programovat v assembleru. Tvorba nějakého složitějšího nebo zajímavějšího softwaru nebyla v plánu, ale mohla by být námětem nějakého budoucího navazujícího projektu.
Z toho důvodu se dosud napsané programy pro MB50 omezují na základní demonstraci fungování počítače. Nejkomplexnější z nich je program demo1.s. Program po startu zobrazí hlavní menu, z něhož je možné vybrat jednu ze čtyř funkcí: zobrazení ASCII tabulky znaků, průběžné vypisování času systémových hodin, přepínání barev popředí, pozadí a okraje obrazovky. Čtvrtou funkcí je vyvolání výjimky, což způsobí vypsání hodnot všech registrů procesoru.
Závěr naší cesty
Tímto článkem jsme zakončili naši cestu od logických hradel až k funkčnímu procesoru MB5016, pro který je možné psát kód v assembleru a spouštět ho na počítači MB50 implementovaném pomocí FPGA. Většinu témat jsem v tomto seriálu nemohl probrat úplně do hloubky. To by vyžadovalo mnohem více textu.
Zájemci o detaily návrhu a implementace počítače MB50 se mohou podívat do repozitáře na GitHubu, kde jsou k dispozici kompletní zdrojové kódy a podrobná dokumentace. Další informace o problematice návrhu hardwaru, konstrukci procesorů, obvodech FPGA a jazycích VHDL/Verilog lze najít na Internetu. Několik linků, kde je možné začít studovat, bylo uvedeno jak v textu jednotlivých článků, tak i v diskuzi.
Projekt MB50 zde tedy prozatím končí, ale pro případné zájemce mám několik nápadů na pokračování:
- Implementovat základní zvukový výstup. Vývojová deska má k tomu připravený hardware.
- Rozšířit paměť o dynamickou RAM dostupnou na desce.
- Přidat externí úložiště, např. čtečku SD karet, a umožnit z něj nahrávat programy.
- Doplnit možnost provozovat MB50 i bez připojení k debuggeru na hostitelském počítači.
- Napsat nějaký zajímavý program, třeba dobrou hru.
- Implementovat překladač některého vyššího programovacího jazyka. Jako dobrý kandidát se nabízí jazyk C.
Pokud někoho z čtenářů tento seriál inspiruje k vlastním pokusům, nebo budete mít nějaké připomínky či dotazy k článkům nebo k obsahu repozitáře, budu rád, když se mi ozvete.
(Autorem obrázků je Martin Beran.)


