Kouzlo minimalismu potřetí: vývoj her a dem pro slavné ZX Spectrum

7. 2. 2023
Doba čtení: 29 minut

Sdílet

 Autor: Depositphotos
Navážeme na série článků o vývoji her pro Atari 2600 a konzoli NES. Řekneme si, jak vyvíjet hry a grafická či hudební dema pro neméně slavný osmibitový stroj ZX Spectrum.

Obsah

1. Kouzlo minimalismu podruhé: vývoj her a grafických i zvukových dem pro ZX Spectrum

2. Slavné ZX Spectrum a ZX Spectrum+

3. Základní parametry ZX Spectra

4. ZX Spectrum 128K+

5. NES a ZX Spectrum: dvě naprosto odlišné platformy

6. Mapa paměti ZX Spectra

7. Grafický režim ZX Spectra

8. Slavný osmibitový mikroprocesor Zilog Z80

9. Assemblery a cross assemblery pro ZX Spectrum a jeho následovníky

10. Instalace assembleru a emulátoru ZX Spectra

11. První program v assembleru: změna barvového atributu v levém horním rohu obrazovky

12. Zápis zdrojového kódu prvního příkladu

13. Překlad do strojového kódu a uložení výsledku ve formátu tap

14. Načtení a spuštění příkladu v emulátoru ZX Spectra s originální licencovanou ROM

15. Načtení a spuštění příkladu s využitím OpenSE BASICu

16. Zobrazení blikajícího čtverečku

17. Symbolické hodnoty namísto konkrétních adres

18. Soubor Makefile pro překlad demonstračních příkladů

19. Repositář s demonstračními příklady

20. Odkazy na Internetu

1. Kouzlo minimalismu podruhé: vývoj her a grafických i zvukových dem pro ZX Spectrum

Na sérii článků o vývoji her (či spíše hříček) pro osmibitovou herní konzoli Atari 2600 s využitím Batari Basicu [1] [2] [3] a taktéž na jedenáctidílný seriál o vývoji pro slavnou osmibitovou herní konzoli NES dnes nepřímo navážeme. Řekneme si totiž, jakým způsobem je možné vyvíjet hry a grafická či hudební dema pro neméně slavný osmibitový stroj – ZX Spectrum. Vývoj pro ZX Spectrum se od vývoje pro NES odlišuje v prakticky všech aspektech, od zcela odlišně pojatého instrukčního souboru, až po rozdíly v grafickém subsystému. To je ostatně jen dobře, protože se naučíme (pro někoho) nové techniky a nebudeme se příliš opakovat.

Obrázek 1: Typické pruhy na okraji obrazovky, které jsou zobrazovány při nahrávání programů z kazety.

Poznámka: právě ZX Spectrum bylo (minimálně v Evropě) tou skutečnou svobodnou platformou, na níž se mohl prosadit i osamělý programátor, a to bez nutnosti uzavření exkluzivních smluv s výrobcem herní konzole. Ostatně mnoho nejúspěšnějších her pro ZX Spectrum vzniklo doslova „v garáži“. Asi nejznámějším příkladem je Manic Miner, dílo tehdy sedmnáctiletého Matthewa Smithe.

Obrázek 2: Level ze hry Manic Miner.

Pokud si tedy chcete alespoň na chvíli odpočinout od moderního softwarového inženýrství s mnoha vrstvami abstrakce, sofistikovanými a rozsáhlými knihovnami, transpřekladači, virtuálními stroji, automatickými správci paměti atd., kde spustitelný soubor zobrazující „Hello world!“ zabírá 2MB a vyžaduje ke svému běhu podobnou kapacitu operační paměti (pokud tedy rovnou neběží v kontejneru s desítkami megabajtů obrazů), je zde stále k dispozici emulátor ZX Spectra, assembler, technická dokumentace k mikroprocesoru Zilog Z80 a 48 kB operační paměti.

Obrázek 3: Jednou z nejoblíbenějších her pro ZX Spectrum zůstává JetPac od firmy Ultimate Play the Game. Tato hra si vystačila s pouhými 16kB RAM (kam musíme počítat i obrazovou paměť!).

2. Slavné ZX Spectrum a ZX Spectrum+

Pravděpodobně nejslavnějším počítačem navrženým a vyráběným společností Sinclair Research je ZX Spectrum a jeho následovníci, tj. modely ZX Spectrum+ a ZX Spectrum 128K+ i jejich rozličné varianty (i ty určené pro trh v USA, které se u některých modelů od původního Spectra odlišují). Původní ZX Spectrum (v tuzemsku lidově označovaný jako „gumák“ podle své klávesnice) bylo nabízeno ve dvou variantách. Levnější varianta, která byla prodávána za 125 liber, obsahovala 16 kB operační paměti, zatímco varianta dražší (nabízená za 175 liber) měla celých 48 kB RAM (i tak se však jednalo o velmi levný mikropočítač). Levnější model bylo možné za přibližně šedesát liber upgradovat, tj. rozšířit paměť o 32 kB RAM. Dalším modelem bylo ZX Spectrum+, které bylo vybaveno klávesnicí s kurzorovými tlačítky, klávesou Extend Mode, která zjednodušovala zápis některých BASICovských příkazů i Resetem.

Obrázek 4: Slavný „gumák“ ZX Spectrum.

Udává se, že po uvedení ZX Spectra na trh se každý týden prodalo až 15 tisíc kusů tohoto počítače. Velká popularita mezi uživateli se samozřejmě odrazila i v počtu aplikací – v době největší slávy ZX Spectra bylo vytvořeno více než 10000 her a dalších programů, ovšem aplikace pro něj vznikají i nyní. Především se jedná o nové hry (například existuje i Doom pro Spectrum) a dema. Většinu her a nástrojů (ale i dobové dokumentace) k ZX Spectru lze nalézt na stránkách https://worldofspectrum.org/archive.

Obrázek 5: ZX Spectrum+ s odlišnou klávesnicí (a novou klávesou Extend Mode zjednodušující zápis některých příkazů a funkcí Sinclair BASICu).

3. Základní parametry ZX Spectra

Všechny typy počítačů ZX Spectrum se v několika ohledech lišily od původních modelů ZX80 a ZX81, i když základ, tj. osmibitový mikroprocesor Zilog Z80, byl použitý ve všech počítačích firmy Sinclair (zde se jeho frekvence zvýšila na 3,5 MHz). Především došlo k rozšíření kapacity paměti ROM na 16 kB, takže bylo možné použít vylepšenou verzi Sinclair Basicu, která (kromě dalších vylepšení) obsahovala nové příkazy i funkce. Taktéž byl vylepšený způsob záznamu dat na magnetofon. Ale největší novinkou, která velkou měrou přispěla k popularitě ZX Spectra, byla upravená verze čipu ULA, jež se mimo dalších operací starala i o generování obrazu, které již bylo ve větší míře nezávislé na mikroprocesoru, než tomu bylo u počítačů ZX80 a ZX81 (takže mj. odpadla potřeba příkazů SLOW a FAST. Počítače ZX Spectrum taktéž začaly používat klasický framebuffer s jeho – pro tento počítač tak typickým a mnoho let nezměněným – rozdělením na dvě poloviny: bitmapu o rozlišení 256×192 pixelů a atributovou paměť s 32×24 bloky, v nichž bylo možné, nezávisle na ostatních blocích, měnit barvu popředí a pozadí (viz též sedmou kapitolu). Zvukový subsystém se stále skládal pouze z „beeperu“ programově ovládaného jediným bitem.

Obrázek 6: Obchodní část hry Elite přepsaná do Sinclair BASICu. Ukazuje se, že i poměrně složité aplikace lze vytvořit v na dnešní dobu primitivním a v mnoha ohledech omezeném programovacím jazyku.

Paměťový prostor ZX Spectra, tj. 64 přímo adresovatelných kilobajtů, byl rozdělen na tři části. Na začátku se nacházela oblast paměti ROM o velikosti 16 kB s interpreterem jazyka Sinclair Basic, rutinami pro výpočty s hodnotami reprezentované v pohyblivé řádové čárce apod. Za pamětí ROM bylo 16 kB RAM, do které měl přístup jak mikroprocesor, tak i čip ULA (který zde měl uložený framebuffer) a poslední oblast o kapacitě 32 kB byla dostupná pouze mikroprocesoru. V dalším textu se budeme zabývat pouze šestnáctikilobajtovou oblastí paměti RAM, do které měl přístup jak mikroprocesor, tak i čip ULA. Z hlediska programátora byla tato paměť „pomalejší“ než zbylých 32 kB, což mj. znamenalo, že se do této oblasti neumisťovaly časově náročné rutiny, například podprogramy pro přehrávání zvuků či práci s magnetofonem. Čip ULA si totiž postupně načítal hodnoty jednotlivých pixelů i příslušné barvové atributy těchto pixelů při generování video signálu. Bližší informace budou uvedeny v šesté kapitole.

Obrázek 7: Další screenshot získaný z obchodní části hry Elite přepsané do Sinclair BASICu.

4. ZX Spectrum+ 128

Následovníkem klasického ZX Spectra 48k a ZX Spectra+ byl model pojmenovaný ZX Spectrum 128 (resp. ZX Spectrum+ 128). Zatímco vzhledově se tento počítač příliš nelišil od svých předchůdců, zejména ZX Spectra+ (na pravou stranu byl ovšem přidán typický chladič), celková architektura počítače byla v několika směrech vylepšena. Především byl zvukový subsystém počítače (tj. původně pouze jednobitový „beeper“ napojený na reproduktor) rozšířen o hudební čip AY-3–8910, přesněji řečeno o jeho variantu AY-8912, která kromě zvukového výstupu obsahovala i jeden osmibitový port použitý pro připojení MIDI zařízení a externí klávesnice. Dále byla zvýšena kapacita paměti ROM ze 16 kB na 32 kB, což například umožnilo použití vylepšeného interpretru Basicu i jeho editoru, včetně menu zobrazeného po startu počítače. Kapacita paměti RAM je zakódována v samotném názvu počítače – má tedy velikost celých 128 kB.

Obrázek 8: ZX Spectrum+ 128K s typickým chladičem na pravé straně.

Částečné vylepšení doznal také grafický subsystém. Největší změnou (spíše rozšířením) bylo to, že se framebuffer mohl nacházet na dvou místech v operační paměti. To znamenalo, že se dal velmi snadno implementovat například takzvaný double buffering, tj. technika, při které se do jednoho (neviditelného) bufferu provádělo vykreslování, zatímco obsah druhého bufferu byl zobrazován (vykreslování tedy nevedlo například k nežádoucímu „sněžení“). Po vykreslení scény se funkce obou bufferů prohodily. Dva buffery bylo možné použít i pro implementaci triku GigaScreen, při kterém se na obrazovce rychle mění dva speciálně upravené obrázky.

Obrázek 9: Nově přidané menu zobrazené po startu ZX Spectra+ 128K.

Poznámka: všechny modely a podmodely ZX Spectra jsou podrobně popsány na stránce https://spectrumforeveryo­ne.com/technical/zx-spectrum-models/.

5. NES a ZX Spectrum: dvě naprosto odlišné platformy

Vzhledem k tomu, že tento článek ideově navazuje na seriál Vývoj her pro herní konzoli NES, bude zajímavé si alespoň ve stručnosti (a z důvodu této stručnosti možná ne vždy zcela přesně) porovnat základní parametry NESu a ZX Spectra. Jedná se o dvě osmibitová zařízení vydaná v přibližně stejné době (1982 resp. 1983), ovšem pro zcela odlišný segment trhu (což paradoxně nakonec nebyla pravda, protože mnozí používali ZX Spectrum jako dostupnou herní konzoli, i když se jednalo o univerzální stroj):

Vlastnost NES ZX Spectrum
Typ zařízení herní konzole univerzální domácí mikropočítač
Rok uvedení na trh 1983 1982
Popularita 62 milionů, cca 50 klonů 5 milionů originálu i navazujících modelů, cca 60 klonů (pravděpodobně i více)
     
Mikroprocesor varianta MOS 6502 původní Zilog Z80
Architektura CPU akumulátorový, čistě osmibitový registrový, kombinace 8/16 bitů, ALU operace s registrem A
Hodinová frekvence 1,66 nebo 1,79 MHz 3,5 MHz
     
Programy uloženy v ROM (cartridge) RAM (načtení z kazety/diskety)
ROM se systémem ne 16 kB (BASIC+systém)
Kapacita RAM 2kB prg+2kB video 16kB, 48kB, 128kB (některé klony 80kB)
     
Video výstup na TV TV
Norma PAL i NTSC PAL (Timex měl model s podporou NTSC)
Rozlišení grafiky 256×240 256×192
Počet barev 25 z 54 15 z 15
Způsob uložení grafických dat dlaždice v ROM + mapování dlaždic ve VRAM bitmapa i atributy v RAM
Přístup CPU ke grafickým datům nepřímo přes registry PPU přímo mapováno do adresního prostoru CPU
Bitmapová grafika ne ano (+ „blokové“ atributy)
Libovolné pozadí scény ne (dlaždice v ROM) ano s omezeními atributů
Sprity 64 nezávislých spritů ne (pouze SW sprity)
Scrolling jemný HW scrolling ne (pouze SW řešení)
Double buffering ano, ale nepotřebný ne (původní model 48k), ano (model 128k)
     
Zvukový subsystém Ricoh 2A03/2A07, MIDI (přes doplněk) beeper, AY-3–8910 (128+), MIDI (128+)
Kanály 2 obdélníkové signály, 1 trojúhelníkový, 1 šum, 1 D/A 1 kanál beeperu (1bit), 3 kanály (obdélník/šum) ayčka
     
Klávesnice ne (lze přikoupit, prakticky nepodporováno) ano
Herní ovladače ano (standard) ano (více de facto standardů), myš
     
Externí paměťová zařízení cartridge kazetový magnetofon, disketová jednotka
     
Vývojové nástroje cross assemblery a překladače interaktivní nástroje, cross assemblery a překladače
Přístup k vývoji omezený HW (ochrana cartridge) zcela volný

Obrázek 10: Super Mario Bros ve verzi pro NES.

Poznámka: v tomto miniseriálu se budeme zabývat především grafickým subsystémem ZX Spectra. Na první pohled jsou si subystémy NESu a Spectra podobné (shodné horizontální rozlišení, podobné rozlišení vertikální, atd.), ovšem programují se zcela rozdílným způsobem a i výsledky jsou vizuálně zcela odlišné. ZX Spectrum nabízí mnohem větší variabilitu grafického výstupu (například není problém si nechat vykreslit grafy), ovšem naprosto všechny grafické operace je nutné provádět programově – HW podpora prakticky neexistuje (sprity, scrolling, double buffering). I z tohoto důvodu se vizuální styl her pro NES a ZX Spectrum v mnoha směrech odlišuje (například na ZX Spectru vzniklo mnoho her s isometrickou grafikou, kdežto u NESu je jasně vidět snaha o využití „dlaždic“ v prakticky všech hrách).

Obrázek 11: Na ZX Spectru vzniklo mnoho her s isometrickou grafikou.

6. Mapa paměti ZX Spectra

Paměťový prostor původního ZX Spectra, tj. 64 přímo adresovatelných kilobajtů, byl rozdělen na tři části. Na začátku se nacházela oblast paměti ROM o velikosti 16 kB, která obsahovala interpret programovacího jazyka Sinclair Basic, rutiny pro práci v pohyblivé řádové čárce apod. Za pamětí ROM byla do adresního prostoru mikroprocesoru namapována 16 kB RAM, do které měl přístup jak mikroprocesor, tak i čip ULA (který zde měl uložený framebuffer) a poslední oblast o kapacitě 32 kB byla dostupná pouze mikroprocesoru.

Na ZX Spectru 128+ byla situace složitější, jelikož bylo nutné v paměťovém rozsahu 64 kB přepínat jak mezi dvěma ROM a dvěma oblastmi pro uložení grafiky (6144+768 bajtů), tak i nějakým způsobem zajistit přístup k celkovým 128 kilobajtům RAM. Z tohoto důvodu se používal přístup známý i z dalších typů počítačů: ROM i RAM byly rozděleny do takzvaných bank, z nichž každá měla kapacitu 16 kB. A tyto banky se mapovaly do čtyř adresovatelných oblastí, a to takovým způsobem, aby byla zajištěna kompatibilita s původním ZX Spectrem 48k. Podobně byly paměťové stránky využity i na dalších klonech ZX Spectra, například na Didaktiku Gama apod.

Konkrétně vypadá mapování z pohledu mikroprocesoru následovně:

ZX Spectrum 48k:

16kB ROM
16kB RAM (s Video RAM)
32kB RAM

ZX Spectrum 128K:

16kB originální ROM nebo 16kB 128 ROM
16kB RAM stránka 5 (s Video RAM)
16kB RAM stránka 2
16kB RAM stránka 0 až 7 (podle výběru)
Poznámka: zde tedy přepínání stránek probíhalo po 16kB, což je (zdá se) ideální hodnota.

Video RAM je buď umístěna na stránce 5 nebo na stránce 7 (může být tedy přesunuta „výše“ z pohledu adresního režimu mikroprocesoru)..

Didaktik Gama:

16kB ROM
16kB RAM (s Video RAM)
32kB RAM stránky 1+2 nebo stránky 3+4
Poznámka: zde přepínání stránek probíhalo po celých 32kB, což je již příliš velká granularita, která navíc mohla způsobovat problémy při programování v BASICu.

Existují i další možnosti rozšíření paměti, například podle Lamače (až do 528 kB) nebo podle Trollera (dalších 32 kB). My se však budeme minimálně v úvodních článcích soustředit pouze na původní ZX Spectrum 48k.

7. Grafický režim ZX Spectra

Obraz zobrazený na televizoru se skládal z okraje (border) a bitmapy. U okraje bylo možné pouze měnit jeho barvu, ale nemohl obsahovat žádné další grafické informace (což nebyla zcela pravda, protože rychlá změna barvy dokázala na okraji „vykouzlit“ pruhy). Zobrazovaná bitmapa měla rozlišení 256×192 pixelů, což znamená, že její paměťové požadavky lze snadno vypočítat: 256×192/8=6144 bajtů. Každý pixel byl v této bitmapě reprezentován jediným bitem, kterým se volilo, zda se jedná o pixel patřící k popředí (ink) či k pozadí (paper). Barvy popředí a pozadí nemohly být nastaveny pro každý pixel zvlášť, ale pouze pro celý blok 8×8 pixelů. Pro tento blok se v jednom bajtu zvaném atribut ukládaly jak informace o popředí a pozadí (k dispozici bylo osm základních barev, tj. jejich indexy bylo možné uložit ve třech bitech), tak i intenzita barev (vyšší/nižší) a příznak, zda má celý blok blikat, tj. periodicky měnit barvu popředí a pozadí.

Obrázek 12: Na obrázku hry Barbarian je poměrně dobře patrné, jakým způsobem je obrazová paměť organizovaná, především omezení daná atributy o velikosti 8×8 pixelů.

bitcoin_skoleni

Atributů bylo celkem 32×24=768, takže celková kapacita paměti pro uložení celého obrázku byla rovna 6144+768=6912 bajtům, což zhruba odpovídá typické kapacitě framebufferů u domácích osmibitových počítačů (větší framebuffery byly nepraktické, protože zabíraly velkou část drahé operační paměti a taktéž by tehdejší mikroprocesory musely provádět přesuny objemnějších bloků dat při změně obrazu, menší framebuffery pak vedly k omezenému rozlišení a/nebo počtu barev). Frekvence mikroprocesoru Zilog Z80, tj. 3,5 MHz nebyla zvolena náhodně. Přesně totiž odpovídá počtu taktů nutných pro generování video signálu pro televize pracující v normě PAL.

Obrázek 13: Při pečlivé práci je možné omezení představovaná atributy do značné míry obejít, jak dokazuje tato bitmapa pro ZX Spectrum.

Poznámka: způsob uspořádání grafické paměti do značné míry ovlivnil vzhled i chování her naprogramovaných pro ZX Spectrum. Můžeme zde vidět značnou odlišnost v porovnání s hrami pro Atari či Commodore C64 způsobenou nutnosti softwarově řízeného scrollování, absencí spritů či pseudografických režimů 12 a 13 známých a používaných u Atari. Rozdíly jsou ovšem patrné i při pohledu na zcela statické obrázky z některých textovek:

Obrázek 14: Textovka Red Moon pro ZX Spectrum.

Obrázek 15: Textovka Red Moon pro osmibitová Atari.

Některé důležité adresy, které souvisí s grafickou pamětí ZX Spectra (všechny adresy jsou uvedeny hexadecimálně, délka dekadicky):


Od Do Délka Stručný popis
4000 47ff 2048 prvních 64 obrazových řádků
4800 5000 2048 obrazové řádky 64–127
5000 57ff 2048 obrazové řádky 128–191
5800 5aff 768 32×24=768 atributů

Poznámka: obrazové řádky v každé skupině nejsou uloženy za sebou, ale v prokládaném formátu vyžadovaném čipem ULA při vykreslování na obrazovku (ULA totiž musí provést přístup jak do bitmapy, tak i do atributové paměti). Tento formát si podrobně popíšeme příště a je dobře viditelný při (pomalém) nahrávání obsahu obrazové paměti z kazety.

Obrázek 16: Známá textovka Adventure pro ZX Spectrum.

Obrázek 17: Známá textovka Adventure pro osmibitová Atari.

8. Slavný osmibitový mikroprocesor Zilog Z80

ZX Spectrum je, podobně jako jeho předchůdci ZX80 a ZX81, postaveno na dvojici čipů: mikroprocesoru Zilog Z80 a ULA. Jako programátoři se přímo setkáme především se Z80. Jedná se o mikroprocesor, který je zpětně kompatibilní s mikroprocesorem Intel 8080 (viz jeho stručnou historii uvedenou níže), ovšem přináší mnoho důležitých změn, a to jak pro programátory (nové pracovní registry a strojové instrukce), tak i pro konstruktéry počítačů (jedno napájecí napětí, podpora pro obnovu obsahu dynamických pamětí).

V roce 1972, tj. pouhých pět měsíců po uvedení 4004 (to se nám to zrychluje) představila společnost Intel jeho osmibitového nástupce. Jednalo se o mikroprocesor Intel 8008. V jeho instrukční sadě se již mnoho programátorů bez problému vyzná, protože po rozšíření se s ní můžeme setkat i v 8080 a Z80. Tento čip již při použití stejné desetimikronové technologie obsahoval 3500 tranzistorů, pracoval na frekvenci 800 kHz a mohl adresovat až 16 kB paměti (kombinace ROM se statickou RAM). Samotný výpočetní výkon byl oproti 4004 skoro dvojnásobný, především však byla použita osmibitová sběrnice a řada podpůrných obvodů, se kterými se můžeme setkat i u pozdějších procesorů.

Za dva roky poté, tj. v roce 1974, Intel uvedl další procesor nazvaný Intel 8080. Ten již pracoval s hodinovou frekvencí 2 MHz, obsahoval cca 4500 tranzistorů a mohl adresovat až 64 kB paměti (+ periferie adresované mimo hlavní RAM+ROM). Jednou z předností tohoto procesoru bylo použití nové třímikronové technologie výroby. Intel 8080 byl použit v mnoha počítačích (Altair 8800), i když ke své práci potřeboval kromě standardního pětivoltového napájení ještě jedno vyšší napětí (pro oscilátory) a také dva podpůrné obvody – 8224 a 8228. Jednou ze zajímavostí je, že se tento mikroprocesor vyráběl i v naší Tesle pod označením MHB 8080A (dlužno ovšem říci, že v době, kdy se ve světě přecházelo na šestnáctibitové a třicetidvoubitové mikroprocesory).

Federico Faggin, jenž byl spolutvůrcem čipu 4004, 8008 i 8080, v roce 1974 z Intelu odešel a společně s Ralphem Ungermannem založil společnost Zilog. O rok později se k Zilogu přidal i další ex-zaměstnanec Intelu: Masatoshi Shima. A společnost Zilog v červenci 1976 vydala svůj doposud nejslavnější produkt – osmibitový mikroprocesor Zilog Z80.

Co se týče popularity, tak byl mikroprocesor Zilog Z80 více než úspěšným soupeřem MOS 6502.. Mikroprocesor Z80 je vlastně podstatně vylepšenou variantou čipu Intel 8080, se kterou byl zpětně kompatibilní, což bylo v té době docela nezvyklé, ovšem o to užitečnější.

Oproti původnímu čipu Intel 8080 byla rozšířena jak instrukční sada (blokové operace, operace s šestnáctibitovými operandy, bitové instrukce), tak i sada pracovních registrů, bylo použito pouze jedno napájecí napětí (už to dokázalo podstatně snížit cenu a zvýšit spolehlivost celého počítače) a především sám procesor dokázal obnovovat dynamické paměti bez pomoci dalších obvodů. Spolu s poměrně vysokou rychlostí (originál pracoval na 2,5 MHz, pozdější verze mohly být taktovány až 8 MHz a CMOS verze 10 MHz) a rozumnou cenou se jednalo o mikroprocesor, který byl použit v mnoha osobních i domácích počítačích, například TRS-80 a především legendárních počítačích ZX-80, ZX-81 a ZX-Spectru (speccy). Ovšem Z80 se používal i v mnoha herních automatech (mnohdy bylo dokonce použito více čipů běžících souběžně) i v mnoha průmyslových systémech a po vzniku CP/M se na chvíli stal v této oblasti standardem.

9. Assemblery a cross assemblery pro ZX Spectrum a jeho následovníky

Vraťme se nyní zpět k ZX Spectru a k vývojovým prostředkům, které pro tento velmi populární domácí mikropočítač vznikly. Zajímat nás budou především assemblery. Těch přímo pro ZX Spectrum vzniklo minimálně několik desítek a lišily se od sebe jak svými možnostmi, tak i způsobem zápisu (popř. i ladění programů), ale například i tím, zda bylo možné vlastní assembler (a editor) přesunout v operační paměti na jiné místo. Z těch známějších assemblerů jmenujme například Zeus, HiSoft Assembler či propracovaný tuzemský Prometheus od Proximy.

Obrázek 18: Obal na kazetu se Zeus Assemblerem určeným pro slavné ZX Spectrum.

Tyto assemblery, které byly provozovány přímo na ZX Spectru, samozřejmě poněkud omezovaly tvůrce „v rozletu“, protože paměť obsazená assemblerem a zdrojovým kódem nebyla využitelná výsledným programem. A pochopitelně vývoj a ladění na obrazovce s 24 textovými řádky a 32 znaky na řádku taktéž nemusí každému vyhovovat, zejména v současnosti, kdy máme k dispozici mnohdy obrovské monitory. A konečně – pád aplikace či její nekorektní chování mohly přepsat samotný assembler a editovaný program, takže se muselo začít od začátku (či od posledního „save“).

Obrázek 19: Vývojové prostředí Zeus Assembleru.

Z tohoto důvodu použijeme cross assembler, tj. assembler běžící přímo na PC, který produkuje buď obraz paměti ZX Spectra nebo obraz záznamu na magnetofonové pásce. Ten bude možné načíst do emulátoru či nahrát na reálné ZX Spectrum (stále se dá pořídit).

Obrázek 20: Uvítací obrazovka HiSoft Assembleru.

Obrázek 21: HiSoft Assembler.

Obrázek 22: Slavný Prometheus od Proximy.

Obrázek 23: Slavný Prometheus od Proximy.

Obrázek 24: Verze Promethea pro ZX Spectrum 128k.

10. Instalace assembleru a emulátoru ZX Spectra

Pro vývoj pro ZX Spectrum je zapotřebí minimum prostředků:

  1. Programátorský textový editor (libovolný)
  2. Cross assembler
  3. Emulátor ZX Spectra
  4. Debugger (bývá součástí emulátoru)

Cross assemblerů pro ZX Spectrum existuje větší množství. V tomto (mini)seriálu použijeme assembler nazvaný Pasmo, mezi jehož užitečné vlastnosti patří fakt, že dokáže generovat přímo obrazy programu tak, jak jsou uloženy na kazetě a dokonce pro programátora dokáže připravit BASICovský „loader“, jenž zajistí automatické načtení a popř. i spuštění programu.

Assembler Pasmo je možné nalézt ve standardních balíčcích, takže jeho instalace je přímočará (zde uvádím instalaci pro Linux Mint, ovšem na jiných distribucích bude průběh podobný):


$ sudo apt-get install pasmo
 
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following NEW packages will be installed:
  pasmo
0 upgraded, 1 newly installed, 0 to remove and 4 not upgraded.
Need to get 124 kB of archives.
After this operation, 380 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu focal/universe amd64 pasmo amd64 0.5.3-6build2 [124 kB]
Fetched 124 kB in 1s (117 kB/s)
Selecting previously unselected package pasmo.
(Reading database ... 293573 files and directories currently installed.)
Preparing to unpack .../pasmo_0.5.3-6build2_amd64.deb ...
Unpacking pasmo (0.5.3-6build2) ...
Setting up pasmo (0.5.3-6build2) ...
Processing triggers for man-db (2.9.1-1) ...
Processing triggers for doc-base (0.10.9) ...
Processing 1 added doc-base file...

Nainstalujeme si i emulátor ZX Spectra. Těch opět existuje velké množství. Z této velké nabídky jsem vybral Fuse neboli Free Unix Spectrum Emulator (Fuse), který mj. obsahuje i vestavěný debugger. Fuse bývá doplněn o GUI vytvořené v Gnome nebo zobrazované přímo přes SDL. Nainstalujme si druhou variantu, tedy Fuse, jehož GUI je naprogramováno v SDL:


$ sudo apt-get install fuse-emulator-sdl
 
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
  fuse-emulator-common libaudiofile1 libspectrum8 opense-basic
Suggested packages:
  spectrum-roms fuse-emulator-utils
The following NEW packages will be installed:
  fuse-emulator-common fuse-emulator-sdl libaudiofile1 libspectrum8
  opense-basic
0 upgraded, 5 newly installed, 0 to remove and 4 not upgraded.
Need to get 898 kB of archives.
After this operation, 2 482 kB of additional disk space will be used.
Do you want to continue? [Y/n] y

Poznámka: emulátor obsahuje i OpenSE BASIC, který nahrazuje originální licencovaný hardware (viz 1). To znamená, že i přes určité rozdíly bude možné naše demonstrační programy načíst a spustit.

11. První program v assembleru: změna barvového atributu v levém horním rohu obrazovky

Náš zcela první program napsaný v čistém assembleru bude velmi jednoduchý a nepřímo si na něm ukážeme, jak blízko má na ZX Spectru programátor k hardwaru tohoto osmibitového mikropočítače. Tento program po svém spuštění změní hodnotu bajtu uloženého na adrese 0×5800. Pokud se podíváme na tabulku uvedenou v sedmé kapitole, zjistíme, že se na této adrese nachází první barvový atribut, tj. bajt obsahující informace o tom, jakou barvu popředí a pozadí mají mít pixely v prvním bloku 8×8 pixelů vlevo nahoře.

Jednotlivé bity v atributovém bajtu mají následující význam:


Bit(y) Význam
7 povolení periodické změny barvy popředí a pozadí (flash)
6 povolení vyšší intenzity barvy
5..3 barva pozadí (paper, background)
2..0 barva popředí (ink, foreground)

A konečně si musíme uvést kódy barev pozadí a popředí. ZX Spectrum rozpoznává osm barev (proto jejich indexy zaberou jen tři bity) a zvolit lze mezi standardní a vyšší intenzitou:


Index Binárně Barva
0 000 černá
1 001 modrá
2 010 červená
3 011 fialová
4 100 zelená
5 101 azurová
6 110 žlutá
7 111 šedá/bílá

Poznámka: u černé barvy se nerozlišuje intenzita (což je škoda, protože by bylo možné mít čtyři úrovně šedi), proto má ZX Spectrum jen 15 barev a nikoli 16.

12. Zápis zdrojového kódu prvního příkladu

Podívejme se nyní na způsob zápisu zdrojového kódu dnešního prvního demonstračního příkladu. Pro zápis v assembleru Z80 se používá stejný formát, jaký jsme viděli u NESu a mikroprocesoru MOS 6502: na začátku řádků se zapisují návěští (label), zatímco o tabulační zarážku dále (nebo na cca osmém sloupci) začínají mnemotechnické zkratky instrukcí popř. direktivy assembleru.

Zápis začíná direktivou org se specifikací počáteční adresy programu. Pro jednoduchost bude program v operační paměti uložen od adresy 0×8000, tj. 32768 dekadicky – viz též šestou kapitolu s mapou paměti. Následuje návěští start (vlastně ho nebudeme potřebovat) a sekvence tří strojových instrukcí:

  1. Načtení osmibitové konstanty 0b00010000 (zapsané binárně) do pracovního registru A (konstanta odpovídá červené barvě pozadí)
  2. Uložení hodnoty registru A na adresu 0×5800
  3. Návrat do volajícího kódu instrukcí RETurn

V assembleru se tento prográmek zapíše takto:


        org $8000
 
start:
        ld a,%00010000
        ld ($5800),a
        ret

Poznámka: povšimněte si, kterým znakem se uvozují binární (dvojkové) hodnoty a hexadecimální hodnoty. Tyto znaky budeme používat i v dalších demonstračních příkladech.

13. Překlad do strojového kódu a uložení výsledku ve formátu tap

Překlad výše uvedeného kódu napsaného v assembleru do strojového kódu je snadný. K tomuto účelu použijeme assembler pasmo, kterému předáme přepínač –tap, aby výsledkem překladu byl soubor s obrazem magnetofonového záznamu, který bude mít koncovku „.tap“. Současně si necháme „vylistovat“ výsledek do souboru s koncovkou „.lst“:


$ pasmo -v -d --tap 01-color-attribute.asm 01.tap >01.lst

Assembler vypíše průběh překladu, z něhož je patrné, že se použily dva průchody – první pro zjištění adres s vygenerováním mezikódu, druhý pro doplnění všech adres do výsledného binárního kódu:


Loading file: 01-color-attribute.asm in 0
Finished loading file: 01-color-attribute.asm in 6
Entering pass 1
Pass 1 finished
Entering pass 2
Pass 2 finished

A takto vypadá soubor „01.lst“, který obsahuje výsledek překladu v čitelné podobě, a to již s expandovanými makry, doplněnými symboly a vypočtenými adresami. U každého řádku je rovněž v hexadecimální podobě vypsán odpovídající strojový kód:


                ORG 8000
8000:           label start
8000:3E10       LD A, 10
8002:320058     LD (5800), A
8005:C9         RET
Emiting TAP from 8000 to 8005

Poznámka: délka výsledného strojového kódu je tedy rovna šesti bajtům.

14. Načtení a spuštění příkladu v emulátoru ZX Spectra s originální licencovanou ROM

Nejjednodušší cestou, jak program načíst a spustit spočívá v tom, že při spuštění emulátoru ZX Spectra zadáme i jméno souboru s obrazem magnetofonové pásky:


$ fuse-sdl 01.tap

Nyní se bude chování emulátoru lišit podle toho, zda je použita originální ROM či nikoli. Nejdříve si ukažme, jak se program spustí při použití originální ROM:

Obrázek 25: Emulátor již program načetl do operační paměti.

Nyní na klávesnici stiskneme klávesy T (vypíše se „RANDOMIZE“), Tab L (dopíše se „USR“) a 32768:

Obrázek 26: Zadáme příkaz RANDOMIZE USR 32768. Jedná se o volání funkce USR s adresou 32768, tedy se žádostí o volání kódu uloženého na této adrese. Ovšem v Sinclair BASICu nelze volat funkci bez využití jejího výsledku; proto je nutné výsledek použít například v příkazu RANDOMIZE nebo PRINT.

Po stisku klávesy Enter se program spustí a změní atribut v levém horním rohu. Poté se vrátí zpět do BASICu:

Obrázek 27: Změna atributu v levém horním rohu.

15. Načtení a spuštění příkladu s využitím OpenSE BASICu

Pokud použijeme ROM OpenSE BASIC se svobodnou licencí, bude postup nepatrně odlišný:

Obrázek 28: Úvodní obrazovka emulátoru ve chvíli, kdy se použije OpenSE BASIC.

Obrázek 29: Napíšeme příkaz load ""code. V OpenSE BASICu se klávesnice používá stejně, jako na PC (tedy co stisk, to jeden znak), ovšem uvozovky se musí psát přes Alt+P. Přímo v emulátoru si z menu Help můžete zobrazit klávesnici ZX Spectra se všemi symboly.

Obrázek 30: Nyní byl program načten a uložen do paměti od adresy 32768.

Obrázek 31: Napíšeme, nyní již znak po znaku, nám již známý příkaz RANDOMIZE USR 32768.

Obrázek 32: Po potvrzení příkazu se program spustí a atribut v levé horní části obrazovky se změní.

16. Zobrazení blikajícího čtverečku

Nyní využijeme jednu unikátní vlastnost ZX Spectra. Jedná se o automatickou a periodicky prováděnou záměnu atributu barvy popředí a pozadí v případě, že je nejvyšší bit příslušného atributu nastaven na jedničku. Z tohoto důvodu předchozí demonstrační příklad nepatrně upravíme, a to takovým způsobem, že první atribut v levém horním rohu nastavíme na binární hodnotu 11010110. Rozklíčování, co tato hodnota znamená, je snadné, protože již máme k dispozici všechny potřebné informace (viz dvě tabulky uvedené v jedenácté kapitole):


1 1 0 1 0 1 1 0
| |  \ /   \ /
| |   |     |
| |   |     +------- barva popředí je žlutá
| |   |
| |   +------------- barva pozadí je červená
| |
| +----------------- povolení vyšší intenzity barvy
|
+------------------- povolení periodické změny barvy popředí a pozadí (flash)

Zdrojový kód příkladu se změní jen nepatrně:


        org $8000

start:
        ld a,%11010110
        ld ($5800),a
        ret

Délka výsledného strojového kódu ani délka souboru s obrazem kazety se nijak nezmění:


                ORG 8000
8000:           label start
8000:3ED6       LD A, D6
8002:320058     LD (5800), A
8005:C9         RET
Emiting TAP from 8000 to 8005

Podívejme se v krátkosti na výsledek:

Obrázek 33: Blikající atribut v levém horním rohu obrazovky.

Obrázek 34: Blikající atribut v levém horním rohu obrazovky.

Poznámka: na pěti řádcích zdrojového kódu (pouze 54 bajtů) a šesti bajtech strojového kódu je realizován program, který by při použití moderních prostředků musel být minimálně o řád větší a složitější (spíše však o několik řádů). I v tom spočívá kouzlo minimalismu osmibitových mikropočítačů a herních konzolí.

17. Symbolické hodnoty namísto konkrétních adres

Assembler Pasmo, podobně jako všechny moderní assemblery, umožňuje adresy a popř. i další hodnoty, které se v programech používají, pojmenovat. U některých assemblerů se symbolická konstanta vytvoří definicí symbol=hodnota, v případě assembleru Pasmo (a mnohých dalších assemblerů) se používá direktiva equ, tedy zápis symbol equ hodnota.

Předchozí zdrojový kód tedy můžeme upravit do podoby, v níž se používá jen jediná „magická“ konstanta:


attribute_adr equ $5800
entry_point   equ $8000
 
 
        org entry_point
 
start:
        ld a,%11010110
        ld (attribute_adr),a
        ret

V průběhu překladu do strojového kódu je patrné, jak se symbolické hodnoty nahrazují hodnotami konkrétními:


attribute_adr   EQU 5800
entry_point     EQU 8000
                ORG 8000
8000:           label start
8000:3ED6       LD A, D6
8002:320058     LD (5800), A
8005:C9         RET
Emiting TAP from 8000 to 8005

Poznámka: výsledkem bude naprosto totožný strojový kód i shodný obraz kazety.

18. Soubor Makefile pro překlad demonstračních příkladů

Výše uvedené příklady i demonstrační příklady, které si popíšeme až příště, lze přeložit s využitím souboru Makefile, jehož aktuální verze vypadá následovně:


ASSEMBLER := pasmo
 
all: 01.tap 02.tap 03.tap 04.tap 05.tap 06.tap 07.tap
 
clean:
        rm -f *.tap
 
.PHONY: all clean
 
01.tap: 01-color-attribute.asm
        $(ASSEMBLER) -v -d --tap $< $@ > 01-color-attribute.lst
 
02.tap: 02-blinking-attribute.asm
        $(ASSEMBLER) -v -d --tap $< $@ > 02-blinking-attribute.lst
 
03.tap: 03-symbolic-names.asm
        $(ASSEMBLER) -v -d --tap $< $@ > 03-symbolic-names.lst
 
04.tap: 04-operators.asm
        $(ASSEMBLER) -v -d --tap $< $@ > 04-operators.lst
 
05.tap: 05-better-symbols.asm
        $(ASSEMBLER) -v -d --tap $< $@ > 05-better-symbols.lst
 
06.tap: 06-tapbas-v1.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 06-tapbas-v1.lst
 
07.tap: 07-tapbas-v2.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 07-tapbas-v2.lst

19. Repositář s demonstračními příklady

V tabulce zobrazené pod tímto odstavcem jsou uvedeny odkazy na všechny prozatím popsané (ale i nepopsané) demonstrační příklady určené pro překlad a spuštění na osmibitovém domácím mikropočítači ZX Spectrum (libovolný model či jeho klon), které jsou psány v assembleru mikroprocesoru Zilog Z80. Pro překlad těchto demonstračních příkladů je možné použít například assembler Pasmo:


# Soubor Stručný popis Adresa
1 01-color-attribute.asm modifikace jednoho barvového atributu https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/01-color-attribute.asm
2 02-blinking-attribute.asm barvový atribut s nastavením bitů pro blikání a vyšší intenzitu https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/02-blinking-attribute.asm
3 03-symbolic-names.asm symbolická jména v assembleru https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/03-symbolic-names.asm
4 04-operators.asm operátory a operace se symbolickými hodnotami https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/04-operators.asm
5 05-better-symbols.asm tradičnější symbolická jména https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/05-better-symbols.asm
6 06-tapbas-v1.asm vygenerování BASICovského loaderu (neúplný příklad) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/06-tapbas-v1.asm
7 07-tapbas-v2.asm vygenerování BASICovského loaderu (úplný příklad) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/07-tapbas-v2.asm
       
8 Makefile Makefile pro překlad a slinkování všech příkladů https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/Makefile

20. Odkazy na Internetu

  1. z80 standalone assembler
    https://www.asm80.com/one­page/asmz80.html
  2. The ZX BASIC Compiler
    https://www.boriel.com/pages/the-zx-basic-compiler.html
  3. Z80 Assembly programming for the ZX Spectrum
    https://www.chibiakumas.com/z80/ZXSpec­trum.php
  4. 8-BIT SMACKDOWN! 65C02 vs. Z80: slithy VLOGS #6
    https://www.youtube.com/wat­ch?v=P1paVoFEvyc
  5. Instrukce mikroprocesoru Z80
    https://clrhome.org/table/
  6. Z80 instructions: adresní režimy atd.
    https://jnz.dk/z80/instructions.html
  7. Z80 Instruction Groups
    https://jnz.dk/z80/instgroups.html
  8. Elena, New programming language for the ZX Spectrum Next
    https://vintageisthenewold.com/elena-new-programming-language-for-the-zx-spectrum-next/
  9. Sinclair BASIC
    https://worldofspectrum.net/legacy-info/sinclair-basic/
  10. Grafika na osmibitových počítačích firmy Sinclair
    https://www.root.cz/clanky/grafika-na-osmibitovych-pocitacich-firmy-sinclair/
  11. Grafika na osmibitových počítačích firmy Sinclair II
    https://www.root.cz/clanky/grafika-na-osmibitovych-pocitacich-firmy-sinclair-ii/
  12. HiSoft BASIC
    https://worldofspectrum.net/in­foseekid.cgi?id=0008249
  13. YS MegaBasic
    https://worldofspectrum.net/in­foseekid.cgi?id=0008997
  14. Beta Basic
    https://worldofspectrum.net/in­foseekid.cgi?id=0007956
  15. BASIC+
    https://worldofspectrum.net/in­foseekid.php?id=0014277
  16. Spectrum ROM Memory Map
    https://skoolkit.ca/disas­semblies/rom/maps/all.html
  17. Goto subroutine
    https://skoolkit.ca/disas­semblies/rom/asm/7783.html
  18. Spectrum Next: The Evolution of the Speccy
    https://www.specnext.com/about/
  19. Sedmdesátiny assemblerů: lidsky čitelný strojový kód
    https://www.root.cz/clanky/sed­mdesatiny-assembleru-lidsky-citelny-strojovy-kod/
  20. Programovací jazyk BASIC na osmibitových mikropočítačích
    https://www.root.cz/clanky/pro­gramovaci-jazyk-basic-na-osmibitovych-mikropocitacich/
  21. Programovací jazyk BASIC na osmibitových mikropočítačích (2)
    https://www.root.cz/clanky/pro­gramovaci-jazyk-basic-na-osmibitovych-mikropocitacich-2/#k06
  22. Programovací jazyk BASIC na osmibitových mikropočítačích (3)
    https://www.root.cz/clanky/pro­gramovaci-jazyk-basic-na-osmibitovych-mikropocitacich-3/
  23. Sinclair BASIC (Wikipedia CZ)
    http://cs.wikipedia.org/wi­ki/Sinclair_BASIC
  24. Assembly Language: Still Relevant Today
    http://wilsonminesco.com/AssyDefense/
  25. Programovani v assembleru na OS Linux
    http://www.cs.vsb.cz/gryga­rek/asm/asmlinux.html
  26. Why Assembly Language Programming? (Why Learning Assembly Language Is Still a Good Idea)
    https://wdc65×x.com/market­s/education/why-assembly-language-programming/
  27. Low Fat Computing
    http://www.ultratechnology­.com/lowfat.htm
  28. Assembly Language
    https://www.cleverism.com/skills-and-tools/assembly-language/
  29. Why do we need assembly language?
    https://cs.stackexchange.com/qu­estions/13287/why-do-we-need-assembly-language
  30. Assembly language (Wikipedia)
    https://en.wikipedia.org/wi­ki/Assembly_language#Histo­rical_perspective
  31. Assembly languages
    https://curlie.org/Computer­s/Programming/Languages/As­sembly/
  32. vasm
    http://sun.hasenbraten.de/vasm/
  33. B-ELITE
    https://jsj.itch.io/b-elite
  34. ZX-Spectrum Child
    http://www.dotkam.com/2008/11/19/zx-spectrum-child/
  35. Speccy.cz
    http://www.speccy.cz/
  36. Planet Sinclair
    http://www.nvg.ntnu.no/sinclair/
  37. World of Spectrum
    http://www.worldofspectrum.org/
  38. Z80 Assembly Language for the ZX Spectrum Tutorial, Episode 1: The Basics
    https://www.youtube.com/wat­ch?v=_J4ahkWtNYw
  39. Z80 assembly resources when starting programming in assembler
    https://www.youtube.com/wat­ch?v=mjLHSnQmHV4
  40. Setting up Visual Studio Code with Pasmo, Sprite Example ZX Spectrum Next
    https://www.youtube.com/wat­ch?v=lKDaFWPObLY
  41. RetroCoder ZX Spectrum development (Z80 Assembly)- Day 1 – Hello World.asm
    https://www.youtube.com/watch?v=Xv6NAC–x24
  42. Rozšíření paměti
    https://wiki.ilnx.cz/doku­.php/lnxspectrum:memorymap
  43. ZX-Spectrum 48K video memory map
    https://www.reddit.com/r/zxspec­trum/comments/phi7lt/zxspec­trum_48k_video_memory_map/
  44. Memory Map: 48K Spectrum
    http://www.breakintoprogram­.co.uk/hardware/computers/zx-spectrum/memory-map
  45. ZX Basic: Git repository
    https://github.com/boriel/zxbasic
  46. ZX Basic Wiki
    https://zxbasic.readthedoc­s.io/en/docs/
  47. ZX Spectrum Games: svět osmibitové herní legendy
    https://www.zx-spectrum.cz/
  48. TAP format
    https://sinclair.wiki.zxnet­.co.uk/wiki/TAP_format
  49. Contended memory
    https://worldofspectrum.or­g/faq/reference/48kreferen­ce.htm#Contention
  50. Screen Memory Layout
    http://www.breakintoprogram­.co.uk/hardware/computers/zx-spectrum/screen-memory-layout
  51. OpenSE BASIC
    https://zxdesign.itch.io/opense
  52. Domácí a školní mikropočítače řady Didaktik
    https://www.root.cz/clanky/domaci-a-skolni-mikropocitace-rady-didaktik/

Autor článku

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