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
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
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
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
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
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
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
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/disassemblies/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
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.
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.
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:
- řídicí kód pro změnu barvy inkoustu
- index barvy inkoustu
- řídicí kód pro změnu barvy pozadí
- index barvy pozadí
- 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.
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.
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.
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
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ů:
- V registrovém páru BC musí být uložena délka řetězce
- 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.
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
- 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/ - Z80 Assembler for Dummies
https://www.msx.org/wiki/Z80_Assembler_for_Dummies - Z80 Resources
https://www.assemblytutorial.com/z80/ - How do Z80 Block Transfer instructions work?
https://retrocomputing.stackexchange.com/questions/5416/how-do-z80-block-transfer-instructions-work - How fast is memcpy on the Z80?
https://retrocomputing.stackexchange.com/questions/4744/how-fast-is-memcpy-on-the-z80 - Comparing Datapoint 2200, 8008, 8080 and Z80 Instruction Sets
https://bread80.com/comparing-datapoint-2200–8008–8080-and-z80-instruction-sets/ - 8080/Z80 Instruction Set
https://retroprogramming.it/2021/02/8080-z80-instruction-set/ - Zilog Z80A Technical Information
https://worldofspectrum.org/faq/reference/z80reference.htm - Z80 programming techniques – Loops
http://map.grauw.nl/articles/fast_loops.php - PRINT in Assembly Language
http://www.breakintoprogram.co.uk/hardware/computers/zx-spectrum/assembly-language/z80-tutorials/print-in-assembly-language - Spectrum ROM Routines
https://skoolkid.github.io/rom/maps/routines.html - Spectrum ROM Routines
https://skoolkit.ca/disassemblies/rom/maps/routines.html - Channels and streams
https://sinclair.wiki.zxnet.co.uk/wiki/Channels_and_streams