Vývoj pro ZX Spectrum: výpis informací na obrazovku

21. 2. 2023
Doba čtení: 33 minut

Sdílet

 Autor: Depositphotos
Ve třetím článku o vývoji pro domácí mikropočítač ZX Spectrum si ukážeme, jak lze zajistit výpis užitečných informací (znaků, řetězců atd.) na obrazovku. Využít přitom můžeme podprogramy z ROM či si vše napsat od začátku.

Obsah

1. Vývoj her a grafických i zvukových dem pro ZX Spectrum: výpis informací na obrazovku

2. Smazání obrazovky a otevření kanálu číslo 2 (screen)

3. Tisk jednoho znaku na obrazovku přes rutinu uloženou v ROM

4. Náhrada instrukce CALL za instrukci RST

5. Tisk znaku bez předchozího smazání obrazovky

6. Tisk celé znakové sady (nekorektní varianta)

7. Oprava předchozího demonstračního příkladu

8. Řídicí znaky a sekvence řídicích znaků

9. Modifikace barvy popředí a pozadí vypisovaných znaků

10. Povolení blikání, vysoké intenzity popředí atd.

11. Tisk na určité místo na obrazovce příkazem AT

12. Tisk celého řetězce

13. Programová smyčka pro tisk řetězce znak po znaku

14. Urychlení testu konce řetězce

15. Tisk řetězce obsahujícího řídicí znaky

16. Tisk celého řetězce s využitím subrutiny v ROM

17. Obsah následujícího článku

18. Příloha: upravený soubor Makefile pro překlad demonstračních příkladů

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

20. Odkazy na Internetu

1. Vývoj her a grafických i zvukových dem pro ZX Spectrum: výpis informací na obrazovku

Ve třetím článku o vývoji programů pro legendární osmibitový domácí mikropočítač ZX Spectrum si ukážeme, jakým způsobem je možné zajistit výpis nějakých informací (znaků, řetězců atd.) na obrazovku. Využít přitom můžeme dvou přístupů. První přístup spočívá v zavolání již připravených podprogramů uložených v ROM ZX Spectra, druhý přístup vyžaduje, abychom si všechny potřebné rutiny napsali od začátku. Oba přístupy přitom mají své opodstatnění. Subrutiny uložené v ROM jsou pro mnoho účelů dostatečně rychlé a jejich nespornou výhodou je, že jejich reimplementaci nemusíme ukládat do operační paměti, jejíž kapacita je omezena (něco jiného platí například pro osmibitová Atari, kde lze ROM „odklopit“ a využít tak téměř celých 64kB operační paměti). A pokud si subrutiny pro vykreslení znaku, řetězce, změnu atributů (barvy atd.) napíšeme sami, můžeme realizovat například různé nestandardní šířky a/nebo výšky znaků (více znaků na řádek atd.) popř. dokonce vypisovat proporcionální text.

Obrázek 1: Standardní znaková sada. ZX Spectrum sice nepodporuje klasické textové režimy, ovšem tato znaková sada je uložena v ROM a používá ji mnoho programů, včetně našich dnešních příkladů (text 32×24 znaků).

Tak daleko však dnes ještě nejsme, takže si ukážeme způsob volání subrutin, které jsou připraveny v ROM ZX Spectra, a to jak v originální licensované ROM, tak i v OpenSE BASICu (což je alternativní ROM, viz též úvodní článek).

Obrázek 2: Ukázka nestandardní znakové sady vykreslované vlastními subrutinami (horní část obrazovky s výpisem programového kódu) kombinovaná se standardní znakovou sadou (vstup textu ve spodní části obrazovky).

V demonstračních příkladech uvedených v následujících kapitolách je použito pouze několik instrukcí, které postupně rozšiřují repertoár nám již známých instrukcí z předchozích dvou článků. Tyto instrukce jsou, společně s jejich stručným popisem, vypsány v následující tabulce:

Strojový kód Instrukce Operandy Stručný popis instrukce
3Exx LD A, xx načtení osmibitové konstanty xx do akumulátoru A
06×x LD B, xx načtení osmibitové konstanty xx do pracovního registru B
0exx LD C, xx načtení osmibitové konstanty xx do pracovního registru C
79 LD A, C přesun dat z registru C do akumulátoru A
       
3C INC A zvýšení obsahu akumulátoru A o jedničku
0C INC C zvýšení obsahu pracovního registru C o jedničku
       
10rr DJNZ rr snížení hodnoty registru B a relativní skok za podmínky, že nová hodnota registru B není nulová
       
C9 RET   návrat z podprogramu
CDxxxx CALL xxxx skok do podprogramu na adrese xxxx s uložením návratové adresy na zásobník
D7 RST 10 kratší a rychlejší varianta CALL pro vybraných osm adres

Obrázek 3: Další ukázka nestandardní znakové sady vykreslované vlastními subrutinami. Zde se dokonce jedná o proporcionální fonty.

2. Smazání obrazovky a otevření kanálu číslo 2 (screen)

Dnešní první demonstrační příklad bude provádět jedinou operaci – zavolá službu resp. subrutinu neboli podprogram, jenž je uložený v paměti ROM a je tedy programátorům snadno dostupný a navíc i velmi dobře zdokumentovaný. Tento podprogram zajistí smazání obrazovky a otevření kanálu číslo 2 (což je právě zařízení typu „obrazovka“ neboli screen). Podprogram ROM_CLS (popř. jen CLS, viz například tento popis) je v paměti ROM umístěn na adrese 0×0DAF a nevyžaduje žádné parametry, které by se jinak předávaly buď v pracovních registrech nebo s využitím speciálním zásobníku numerických hodnot typu float (k čemuž se ještě dostaneme) v některém z dalších částí tohoto seriálu.

Zavolání podprogramu zajišťuje u mikroprocesorů Zilog Z80 (a i na mnoha dalších mikroprocesorových architekturách) instrukce CALL, která uloží návratovou adresu na zásobník a následně provede skok. Náš program se tedy bude skládat ze dvou instrukcí CALL + RET:

ENTRY_POINT   equ $8000
ROM_CLS       equ $0DAF
 
        org ENTRY_POINT
 
start:
        call ROM_CLS    ; smazání obrazovky a otevření kanálu číslo 2 (screen)
        ret             ; návrat z programu do BASICu
 
end ENTRY_POINT
Poznámka: možná vás již napadlo, že dvojici CALL+RET lze nahradit prostým skokem JP.

Překlad výše uvedeného zdrojového kódu do assembleru bude vypadat následovně:

ENTRY_POINT     EQU 8000
ROM_CLS         EQU 0DAF
                ORG 8000
8000:           label start
8000:CDAF0D     CALL 0DAF
8003:C9         RET
8004:           END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 8003
Poznámka: zdrojový kód tohoto demonstračního příkladu naleznete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/18-cls.asm.

Podívejme se nyní na to, jak budou vypadat výsledky po spuštění v emulátoru s originální ROM i v emulátoru, v němž je tato licensovaná ROM nahrazena za OpenSE BASIC (tím mj. ověříme kompatibilitu obou ROM minimálně z pohledu služby ROM_CLS:

Obrázek 4: Smazání obrazovky v emulátoru s originální ROM (zprávy dole jsou vypsány až po ukončení programu).

Obrázek 5: Smazání obrazovky v emulátoru s OpenSE BASICem (povšimněte si nepatrně odlišné odezvy interpretru).

3. Tisk jednoho znaku na obrazovku přes rutinu uloženou v ROM

Ve chvíli, kdy je po zavolání subrutiny ROM_CLS umožněn tisk na obrazovku, je možné využít subrutinu, která je dostupná na adrese 0×10 a popsaná je například zde. Tato subrutina na obrazovku vypíše jeden znak a posune (neviditelný) kurzor, který ukazuje na místo na obrazovce, kam bude proveden další tisk (obrazovka je tedy použita jako terminál). A jelikož tato subrutina potřebuje znát ASCII kód tisknutého znaku, je nutné nějakým způsobem tento parametr předat. V tomto konkrétním případě je to jednoduché, protože se jedná o jediný osmibitový parametr. Předán bude v akumulátoru, tedy v registru A (to, jak se parametry předávají do konkrétních subrutin, zjistíme právě z jejich dokumentace). Program, který na obrazovku vytiskne znak „*“, jehož ASCII kód je roven 42, může vypadat následovně:

ENTRY_POINT   equ $8000
ROM_CLS       equ $0DAF
 
        org ENTRY_POINT
 
start:
        call ROM_CLS    ; smazání obrazovky a otevření kanálu číslo 2 (screen)
        ld   A, 42      ; kód znaku '*' pro tisk
        call 0x10       ; zavolání rutiny v ROM
        ret             ; návrat z programu do BASICu
 
end ENTRY_POINT
Poznámka: namísto hodnoty 42 můžete zapsat i ‚*‘.

Překlad výše uvedeného zdrojového kódu do assembleru bude vypadat následovně. Povšimněte si, že celý program zabere v operační paměti pouhých devět bajtů:

ENTRY_POINT     EQU 8000
ROM_CLS         EQU 0DAF
                ORG 8000
8000:           label start
8000:CDAF0D     CALL 0DAF
8003:3E2A       LD A, 2A
8005:CD1000     CALL 0010
8008:C9         RET
8009:           END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 8008
Poznámka: zdrojový kód tohoto demonstračního příkladu naleznete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/19-print-char-call.asm.

Opět se podívejme na to, jak bude vypadat výsledek při použití originální i volně dostupné ROM. Tyto ROM se totiž odlišují mj. i jinou znakovou sadou (v prvním případě má hvězdička šest cípů, ve druhém pouze pět):

Obrázek 6: Znak „*“ vytištěný v emulátoru s originální ROM ZX Spectra.

Obrázek 7: Znak „*“ vytištěný v emulátoru s OpenSE BASICem.

4. Náhrada instrukce CALL za instrukci RST

Program uvedený v předchozí kapitole je ve skutečnosti možné zkrátit a současně i urychlit. Je tomu tak z toho důvodu, že volání podprogramů uložených na adresách 0×00, 0×08, 0×10, 0×18, 0×20, 0×28, 0×30 a 0×38 není nutné realizovat instrukcemi typu CALL, jejichž strojový kód zabírá tři bajty a doba provedení je velmi dlouhá – celých sedmnáct hodinových cyklů. Namísto toho lze použít instrukci RST, která má po přeložení délku jednoho bajtu a doba jejího provedení je taktéž kratší: jedenáct cyklů namísto cyklů sedmnácti. Způsob zápisu operandů instrukce RST je u Zilogu Z80 odlišný od Intelu 8080, ovšem díky tomu, že se operandy vždy odlišují, nedojde při převodu zdrojových textů programů ke zmatkům:

Intel 8080 Zilog Z80 Operační kód Provedená operace
RST 0 RST 0 C7 CALL 0
RST 1 RST 8 CF CALL 8
RST 2 RST 10H D7 CALL 10H
RST 3 RST 18H DF CALL 18H
RST 4 RST 20H E7 CALL 20H
RST 5 RST 28H EF CALL 28H
RST 6 RST 30H F7 CALL 30H
RST 7 RST 38H FF CALL 38H

Program tedy upravíme do následující zkrácené a současně i rychlejší podoby:

ENTRY_POINT   equ $8000
ROM_CLS       equ $0DAF
 
        org ENTRY_POINT
 
start:
        call ROM_CLS    ; smazání obrazovky a otevření kanálu číslo 2 (screen)
        ld   A, 42      ; kód znaku '*' pro tisk
        rst  0x10       ; zavolání rutiny v ROM
        ret             ; návrat z programu do BASICu
 
end ENTRY_POINT

Po překladu získáme tento kód, který je zcela zřejmě kratší v porovnání s kódem z předchozí kapitoly (má pouze sedm bajtů namísto bajtů devíti):

ENTRY_POINT     EQU 8000
ROM_CLS         EQU 0DAF
                ORG 8000
8000:           label start
8000:CDAF0D     CALL 0DAF
8003:3E2A       LD A, 2A
8005:D7         RST 10
8006:C9         RET
8007:           END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 8006
Poznámka: zdrojový kód tohoto demonstračního příkladu naleznete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/20-print-char-rst.asm.

5. Tisk znaku bez předchozího smazání obrazovky

V některých aplikacích je zapotřebí vypsat nějaký text bez předchozího smazání obrazovky. V tomto případě již není možné volat subrutinu ROM_CLS, ale potřebujeme „pouze“ otevřít kanál zařízení „screen“ s číslem 2. To se provede subrutinou dostupnou na adrese 0×1601, kterou si pojmenujeme ROM_OPEN_CHANNEL a jejíž popis je dostupný na adrese https://skoolkit.ca/disas­semblies/rom/asm/5633.html. K samotnému popisu konceptu kanálů se ještě vrátíme – jedná se o jeden z velmi užitečných konceptů ZX Spectra. Program tedy upravíme do podoby:

ENTRY_POINT      equ $8000
ROM_OPEN_CHANNEL equ $1601
 
        org ENTRY_POINT
 
start:
        ld   A,2              ; číslo kanálu
        call ROM_OPEN_CHANNEL ; otevření kanálu číslo 2 (screen)
        ld   A, 42            ; kód znaku '*' pro tisk
        rst  0x10             ; zavolání rutiny v ROM
        ret                   ; návrat z programu do BASICu
 
end ENTRY_POINT

Výsledek po překladu:

ENTRY_POINT     EQU 8000
ROM_OPEN_CHANNEL EQU 1601
                ORG 8000
8000:           label start
8000:3E02       LD A, 02
8002:CD0116     CALL 1601
8005:3E2A       LD A, 2A
8007:D7         RST 10
8008:C9         RET
8009:           END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 8008
Poznámka: zdrojový kód tohoto demonstračního příkladu naleznete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/21-print-char.asm.

6. Tisk celé znakové sady (nekorektní varianta)

Nyní již máme k dispozici (alespoň zdánlivě) všechny informace potřebné pro vytištění celé znakové sady, tedy konkrétně znaků s kódy 32 až 128 (ASCII), ke kterým je přidáno dalších šestnáct znaků pro pseudografiku. Pokusme se tedy pro tento účel použít programovou smyčku s počitadlem uloženým v pracovním registru B a kódem aktuálně tisknutého znaku uloženého v registru A (tedy v akumulátoru). Samotná programová smyčka je triviální, protože jak výpočet nové hodnoty počitadla, tak i podmíněný skok je implementován jedinou instrukcí DJNZ (viz předchozí článek). Hodnota uložená v registru A je předána na subrutiny pro tisk jednoho znaku:

ENTRY_POINT   equ $8000
ROM_CLS       equ $0DAF
 
        org ENTRY_POINT
 
start:
        call ROM_CLS    ; smazání obrazovky a otevření kanálu číslo 2 (screen)
 
        ld  a, ' '      ; kód prvního zapisovaného znaku
        ld  b, 96+16    ; počitadlo smyčky
 
loop:
        rst  0x10       ; zavolání rutiny v ROM
 
        inc a           ; zvýšení zapisované hodnoty (kódu znaku)
        djnz loop       ; kombinace dec b + jp NZ, loop
                        ; snížení hodnoty počitadla
                        ; skok pokud se ještě nedosáhlo nuly
        ret             ; návrat z programu do BASICu
 
end ENTRY_POINT

A takto vypadá výsledek překladu. Program je (pochopitelně) nepatrně delší, než tomu bylo u předchozích demonstračních příkladů:

ENTRY_POINT     EQU 8000
ROM_CLS         EQU 0DAF
                ORG 8000
8000:           label start
8000:CDAF0D     CALL 0DAF
8003:3E20       LD A, 20
8005:0670       LD B, 70
8007:           label loop
8007:D7         RST 10
8008:3C         INC A
8009:10FC       DJNZ 8007
800B:C9         RET
800C:           END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 800B

Podívejme se však na výsledek:

Obrázek 8: Obrazovka, kterou jsme získali po spuštění demonstračního příkladu z této kapitoly.

Z výsledku je patrné, že program nepracuje přesně tak, jak jsme očekávali, protože sice vytiskne počáteční mezeru (což je správně), ovšem posléze je vytištěna jen sekvence devítek. Opravu provedeme v rámci navazující kapitoly.

Poznámka: zdrojový kód tohoto demonstračního příkladu naleznete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/22-print-all-chars.asm.

7. Oprava předchozího demonstračního příkladu

Chyba, která se „vloudila“ do demonstračního příkladu uvedeného v šesté kapitole, nám ukazuje další vlastnost subrutin uložených v paměti ROM – po zavolání subrutiny se mohou obsahy některých pracovních registrů změnit, což je i náš případ, protože se změnil obsah akumulátoru A na hodnotu, která odpovídá kódu znaku „8“, což je decimálně 56 popř. hexadecimálně 0×38. Náprava je v tomto případě velmi snadná – nebudeme akumulátor používat pro uložení kódu vypisovaného znaku, ale použijeme namísto toho jiný pracovní registr, například registr C. Samozřejmě bude nutné při volání subrutiny na adrese 0×10 naplnit akumulátor kódem znaku, ale již nás nebude zajímat, zda a proč se tato hodnota v subrutině změnila, protože původní hodnota zůstane v C:

ENTRY_POINT   equ $8000
ROM_CLS       equ $0DAF
 
        org ENTRY_POINT
 
start:
        call ROM_CLS    ; smazání obrazovky a otevření kanálu číslo 2 (screen)
 
        ld  c, ' '      ; kód prvního zapisovaného znaku
        ld  b, 96+16    ; počitadlo smyčky
 
loop:
        ld   a, c       ; kód zapisovaného znaku
        rst  0x10       ; zavolání rutiny v ROM
 
        inc c           ; zvýšení zapisované hodnoty (kód znaku)
        djnz loop       ; kombinace dec b + jp NZ, loop
                        ; snížení hodnoty počitadla
                        ; skok pokud se ještě nedosáhlo nuly
        ret             ; návrat z programu do BASICu
 
end ENTRY_POINT

Překlad do strojového kódu vypadá v lidsky čitelné podobě následovně:

ENTRY_POINT     EQU 8000
ROM_CLS         EQU 0DAF
                ORG 8000
8000:           label start
8000:CDAF0D     CALL 0DAF
8003:0E20       LD C, 20
8005:0670       LD B, 70
8007:           label loop
8007:79         LD A, C
8008:D7         RST 10
8009:0C         INC C
800A:10FB       DJNZ 8007
800C:C9         RET
800D:           END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 800C

Nyní tento demonstrační příklad skutečně vypíše celou dostupnou znakovou sadu ZX Spectra, což znamená podmnožinu odpovídající ASCII (až na několik malých změn – například se týká znaku libry a ©), která je doplněna o šestnáct pseudografických znaků využívaných například na mikropočítačích ZX-80 a ZX-81 pro tvorbu (pseudo)grafiky:

Obrázek 9: Znaková sada ZX Spectra s originální ROM.

Obrázek 10: Znaková sada ZX Spectra s volně dostupnou ROM s OpenSE BASICem.

Poznámka: zdrojový kód tohoto demonstračního příkladu naleznete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/23-print-all-chars.asm.

8. Řídicí znaky a sekvence řídicích znaků

V předchozím textu jsme si mj. uvedli odkaz na stránku se znakovou sadou ZX Spectra. Ovšem tato stránka obsahuje i další důležité informace. Například ve druhém sloupci, který obsahuje kódy od 0×10 do 0×1f, můžeme najít seznam řídicích kódů, které – pokud budou vytisknuty – ovlivní znaky tisknuté později. Samotný řídicí kód není při tisku viditelný, ale změní vnitřní stav subrutiny pro tisk znaku. Všechny řídicí kódy navíc očekávají jeden či dva parametry, což jsou vlastně taktéž tisknuté „znaky“, jak to ostatně uvidíme v příkladem uvedených v navazujících kapitolách:

Řídicí kód Parametr #1 Parametr #2
Ink index barvy  
Paper index barvy  
Flash 0 nebo 1  
Bright 0 nebo 1  
Inverse 0 nebo 1  
Over 0 nebo 1  
At řádek sloupec
Tab počet mezer  

9. Modifikace barvy popředí a pozadí vypisovaných znaků

V dalším demonstračním příkladu si ukážeme způsob využití řídicích kódů určených pro změnu barvy inkoustu (INK) a modifikaci barvy papíru (PAPER). Pokud budeme například chtít zobrazit barevnou hvězdičku na modrém pozadí, budou se „tisknout“ tyto znaky:

  1. řídicí kód pro změnu barvy inkoustu
  2. index barvy inkoustu
  3. řídicí kód pro změnu barvy pozadí
  4. index barvy pozadí
  5. a konečně vlastní hvězdička

Vše lze zrealizovat takto přímočaře (i když nepříliš obecně):

ENTRY_POINT      equ $8000
ROM_OPEN_CHANNEL equ $1601
 
INK              equ $10
PAPER            equ $11
FLASH            equ $12
BRIGHT           equ $13
INVERSE          equ $14
 
BLACK_COLOR      equ %000
BLUE_COLOR       equ %001
RED_COLOR        equ %010
MAGENTA_COLOR    equ %011
GREEN_COLOR      equ %100
CYAN_COLOR       equ %101
YELLOW_COLOR     equ %110
WHITE_COLOR      equ %111
 
        org ENTRY_POINT
 
start:
        ld   A,2              ; číslo kanálu
        call ROM_OPEN_CHANNEL ; otevření kanálu číslo 2 (screen)
 
        ld   A, INK           ; řídicí kód pro specifikaci barvy inkoustu
        rst  0x10             ; zavolání rutiny v ROM
 
        ld   A, YELLOW_COLOR  ; barva inkoustu
        rst  0x10             ; zavolání rutiny v ROM
 
        ld   A, PAPER         ; řídicí kód pro specifikaci barvy papíru
        rst  0x10             ; zavolání rutiny v ROM
 
        ld   A, BLUE_COLOR    ; barva papíru
        rst  0x10             ; zavolání rutiny v ROM
 
        ld   A, 42            ; kód znaku '*' pro tisk
        rst  0x10             ; zavolání rutiny v ROM
 
        ret                   ; návrat z programu do BASICu
 
end ENTRY_POINT

Způsob překladu tohoto demonstračního příkladu do assembleru:

ENTRY_POINT     EQU 8000
ROM_OPEN_CHANNEL EQU 1601
INK             EQU 0010
PAPER           EQU 0011
FLASH           EQU 0012
BRIGHT          EQU 0013
INVERSE         EQU 0014
BLACK_COLOR     EQU 0000
BLUE_COLOR      EQU 0001
RED_COLOR       EQU 0002
MAGENTA_COLOR   EQU 0003
GREEN_COLOR     EQU 0004
CYAN_COLOR      EQU 0005
YELLOW_COLOR    EQU 0006
WHITE_COLOR     EQU 0007
                ORG 8000
8000:           label start
8000:3E02       LD A, 02
8002:CD0116     CALL 1601
8005:3E10       LD A, 10
8007:D7         RST 10
8008:3E06       LD A, 06
800A:D7         RST 10
800B:3E11       LD A, 11
800D:D7         RST 10
800E:3E01       LD A, 01
8010:D7         RST 10
8011:3E2A       LD A, 2A
8013:D7         RST 10
8014:C9         RET
8015:           END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 8014

A konečně se podívejme na výsledek, který odpovídá popisu:

Obrázek 11: Hvězdička je nyní zobrazena žlutou barvou a s modrým pozadím.

Poznámka: zdrojový kód tohoto demonstračního příkladu naleznete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/24-change-color.asm.

10. Povolení blikání, vysoké intenzity popředí atd.

Mnohé řídicí kódy zmíněné v osmé kapitole vyžadují, aby se příslušná vlastnost (blikání, vysoká intenzita atd.) povolila či naopak zakázala druhým řídicím kódem, tedy hodnotou 0 nebo 1. Ukažme si například, jak lze vynutit blikání hvězdičky, a to s využitím řídicího znaku FLASH:

ENTRY_POINT      equ $8000
ROM_OPEN_CHANNEL equ $1601
 
INK              equ $10
PAPER            equ $11
FLASH            equ $12
BRIGHT           equ $13
INVERSE          equ $14
 
ENABLE           equ 1
DISABLE          equ 0
 
        org ENTRY_POINT
 
start:
        ld   A,2              ; číslo kanálu
        call ROM_OPEN_CHANNEL ; otevření kanálu číslo 2 (screen)
 
        ld   A, FLASH         ; řídicí kód pro specifikaci blikání
        rst  0x10             ; zavolání rutiny v ROM
 
        ld   A, ENABLE        ; povolení blikání
        rst  0x10             ; zavolání rutiny v ROM
 
        ld   A, 42            ; kód znaku '*' pro tisk
        rst  0x10             ; zavolání rutiny v ROM
 
        ret                   ; návrat z programu do BASICu
 
end ENTRY_POINT

Takto vypadá lidsky čitelný výsledek překladu demonstračního příkladu z této kapitoly:

ENTRY_POINT     EQU 8000
ROM_OPEN_CHANNEL EQU 1601
INK             EQU 0010
PAPER           EQU 0011
FLASH           EQU 0012
BRIGHT          EQU 0013
INVERSE         EQU 0014
ENABLE          EQU 0001
DISABLE         EQU 0000
                ORG 8000
8000:           label start
8000:3E02       LD A, 02
8002:CD0116     CALL 1601
8005:3E12       LD A, 12
8007:D7         RST 10
8008:3E01       LD A, 01
800A:D7         RST 10
800B:3E2A       LD A, 2A
800D:D7         RST 10
800E:C9         RET
800F:           END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 800E

A výsledkem by po spuštění v emulátoru měla být skutečně blikající hvězdička:

Obrázek 12: Blikající hvězdička vytištěná demonstračním příkladem.

Obrázek 13: Blikající hvězdička vytištěná demonstračním příkladem.

Poznámka: zdrojový kód tohoto demonstračního příkladu naleznete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/25-change-flash.asm.

11. Tisk na určité místo na obrazovce příkazem AT

Posledním zajímavým řídicím znakem, s nímž se dnes setkáme, je řídicí znak AT (jenž je interně použit v BASICovském příkazu PRINT AT). Tento řídicí znak přesune neviditelný „kurzor“ na určený řádek a sloupec, i když na tomto místě je vhodné poznamenat, že koncept kurzoru je na ZX Spectru pojat poněkud odlišně, než například na osmibitových Atari s celoobrazovkovým editorem. Ovšem vraťme se k assembleru na ZX Spectru. Necháme si opět vypsat hvězdičku, ovšem tentokrát na samotný konec sedmnáctého řádku. Příkazu AT se tedy předá dvojice parametrů 16 (řádek) a 31 (sloupec):

ENTRY_POINT      equ $8000
ROM_OPEN_CHANNEL equ $1601
 
AT               equ 0x16
 
        org ENTRY_POINT
 
start:
        ld   A,2              ; číslo kanálu
        call ROM_OPEN_CHANNEL ; otevření kanálu číslo 2 (screen)
 
        ld   A, AT            ; řídicí kód pro specifikaci pozice psaní
        rst  0x10             ; zavolání rutiny v ROM
 
        ld   A, 16            ; y-ová souřadnice
        rst  0x10             ; zavolání rutiny v ROM
 
        ld   A, 31            ; x-ová souřadnice
        rst  0x10             ; zavolání rutiny v ROM
 
        ld   A, 42            ; kód znaku '*' pro tisk
        rst  0x10             ; zavolání rutiny v ROM
 
        ret                   ; návrat z programu do BASICu
 
end ENTRY_POINT

Takto vypadá lidsky čitelný výsledek překladu demonstračního příkladu z této kapitoly:

ENTRY_POINT     EQU 8000
ROM_OPEN_CHANNEL EQU 1601
AT              EQU 0016
                ORG 8000
8000:           label start
8000:3E02       LD A, 02
8002:CD0116     CALL 1601
8005:3E16       LD A, 16
8007:D7         RST 10
8008:3E10       LD A, 10
800A:D7         RST 10
800B:3E1F       LD A, 1F
800D:D7         RST 10
800E:3E2A       LD A, 2A
8010:D7         RST 10
8011:C9         RET
8012:           END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 8011

Výsledkem by měla být obrazovka s tímto obsahem:

Obrázek 14: Hvězdička vykreslená na samotném konci sedmnáctého řádku.

Poznámka: zdrojový kód tohoto demonstračního příkladu naleznete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/26-print-at.asm.

12. Tisk celého řetězce

V dalších čtyřech kapitolách si ukážeme, jakým způsobem lze realizovat tisk celého řetězce, a to jak řetězce se známou délkou (tu nám dokáže vypočítat assembler), tak i céčkovského řetězce ukončeného nulou popř. jiným znakem (někdy se používá znak dolaru atd.). Opět existuje několik variant realizace tisku řetězce – buď budeme sami provádět tisk ve smyčce, tedy znak po znaku nebo využijeme další subrutinu uloženou v paměti ROM, která tisk provede za nás. Ve druhém případě budeme nepatrně omezeni tím, jaké tato subrutina očekává parametry a jak se zadává konec řetězce.

13. Programová smyčka pro tisk řetězce znak po znaku

Nejprve si ukažme tisk řetězce realizovaný programovou smyčkou. Až na způsob deklarace řetězce (ukončeného nulou):

TEXT:   db "Hello, Speccy!", 0

vlastně tento příklad neobsahuje žádné komplikace, neboť programovou smyčku již umíme vytvořit, stejně jako umíme otestovat obsah registru na nulu. Pro adresování se používá dvojice registrů HL a výskok je uvnitř smyčky (ne na konci):

ENTRY_POINT      equ $8000
ROM_OPEN_CHANNEL equ $1601
 
        org ENTRY_POINT
 
start:
        ld   A,2              ; číslo kanálu
        call ROM_OPEN_CHANNEL ; otevření kanálu číslo 2 (screen)
 
        ld   HL, TEXT         ; adresa prvního znaku v řetězci
 
LOOP:
        ld   A, (HL)          ; načíst kód znaku z řetězce
        cp   0                ; test na kód znak s kódem 0
        ret  Z                ; ukončit program na konci řetězce
 
        rst  0x10             ; zavolání rutiny v ROM
        inc  HL               ; přechod na další znak
        jr   LOOP
 
; nulou ukončený řetězec
TEXT:   db "Hello, Speccy!", 0
 
end ENTRY_POINT

Překlad tohoto příkladu do strojového kódu bude vypadat následovně:

ENTRY_POINT     EQU 8000
ROM_OPEN_CHANNEL EQU 1601
                ORG 8000
8000:           label start
8000:3E02       LD A, 02
8002:CD0116     CALL 1601
8005:211080     LD HL, 8010
8008:           label LOOP
8008:7E         LD A, (HL)
8009:FE00       CP 00
800B:C8         RET Z
800C:D7         RST 10
800D:23         INC HL
800E:18F8       JR 8008
8010:           label TEXT
8010:48656C6C   DEFB of 15 bytes
8014:6F2C2053
8018:70656363
801C:792100
801F:           END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 801E

A samozřejmě si ukážeme i výsledek:

Obrázek 15: Řetězec vytištěný demonstračním příkladem.

14. Urychlení testu konce řetězce

Nulou ukončené řetězce jsou masivně používány v céčku a tím pádem i v mnoha knihovnách, které jsou v C psány či na C postaveny. Nejedná se o náhodu, protože test na nulovou hodnotu lze na mnoha mikroprocesorových architekturách realizovat snadněji a rychleji, než test na jinou hodnotu. Ostatně podívejme se, jak je tomu v případě Zilogu Z80. Explicitní test na nulu je instrukce s délkou dvou bajtů a dobou vykonání sedmi cyklů:

cp   0                ; test na kód znak s kódem 0

Ovšem namísto toho můžeme použít například instrukci and a, která má délku jen jeden bajt a doba jejího vykonání je čtyři takty (patří tedy do skupiny nejrychlejších instrukcí). Tato instrukce nezmění obsah akumulátoru, ale nastaví příznak zero ve chvíli, kdy akumulátor skutečně obsahuje nulu:

and  a                ; test na kód znak s kódem 0

Upravený zdrojový kód demonstračního příkladu může vypadat takto:

ENTRY_POINT      equ $8000
ROM_OPEN_CHANNEL equ $1601
 
        org ENTRY_POINT
 
start:
        ld   A,2              ; číslo kanálu
        call ROM_OPEN_CHANNEL ; otevření kanálu číslo 2 (screen)
 
        ld   HL, TEXT         ; adresa prvního znaku v řetězci
 
LOOP:
        ld   A, (HL)          ; načíst kód znaku z řetězce
        and  a                ; test na kód znak s kódem 0
        ret  Z                ; ukončit program na konci řetězce
 
        rst  0x10             ; zavolání rutiny v ROM
        inc  HL               ; přechod na další znak
        jr   LOOP
 
; nulou ukončený řetězec
TEXT:   db "Hello, Speccy!", 0
 
end ENTRY_POINT

Zpráva o překladu do strojového kódu skutečně ukazuje, že je výsledek o jeden bajt kratší:

ENTRY_POINT     EQU 8000
ROM_OPEN_CHANNEL EQU 1601
                ORG 8000
8000:           label start
8000:3E02       LD A, 02
8002:CD0116     CALL 1601
8005:210F80     LD HL, 800F
8008:           label LOOP
8008:7E         LD A, (HL)
8009:A7         AND A
800A:C8         RET Z
800B:D7         RST 10
800C:23         INC HL
800D:18F9       JR 8008
800F:           label TEXT
800F:48656C6C   DEFB of 15 bytes
8013:6F2C2053
8017:70656363
801B:792100
801E:           END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 801D

Obrázek 16: Řetězec vytištěný demonstračním příkladem (výstup je totožný s předchozím příkladem).

15. Tisk řetězce obsahujícího řídicí znaky

Řetězec, který tiskneme s využitím explicitně zapsané programové smyčky, může pochopitelně obsahovat i řídicí znaky atd. Samotný programový kód nebude vyžadovat žádné úpravy, pouze se podívejme, jak vypadá deklarace řetězce „proloženého“ řídicími znaky:

TEXT:   db PAPER, RED_COLOR, "Hello", INK, WHITE_COLOR, "Speccy", FLASH, 1, "!", 0
Poznámka: což je mimochodem přehlednější zápis, než tomu je v mnoha vysokoúrovňových programovacích jazycích.

Celý zdrojový kód s takto deklarovaným řetězcem bude vypadat následovně:

ENTRY_POINT      equ $8000
ROM_OPEN_CHANNEL equ $1601
 
INK              equ $10
PAPER            equ $11
FLASH            equ $12
BRIGHT           equ $13
INVERSE          equ $14
 
BLACK_COLOR      equ %000
BLUE_COLOR       equ %001
RED_COLOR        equ %010
MAGENTA_COLOR    equ %011
GREEN_COLOR      equ %100
CYAN_COLOR       equ %101
YELLOW_COLOR     equ %110
WHITE_COLOR      equ %111
 
 
        org ENTRY_POINT
 
start:
        ld   A,2              ; číslo kanálu
        call ROM_OPEN_CHANNEL ; otevření kanálu číslo 2 (screen)
 
        ld   HL, TEXT         ; adresa prvního znaku v řetězci
 
LOOP:
        ld   A, (HL)          ; načíst kód znaku z řetězce
        and  a                ; test na kód znak s kódem 0
        ret  Z                ; ukončit program na konci řetězce
 
        rst  0x10             ; zavolání rutiny v ROM
        inc  HL               ; přechod na další znak
        jr   LOOP
 
; nulou ukončený řetězec
TEXT:   db PAPER, RED_COLOR, "Hello", INK, WHITE_COLOR, "Speccy", FLASH, 1, "!", 0
 
end ENTRY_POINT

Překlad do strojového kódu:

ENTRY_POINT     EQU 8000
ROM_OPEN_CHANNEL EQU 1601
INK             EQU 0010
PAPER           EQU 0011
FLASH           EQU 0012
BRIGHT          EQU 0013
INVERSE         EQU 0014
BLACK_COLOR     EQU 0000
BLUE_COLOR      EQU 0001
RED_COLOR       EQU 0002
MAGENTA_COLOR   EQU 0003
GREEN_COLOR     EQU 0004
CYAN_COLOR      EQU 0005
YELLOW_COLOR    EQU 0006
WHITE_COLOR     EQU 0007
                ORG 8000
8000:           label start
8000:3E02       LD A, 02
8002:CD0116     CALL 1601
8005:210F80     LD HL, 800F
8008:           label LOOP
8008:7E         LD A, (HL)
8009:A7         AND A
800A:C8         RET Z
800B:D7         RST 10
800C:23         INC HL
800D:18F9       JR 8008
800F:           label TEXT
800F:11024865   DEFB of 19 bytes
8013:6C6C6F10
8017:07537065
801B:63637912
801F:012100
8022:           END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 8021

A konečně se podívejme na výslednou obrazovku, která mj. obsahuje i blikající vykřičník:

Obrázek 17: Vícebarevný a částečně blikající text vytištěný demonstračním příkladem.

Obrázek 18: Vícebarevný a částečně blikající text vytištěný demonstračním příkladem.

16. Tisk celého řetězce s využitím subrutiny v ROM

V dnešním posledním demonstračním příkladu využijeme pro tisk řetězce subrutinu, která je uložena v paměti ROM od adresy 0×203C. Tato subrutina vyžaduje několik parametrů:

  1. V registrovém páru BC musí být uložena délka řetězce
  2. V registrovém páru DE musí být uložena adresa prvního znaku v řetězci

Kvůli tomu, že se pracuje s (předem známou) délkou řetězce, není nutné, aby byl řetězec ukončen nulou. Jak se však délka řetězce získá? Pomůže nám samotný assembler Pasmo, který v pseudoproměnné $ obsahuje aktuálně zpracovávanou adresu. Postačuje tedy tuto adresu odečíst od počáteční adresy řetězce (tu assembler zná, stejně jako ukazatelovou aritmetiku), vypočítat délku a tu následně použít (v druhém průchodu se konstanta s délkou doplní do kódu):

; řetězec
TEXT:   db PAPER, RED_COLOR, "Hello", INK, WHITE_COLOR, "Speccy", FLASH, 1, "!"
 
TEXT_LENGTH: equ $ - TEXT

A takto vypadá výsledný programový kód, který je kratší, než kód s explicitní smyčkou:

ENTRY_POINT      equ $8000
ROM_OPEN_CHANNEL equ $1601
ROM_PRINT        equ $203C
 
INK              equ $10
PAPER            equ $11
FLASH            equ $12
BRIGHT           equ $13
INVERSE          equ $14
 
BLACK_COLOR      equ %000
BLUE_COLOR       equ %001
RED_COLOR        equ %010
MAGENTA_COLOR    equ %011
GREEN_COLOR      equ %100
CYAN_COLOR       equ %101
YELLOW_COLOR     equ %110
WHITE_COLOR      equ %111
 
 
        org ENTRY_POINT
 
start:
        ld   A,2              ; číslo kanálu
        call ROM_OPEN_CHANNEL ; otevření kanálu číslo 2 (screen)
 
        ld   DE, TEXT         ; adresa prvního znaku v řetězci
        ld   BC, TEXT_LENGTH  ; délka textu
        call ROM_PRINT        ; volání subrutiny v ROM
        ret                   ; ukončit program
 
; řetězec
TEXT:   db PAPER, RED_COLOR, "Hello", INK, WHITE_COLOR, "Speccy", FLASH, 1, "!"
 
TEXT_LENGTH: equ $ - TEXT
 
end ENTRY_POINT

Výsledek překladu do strojového kódu:

ENTRY_POINT     EQU 8000
ROM_OPEN_CHANNEL EQU 1601
ROM_PRINT       EQU 203C
INK             EQU 0010
PAPER           EQU 0011
FLASH           EQU 0012
BRIGHT          EQU 0013
INVERSE         EQU 0014
BLACK_COLOR     EQU 0000
BLUE_COLOR      EQU 0001
RED_COLOR       EQU 0002
MAGENTA_COLOR   EQU 0003
GREEN_COLOR     EQU 0004
CYAN_COLOR      EQU 0005
YELLOW_COLOR    EQU 0006
WHITE_COLOR     EQU 0007
                ORG 8000
8000:           label start
8000:3E02       LD A, 02
8002:CD0116     CALL 1601
8005:110F80     LD DE, 800F
8008:011200     LD BC, 0012
800B:CD3C20     CALL 203C
800E:C9         RET
800F:           label TEXT
800F:11024865   DEFB of 18 bytes
8013:6C6C6F10
8017:07537065
801B:63637912
801F:0121
TEXT_LENGTH     EQU 0012
8021:           END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 8020

Obrázek 19: Vícebarevný a částečně blikající text vytištěný demonstračním příkladem.

Obrázek 20: Vícebarevný a částečně blikající text vytištěný demonstračním příkladem.

17. Obsah následujícího článku

V pořadí již čtvrté části seriálu o vývoji programů pro legendární osmibitový domácí mikropočítač ZX Spectrum si ukážeme různé způsoby přímé manipulace s obrazovou pamětí, tedy konkrétně takové postupy, které se obejdou bez využití podprogramů, které jsou uloženy v ROM. Popíšeme si tedy jak strukturu obrazové paměti (prozatím jsme si v demonstračních příkladech otestovali „pouze“ strukturu paměti s barvovými atributy, nikoli ovšem způsob uložení podkladové bitmapy), tak i některé vlastní rutiny použitelné pro vykreslování různých obrazců, ale i běžného textu. Věnovat se budeme i některým postupům, které se na ZX Spectru používají pro vykreslení pohybujících se objektů (spritů). Nakonec se zmíníme o problematice práce s okrajem obrazovky (border), protože i tato část obrazu může být do jisté míry využita.

bitcoin školení listopad 24

18. Příloha: upravený soubor Makefile pro překlad demonstračních příkladů

Výše uvedené demonstrační příklady i příklady, které již byly popsány v předchozích dvou článcích [1] [2], je možné přeložit s využitím souboru Makefile, jehož aktuální verze vypadá následovně (pro překlad a slinkování je použit assembler Pasmo):

ASSEMBLER := pasmo
 
all: 01.tap 02.tap 03.tap 04.tap 05.tap 06.tap 07.tap 08.tap 09.tap 10.tap \
    11.tap 12.tap 13.tap 14.tap 15.tap 16.tap 17.tap 18.tap 19.tap 20.tap \
    21.tap 22.tap 23.tap 24.tap 25.tap 26.tap 27.tap 28.tap 29.tap 30.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
 
08.tap: 08-loop.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 08-loop.lst
 
09.tap: 09-loop.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 09-loop.lst
 
10.tap: 10-loop.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 10-loop.lst
 
11.tap: 11-loop.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 11-loop.lst
 
12.tap: 12-loop.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 12-loop.lst
 
13.tap: 13-loop.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 13-loop.lst
 
14.tap: 14-loop.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 14-loop.lst
 
15.tap: 15-loop.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 15-loop.lst
 
16.tap: 16-loop.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 16-loop.lst
 
17.tap: 17-loop.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 17-loop.lst
 
18.tap: 18-cls.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 18-cls.lst
 
19.tap: 19-print-char-call.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 19-print-char-call.lst
 
20.tap: 20-print-char-rst.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 20-print-char-rst.lst
 
21.tap: 21-print-char.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 21-print-char.lst
 
22.tap: 22-print-all-chars.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 22-print-all-chars.lst
 
23.tap: 23-print-all-chars.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 23-print-all-chars.lst
 
24.tap: 24-change-color.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 24-change-color.lst
 
25.tap: 25-change-flash.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 25-change-flash.lst
 
26.tap: 26-print-at.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 26-print-at.lst
 
27.tap: 27-print-string.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 27-print-string.lst
 
28.tap: 28-print-string.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 28-print-string.lst
 
29.tap: 29-print-colorized-string.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 29-print-colorized-string.lst
 
30.tap: 30-print-string-ROM.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 30-print-string-ROM.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é 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 (viz též úvodní článek):

# 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 08-loop.asm jednoduchá počítaná programová smyčka: naivní varianta https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/08-loop.asm
9 09-loop.asm programová smyčka: zkrácení kódu pro vynulování použitých pracovních registrů https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/09-loop.asm
10 10-loop.asm programová smyčka: optimalizace skoku na konci smyčky (instrukce DJNZ) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/10-loop.asm
11 11-loop.asm programová smyčka: optimalizace využití pracovních registrů https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/11-loop.asm
12 12-loop.asm programová smyčka: použití pracovního registru IX https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/12-loop.asm
13 13-loop.asm programová smyčka: použití pracovního registru IY https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/13-loop.asm
14 14-loop.asm programová smyčka se šestnáctibitovým počitadlem, základní varianta https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/14-loop.asm
15 15-loop.asm programová smyčka se šestnáctibitovým počitadlem, vylepšená varianta https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/15-loop.asm
16 16-loop.asm použití relativního skoku a nikoli skoku absolutního https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/16-loop.asm
17 17-loop.asm programová smyčka: inc l namísto inc hl https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/17-loop.asm
       
18 18-cls.asm smazání obrazovky a otevření kanálu číslo 2 (screen) přes funkci v ROM https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/18-cls.asm
19 19-print-char-call.asm smazání obrazovky a výpis jednoho znaku na obrazovku přes funkci v ROM (použití instrukce CALL) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/19-print-char-call.asm
20 20-print-char-rst.asm smazání obrazovky a výpis jednoho znaku na obrazovku přes funkci v ROM (použití instrukce RST) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/20-print-char-rst.asm
21 21-print-char.asm pouze výpis jednoho znaku na obrazovku bez jejího smazání https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/21-print-char.asm
22 22-print-all-chars.asm výpis znakové sady znak po znaku (nekorektní verze příkladu) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/22-print-all-chars.asm
23 23-print-all-chars.asm výpis znakové sady znak po znaku (korektní verze příkladu) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/23-print-all-chars.asm
24 24-change-color.asm změna barvových atributů (popředí a pozadí) vypisovaných znaků https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/24-change-color.asm
25 25-change-flash.asm povolení či zákaz blikání vypisovaných znaků https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/25-change-flash.asm
26 26-print-at.asm výpis znaku či znaků na určené místo na obrazovce https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/26-print-at.asm
27 27-print-string.asm výpis celého řetězce explicitně zapsanou programovou smyčkou (základní varianta) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/27-print-string.asm
28 28-print-string.asm výpis celého řetězce explicitně zapsanou programovou smyčkou (vylepšená varianta) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/28-print-string.asm
29 29-print-colorized-string.asm výpis řetězce, který obsahuje i řídicí znaky pro změnu barvy atd. https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/29-print-colorized-string.asm
30 30-print-string-ROM.asm výpis řetězce s využitím služby/subrutiny uložené v ROM ZX Spectra https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/30-print-string-ROM.asm
       
31 Makefile Makefile pro překlad a slinkování všech demonstračních příkladů do podoby obrazu magnetické pásky 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/
  53. Z80 Assembler for Dummies
    https://www.msx.org/wiki/Z80_As­sembler_for_Dummies
  54. Z80 Resources
    https://www.assemblytutorial.com/z80/
  55. How do Z80 Block Transfer instructions work?
    https://retrocomputing.stac­kexchange.com/questions/5416/how-do-z80-block-transfer-instructions-work
  56. How fast is memcpy on the Z80?
    https://retrocomputing.stac­kexchange.com/questions/4744/how-fast-is-memcpy-on-the-z80
  57. Comparing Datapoint 2200, 8008, 8080 and Z80 Instruction Sets
    https://bread80.com/comparing-datapoint-2200–8008–8080-and-z80-instruction-sets/
  58. 8080/Z80 Instruction Set
    https://retroprogramming.it/2021/02/8080-z80-instruction-set/
  59. Zilog Z80A Technical Information
    https://worldofspectrum.or­g/faq/reference/z80referen­ce.htm
  60. Z80 programming techniques – Loops
    http://map.grauw.nl/articles/fas­t_loops.php
  61. PRINT in Assembly Language
    http://www.breakintoprogram­.co.uk/hardware/computers/zx-spectrum/assembly-language/z80-tutorials/print-in-assembly-language
  62. Spectrum ROM Routines
    https://skoolkid.github.i­o/rom/maps/routines.html
  63. Spectrum ROM Routines
    https://skoolkit.ca/disas­semblies/rom/maps/routines­.html
  64. Channels and streams
    https://sinclair.wiki.zxnet­.co.uk/wiki/Channels_and_stre­ams

Autor článku

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