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
5. NES a ZX Spectrum: dvě naprosto odlišné platformy
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
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.
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.
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.
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)
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
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ů.
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.
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ů |
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ů:
- Programátorský textový editor (libovolný)
- Cross assembler
- Emulátor ZX Spectra
- 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
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á |
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í:
- Načtení osmibitové konstanty 0b00010000 (zapsané binárně) do pracovního registru A (konstanta odpovídá červené barvě pozadí)
- Uložení hodnoty registru A na adresu 0×5800
- 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
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
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.
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
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:
20. Odkazy na Internetu
- z80 standalone assembler
https://www.asm80.com/onepage/asmz80.html - The ZX BASIC Compiler
https://www.boriel.com/pages/the-zx-basic-compiler.html - Z80 Assembly programming for the ZX Spectrum
https://www.chibiakumas.com/z80/ZXSpectrum.php - 8-BIT SMACKDOWN! 65C02 vs. Z80: slithy VLOGS #6
https://www.youtube.com/watch?v=P1paVoFEvyc - Instrukce mikroprocesoru Z80
https://clrhome.org/table/ - Z80 instructions: adresní režimy atd.
https://jnz.dk/z80/instructions.html - Z80 Instruction Groups
https://jnz.dk/z80/instgroups.html - Elena, New programming language for the ZX Spectrum Next
https://vintageisthenewold.com/elena-new-programming-language-for-the-zx-spectrum-next/ - Sinclair BASIC
https://worldofspectrum.net/legacy-info/sinclair-basic/ - Grafika na osmibitových počítačích firmy Sinclair
https://www.root.cz/clanky/grafika-na-osmibitovych-pocitacich-firmy-sinclair/ - Grafika na osmibitových počítačích firmy Sinclair II
https://www.root.cz/clanky/grafika-na-osmibitovych-pocitacich-firmy-sinclair-ii/ - HiSoft BASIC
https://worldofspectrum.net/infoseekid.cgi?id=0008249 - YS MegaBasic
https://worldofspectrum.net/infoseekid.cgi?id=0008997 - Beta Basic
https://worldofspectrum.net/infoseekid.cgi?id=0007956 - BASIC+
https://worldofspectrum.net/infoseekid.php?id=0014277 - Spectrum ROM Memory Map
https://skoolkit.ca/disassemblies/rom/maps/all.html - Goto subroutine
https://skoolkit.ca/disassemblies/rom/asm/7783.html - Spectrum Next: The Evolution of the Speccy
https://www.specnext.com/about/ - Sedmdesátiny assemblerů: lidsky čitelný strojový kód
https://www.root.cz/clanky/sedmdesatiny-assembleru-lidsky-citelny-strojovy-kod/ - Programovací jazyk BASIC na osmibitových mikropočítačích
https://www.root.cz/clanky/programovaci-jazyk-basic-na-osmibitovych-mikropocitacich/ - Programovací jazyk BASIC na osmibitových mikropočítačích (2)
https://www.root.cz/clanky/programovaci-jazyk-basic-na-osmibitovych-mikropocitacich-2/#k06 - Programovací jazyk BASIC na osmibitových mikropočítačích (3)
https://www.root.cz/clanky/programovaci-jazyk-basic-na-osmibitovych-mikropocitacich-3/ - Sinclair BASIC (Wikipedia CZ)
http://cs.wikipedia.org/wiki/Sinclair_BASIC - Assembly Language: Still Relevant Today
http://wilsonminesco.com/AssyDefense/ - Programovani v assembleru na OS Linux
http://www.cs.vsb.cz/grygarek/asm/asmlinux.html - Why Assembly Language Programming? (Why Learning Assembly Language Is Still a Good Idea)
https://wdc65×x.com/markets/education/why-assembly-language-programming/ - Low Fat Computing
http://www.ultratechnology.com/lowfat.htm - Assembly Language
https://www.cleverism.com/skills-and-tools/assembly-language/ - Why do we need assembly language?
https://cs.stackexchange.com/questions/13287/why-do-we-need-assembly-language - Assembly language (Wikipedia)
https://en.wikipedia.org/wiki/Assembly_language#Historical_perspective - Assembly languages
https://curlie.org/Computers/Programming/Languages/Assembly/ - vasm
http://sun.hasenbraten.de/vasm/ - B-ELITE
https://jsj.itch.io/b-elite - ZX-Spectrum Child
http://www.dotkam.com/2008/11/19/zx-spectrum-child/ - Speccy.cz
http://www.speccy.cz/ - Planet Sinclair
http://www.nvg.ntnu.no/sinclair/ - World of Spectrum
http://www.worldofspectrum.org/ - Z80 Assembly Language for the ZX Spectrum Tutorial, Episode 1: The Basics
https://www.youtube.com/watch?v=_J4ahkWtNYw - Z80 assembly resources when starting programming in assembler
https://www.youtube.com/watch?v=mjLHSnQmHV4 - Setting up Visual Studio Code with Pasmo, Sprite Example ZX Spectrum Next
https://www.youtube.com/watch?v=lKDaFWPObLY - RetroCoder ZX Spectrum development (Z80 Assembly)- Day 1 – Hello World.asm
https://www.youtube.com/watch?v=Xv6NAC–x24 - Rozšíření paměti
https://wiki.ilnx.cz/doku.php/lnxspectrum:memorymap - ZX-Spectrum 48K video memory map
https://www.reddit.com/r/zxspectrum/comments/phi7lt/zxspectrum_48k_video_memory_map/ - Memory Map: 48K Spectrum
http://www.breakintoprogram.co.uk/hardware/computers/zx-spectrum/memory-map - ZX Basic: Git repository
https://github.com/boriel/zxbasic - ZX Basic Wiki
https://zxbasic.readthedocs.io/en/docs/ - ZX Spectrum Games: svět osmibitové herní legendy
https://www.zx-spectrum.cz/ - TAP format
https://sinclair.wiki.zxnet.co.uk/wiki/TAP_format - Contended memory
https://worldofspectrum.org/faq/reference/48kreference.htm#Contention - Screen Memory Layout
http://www.breakintoprogram.co.uk/hardware/computers/zx-spectrum/screen-memory-layout - OpenSE BASIC
https://zxdesign.itch.io/opense - Domácí a školní mikropočítače řady Didaktik
https://www.root.cz/clanky/domaci-a-skolni-mikropocitace-rady-didaktik/