Obsah
1. Ovládání hráčů ve hře klávesnicí nebo joystickem na ZX Spectru
2. Testování stisku kláves Q, A, O a P použitých pro pohyb hráče
3. Realizace pohybu hráče – šestnáctibitová aritmetika
4. Úplný zdrojový kód dnešního prvního demonstračního příkladu
5. Refaktoring: odstranění duplicitního kódu a test stisku kláves jednodušším způsobem
6. Úplný zdrojový kód dnešního druhého demonstračního příkladu
9. Realizace čtení polohy kurzorového joysticku
10. Úplný zdrojový kód dnešního třetího demonstračního příkladu
11. Joystick připojený přes Sinclair / Interface 2
12. Realizace čtení polohy joysticku připojeného přes Interface 2
13. Úplný zdrojový kód dnešního čtvrtého demonstračního příkladu
14. Joystick připojený přes rozhraní Kempston
15. Realizace čtení polohy joysticku připojeného přes rozhraní Kempston
16. Úplný zdrojový kód dnešního pátého demonstračního příkladu
17. Příloha: upravený soubor Makefile pro překlad demonstračních příkladů
18. Repositář s demonstračními příklady
1. Ovládání hráčů ve hře klávesnicí nebo joystickem na ZX Spectru
V dnešní části seriálu o vývoji programů pro legendární osmibitový domácí mikropočítač ZX Spectrum si ukážeme základní metody ovládání hráčů (postaviček) ve hrách, a to jak s využitím klávesnice, tak i pomocí joysticků připojených přes různá rozhraní („cursor“, Kempston, Interface-2 atd.).
Pro jednoduchost budeme „hráče“ zobrazovat formou čtverečku 8×8 pixelů, který vykreslíme tak, že se změní jeden atribut v atributové paměti. Adresa atributu s hráčem je uložena v registrovém páru HL, protože práce s ním je velmi flexibilní. Pro změnu atributu si vytvoříme makro (které vlastně jen „pojmenovává“ jedinou instrukci):
changeAttribute MACRO attribute ld (hl), attribute ENDM
Hráče umístíme zhruba doprostřed obrazovky, takže si vypočteme (nyní v čase překladu) jeho adresu v atributové paměti:
ATTRIBUTE_ADR equ $5800 INIT_X equ 15 INIT_Y equ 12 INIT_POSITION equ ATTRIBUTE_ADR + INIT_X + 32*INIT_Y
Nastavení pozice hráče je triviální:
ld hl, INIT_POSITION
S výsledkem:
Obrázek 1: Původní pozice hráče na obrazovce.
Samotná změna pozice hráče se provádí takto: smažeme původní obrázek hráče (tedy přepíšeme původní atribut), změníme obsah registrového páru HL (+1, –1, +32 nebo –32) a vykreslíme hráče na novou pozici:
changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici dec hl ; posun doleva o jeden bajt changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici
Obrázek 2: Posunutí hráče klávesnicí (nebo joystickem).
Obrázek 3: Hráč vyjel z atributové paměti do bitmapové části obrazové paměti.
2. Testování stisku kláves Q, A, O a P použitých pro pohyb hráče
V relativně velkém množství her určených pro ZX Spectrum se pro ovládání hráče používají klávesy Q, A (nahoru, dolů) a O, P (doleva, doprava). Tyto klávesy se čtou z různých portů, takže si připravíme jak symboly s adresami portů, tak i makro pro přečtení hodnoty z portu a nastavení příznaku zero podle toho, zda je konkrétní klávesa stisknuta či nikoli:
KB_ROW_0_PORT equ $fe KB_ROW_1_PORT equ $fd KB_ROW_2_PORT equ $fb KB_ROW_3_PORT equ $f7 KB_ROW_4_PORT equ $ef KB_ROW_5_PORT equ $df KB_ROW_6_PORT equ $bf KB_ROW_7_PORT equ $7f
Výše zmíněné makro přečte stav stisku pěti kláves na zvoleném fyzickém řádku a dále provede operaci AND se zvolenou bitovou maskou. Vzhledem k tomu, že maska vždy obsahuje jediný bit nastavený na jedničku, bude výsledkem příznak zero nastavený na logickou jedničku ve chvíli, kdy je daná klávesa stisknuta (a na nulu v opačném případě):
keypress MACRO port, mask ld b, port ; adresa portu, ze kterého budeme číst údaje in a, (c) ; vlastní čtení z portu (5 bitů) and mask ENDM
Samotná detekce stisku kláves Q, A, O a P s reakcí na jejich stisk může vypadat následovně:
ld c, $fe ; port, ze kterého se bude číst keypress KB_ROW_5_PORT, 1 << 0 ; test stisku klávesy P jr nz, p_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta ... ... ... p_not_pressed: keypress KB_ROW_5_PORT, 1 << 1 ; test stisku klávesy O jr nz, o_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta ... ... ... o_not_pressed: keypress KB_ROW_1_PORT, 1 << 0 ; test stisku klávesy A jr nz, a_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta ... ... ... a_not_pressed: keypress KB_ROW_2_PORT, 1 << 0 ; test stisku klávesy Q jr nz, q_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta ... ... ... q_not_pressed: call delay ; Z80 je pro nás moc rychlý :-) jr repeat ; opakovat
3. Realizace pohybu hráče – šestnáctibitová aritmetika
Pohyb hráče doleva a doprava je řešen triviálním způsobem – změní se atribut na původní adrese a nastaví se sousední atribut vlevo či vpravo, což v praxi znamená, že je nutné registrovou dvojici HL zvýšit či snížit o jedničku. To je u Z80 velmi jednoduchá úloha a celý posun hráče doleva a doprava lze naprogramovat takto:
changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici dec hl ; posun doleva o jeden bajt changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici
resp. pohyb doprava:
changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici inc hl ; posun doprava o jeden bajt changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici
Naproti tomu pohyb hráče nahoru nebo dolů vyžaduje šestnáctibitové ALU operace, konkrétně přičtení či odečtení konstanty 32. Šestnáctibitové aritmetické operace jsou mikroprocesorem Z80 taktéž podporovány, ovšem namísto konstanty je nutné použít jiný registrový pár, například BC (a navíc je cílem vždy dvojice HL). Proto si vytvoříme pomocná makra pro provedení těchto operací:
add_to_hl MACRO value ld b, 0 ld c, value add hl, bc ENDM
a:
sub_from_hl MACRO value ld b, 0 ld c, value or a ; vynulovat carry sbc hl, bc ENDM
Použití těchto maker je již přímočaré:
changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici add_to_hl 32 ; posun dolů (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici
a:
changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici sub_from_hl 32 ; posun nahoru (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici
4. Úplný zdrojový kód dnešního prvního demonstračního příkladu
Úplný zdrojový kód dnešního prvního demonstračního příkladu najdete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/98-game-character.asm:
ATTRIBUTE_ADR equ $5800 ENTRY_POINT equ $8000 ROM_CLS equ $0DAF org ENTRY_POINT BLINK_BIT equ %10000000 INTENSITY_BIT equ %01000000 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 RED_BLOCK equ INTENSITY_BIT | (RED_COLOR << 3) ORIG_BLOCK equ WHITE_COLOR << 3 INIT_X equ 15 INIT_Y equ 12 INIT_POSITION equ ATTRIBUTE_ADR + INIT_X + 32*INIT_Y KB_ROW_0_PORT equ $fe KB_ROW_1_PORT equ $fd KB_ROW_2_PORT equ $fb KB_ROW_3_PORT equ $f7 KB_ROW_4_PORT equ $ef KB_ROW_5_PORT equ $df KB_ROW_6_PORT equ $bf KB_ROW_7_PORT equ $7f changeAttribute MACRO attribute ld (hl), attribute ENDM keypress MACRO port, mask ld b, port ; adresa portu, ze kterého budeme číst údaje in a, (c) ; vlastní čtení z portu (5 bitů) and mask ENDM add_to_hl MACRO value ld b, 0 ld c, value add hl, bc ENDM sub_from_hl MACRO value ld b, 0 ld c, value or a ; vynulovat carry sbc hl, bc ENDM start: call ROM_CLS ; smazání obrazovky ld hl, INIT_POSITION changeAttribute RED_BLOCK ; vykreslit hráče na startovní pozici zhruba uprostřed obrazovky repeat: ld c, $fe ; port, ze kterého se bude číst keypress KB_ROW_5_PORT, 1 << 0 ; test stisku klávesy P jr nz, p_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici inc hl ; posun doprava o jeden bajt changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici p_not_pressed: keypress KB_ROW_5_PORT, 1 << 1 ; test stisku klávesy O jr nz, o_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici dec hl ; posun doleva o jeden bajt changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici o_not_pressed: keypress KB_ROW_1_PORT, 1 << 0 ; test stisku klávesy A jr nz, a_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici add_to_hl 32 ; posun dolů (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici a_not_pressed: keypress KB_ROW_2_PORT, 1 << 0 ; test stisku klávesy Q jr nz, q_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici sub_from_hl 32 ; posun nahoru (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici q_not_pressed: call delay ; Z80 je pro nás moc rychlý :-) jr repeat ; opakovat delay: ; zpožďovací rutina ; mění BC (což nám nevadí) ld b, 30 ; počitadlo vnější zpožďovací smyčky outer_loop: ld c, 0 ; počitadlo vnitřní zpožďovací smyčky inner_loop: dec c ; snížení hodnoty počitadla (v první iteraci 256->255) jr NZ, inner_loop ; opakovat, dokud není dosaženo nuly djnz outer_loop ; opakovat vnější smyčku, nyní s počitadlem v B ret ; návrat z podprogramu end ENTRY_POINT
Překlad tohoto demonstračního příkladu do strojového kódu vypadá následovně:
ATTRIBUTE_ADR EQU 5800 ENTRY_POINT EQU 8000 ROM_CLS EQU 0DAF ORG 8000 BLINK_BIT EQU 0080 INTENSITY_BIT EQU 0040 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 RED_BLOCK EQU 0050 ORIG_BLOCK EQU 0038 INIT_X EQU 000F INIT_Y EQU 000C INIT_POSITION EQU 598F KB_ROW_0_PORT EQU 00FE KB_ROW_1_PORT EQU 00FD KB_ROW_2_PORT EQU 00FB KB_ROW_3_PORT EQU 00F7 KB_ROW_4_PORT EQU 00EF KB_ROW_5_PORT EQU 00DF KB_ROW_6_PORT EQU 00BF KB_ROW_7_PORT EQU 007F Defining MACRO changeAttribute Params: attribute Defining MACRO keypress Params: port, mask Defining MACRO add_to_hl Params: value Defining MACRO sub_from_hl Params: value 8000: label start 8000:CDAF0D CALL 0DAF 8003:218F59 LD HL, 598F Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 8006:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 8008: label repeat 8008:0EFE LD C, FE Expanding MACRO keypress port= KB_ROW_5_PORT mask= 0001 << 0000 LD B , port 800A:06DF LD B, DF IN A , ( C ) 800C:ED78 IN A, (C) AND mask 800E:E601 AND 01 ENDM ENDM End of MACRO keypress 8010:2005 JR NZ, 8017 Expanding MACRO changeAttribute attribute= ORIG_BLOCK LD ( HL ) , attribute 8012:3638 LD (HL), 38 ENDM ENDM End of MACRO changeAttribute 8014:23 INC HL Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 8015:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 8017: label p_not_pressed Expanding MACRO keypress port= KB_ROW_5_PORT mask= 0001 << 0001 LD B , port 8017:06DF LD B, DF IN A , ( C ) 8019:ED78 IN A, (C) AND mask 801B:E602 AND 02 ENDM ENDM End of MACRO keypress 801D:2005 JR NZ, 8024 Expanding MACRO changeAttribute attribute= ORIG_BLOCK LD ( HL ) , attribute 801F:3638 LD (HL), 38 ENDM ENDM End of MACRO changeAttribute 8021:2B DEC HL Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 8022:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 8024: label o_not_pressed Expanding MACRO keypress port= KB_ROW_1_PORT mask= 0001 << 0000 LD B , port 8024:06FD LD B, FD IN A , ( C ) 8026:ED78 IN A, (C) AND mask 8028:E601 AND 01 ENDM ENDM End of MACRO keypress 802A:2009 JR NZ, 8035 Expanding MACRO changeAttribute attribute= ORIG_BLOCK LD ( HL ) , attribute 802C:3638 LD (HL), 38 ENDM ENDM End of MACRO changeAttribute Expanding MACRO add_to_hl value= 0020 LD B , 0000 802E:0600 LD B, 00 LD C , value 8030:0E20 LD C, 20 ADD HL , BC 8032:09 ADD HL, BC ENDM ENDM End of MACRO add_to_hl Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 8033:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 8035: label a_not_pressed Expanding MACRO keypress port= KB_ROW_2_PORT mask= 0001 << 0000 LD B , port 8035:06FB LD B, FB IN A , ( C ) 8037:ED78 IN A, (C) AND mask 8039:E601 AND 01 ENDM ENDM End of MACRO keypress 803B:200B JR NZ, 8048 Expanding MACRO changeAttribute attribute= ORIG_BLOCK LD ( HL ) , attribute 803D:3638 LD (HL), 38 ENDM ENDM End of MACRO changeAttribute Expanding MACRO sub_from_hl value= 0020 LD B , 0000 803F:0600 LD B, 00 LD C , value 8041:0E20 LD C, 20 OR A 8043:B7 OR A SBC HL , BC 8044:ED42 SBC HL, BC ENDM ENDM End of MACRO sub_from_hl Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 8046:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 8048: label q_not_pressed 8048:CD4D80 CALL 804D 804B:18BB JR 8008 804D: label delay 804D:061E LD B, 1E 804F: label outer_loop 804F:0E00 LD C, 00 8051: label inner_loop 8051:0D DEC C 8052:20FD JR NZ, 8051 8054:10F9 DJNZ 804F 8056:C9 RET 8057: END 8000 Emiting TAP basic loader Emiting TAP from 8000 to 8056
5. Refaktoring: odstranění duplicitního kódu a test stisku kláves jednodušším způsobem
Pokud se podíváme na výsledek překladu demonstračního příkladu z předchozí kapitoly, je zřejmé, že čtení každé klávesy je provedeno samostatnými instrukcemi, což není příliš rychlé (na druhou stranu nám nemusí na efektivitě této části kódu záležet, protože se bude volat jen několikrát za sekundu). Ale i tak se pokusme o malý refaktoring. Nejprve změníme makro pro čtení klávesy tak, aby se neprovádělo maskování:
keypress MACRO port ld b, port ; adresa portu, ze kterého budeme číst údaje in a, (c) ; vlastní čtení z portu (5 bitů) ENDM
Při čtení stavu klávesy se vrátíme k využití rotace bitů s jejich vysunutím do příznaku carry. Toho využijeme zejména u kláves O a P, které leží na jednom fyzickém řádku:
keypress KB_ROW_5_PORT ; test stisku klávesy O a P rra ; nultý bit do příznaku carry jr c, p_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici inc hl ; posun doprava o jeden bajt changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici p_not_pressed: rra ; první bit do příznaku carry jr c, o_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici dec hl ; posun doleva o jeden bajt changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici
Naproti tomu klávesy A a Q leží na jiných fyzických řádcích, ovšem na vhodném místě, které v kódu vyžaduje provedení jediné rotace:
o_not_pressed: keypress KB_ROW_1_PORT ; test stisku klávesy A rra ; nultý bit do příznaku carry jr c, a_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici add_to_hl 32 ; posun dolů (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici a_not_pressed: keypress KB_ROW_2_PORT ; test stisku klávesy Q rra ; nultý bit do příznaku carry jr c, q_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici sub_from_hl 32 ; posun nahoru (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici
Výsledný kód bude kratší a nepatrně rychlejší, ovšem lze jít ještě dále a využít příznak carry přímo ve výpočtu adresy hráče.
6. Úplný zdrojový kód dnešního druhého demonstračního příkladu
Úplný zdrojový kód dnešního druhého demonstračního příkladu najdete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/99-game-character-2.asm:
ATTRIBUTE_ADR equ $5800 ENTRY_POINT equ $8000 ROM_CLS equ $0DAF org ENTRY_POINT BLINK_BIT equ %10000000 INTENSITY_BIT equ %01000000 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 RED_BLOCK equ INTENSITY_BIT | (RED_COLOR << 3) ORIG_BLOCK equ WHITE_COLOR << 3 INIT_X equ 15 INIT_Y equ 12 INIT_POSITION equ ATTRIBUTE_ADR + INIT_X + 32*INIT_Y KB_ROW_0_PORT equ $fe KB_ROW_1_PORT equ $fd KB_ROW_2_PORT equ $fb KB_ROW_3_PORT equ $f7 KB_ROW_4_PORT equ $ef KB_ROW_5_PORT equ $df KB_ROW_6_PORT equ $bf KB_ROW_7_PORT equ $7f changeAttribute MACRO attribute ld (hl), attribute ENDM keypress MACRO port ld b, port ; adresa portu, ze kterého budeme číst údaje in a, (c) ; vlastní čtení z portu (5 bitů) ENDM add_to_hl MACRO value ld b, 0 ld c, value add hl, bc ENDM sub_from_hl MACRO value ld b, 0 ld c, value or a ; vynulovat carry sbc hl, bc ENDM start: call ROM_CLS ; smazání obrazovky ld hl, INIT_POSITION changeAttribute RED_BLOCK ; vykreslit hráče na startovní pozici zhruba uprostřed obrazovky repeat: ld c, $fe ; port, ze kterého se bude číst keypress KB_ROW_5_PORT ; test stisku klávesy O a P rra ; nultý bit do příznaku carry jr c, p_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici inc hl ; posun doprava o jeden bajt changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici p_not_pressed: rra ; první bit do příznaku carry jr c, o_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici dec hl ; posun doleva o jeden bajt changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici o_not_pressed: keypress KB_ROW_1_PORT ; test stisku klávesy A rra ; nultý bit do příznaku carry jr c, a_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici add_to_hl 32 ; posun dolů (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici a_not_pressed: keypress KB_ROW_2_PORT ; test stisku klávesy Q rra ; nultý bit do příznaku carry jr c, q_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici sub_from_hl 32 ; posun nahoru (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici q_not_pressed: call delay ; Z80 je pro nás moc rychlý :-) jr repeat ; opakovat delay: ; zpožďovací rutina ; mění BC (což nám nevadí) ld b, 30 ; počitadlo vnější zpožďovací smyčky outer_loop: ld c, 0 ; počitadlo vnitřní zpožďovací smyčky inner_loop: dec c ; snížení hodnoty počitadla (v první iteraci 256->255) jr NZ, inner_loop ; opakovat, dokud není dosaženo nuly djnz outer_loop ; opakovat vnější smyčku, nyní s počitadlem v B ret ; návrat z podprogramu end ENTRY_POINT
Překlad tohoto demonstračního příkladu do strojového kódu vypadá následovně:
ATTRIBUTE_ADR EQU 5800 ENTRY_POINT EQU 8000 ROM_CLS EQU 0DAF ORG 8000 BLINK_BIT EQU 0080 INTENSITY_BIT EQU 0040 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 RED_BLOCK EQU 0050 ORIG_BLOCK EQU 0038 INIT_X EQU 000F INIT_Y EQU 000C INIT_POSITION EQU 598F KB_ROW_0_PORT EQU 00FE KB_ROW_1_PORT EQU 00FD KB_ROW_2_PORT EQU 00FB KB_ROW_3_PORT EQU 00F7 KB_ROW_4_PORT EQU 00EF KB_ROW_5_PORT EQU 00DF KB_ROW_6_PORT EQU 00BF KB_ROW_7_PORT EQU 007F Defining MACRO changeAttribute Params: attribute Defining MACRO keypress Params: port Defining MACRO add_to_hl Params: value Defining MACRO sub_from_hl Params: value 8000: label start 8000:CDAF0D CALL 0DAF 8003:218F59 LD HL, 598F Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 8006:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 8008: label repeat 8008:0EFE LD C, FE Expanding MACRO keypress port= KB_ROW_5_PORT LD B , port 800A:06DF LD B, DF IN A , ( C ) 800C:ED78 IN A, (C) ENDM ENDM End of MACRO keypress 800E:1F RRA 800F:3805 JR C, 8016 Expanding MACRO changeAttribute attribute= ORIG_BLOCK LD ( HL ) , attribute 8011:3638 LD (HL), 38 ENDM ENDM End of MACRO changeAttribute 8013:23 INC HL Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 8014:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 8016: label p_not_pressed 8016:1F RRA 8017:3805 JR C, 801E Expanding MACRO changeAttribute attribute= ORIG_BLOCK LD ( HL ) , attribute 8019:3638 LD (HL), 38 ENDM ENDM End of MACRO changeAttribute 801B:2B DEC HL Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 801C:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 801E: label o_not_pressed Expanding MACRO keypress port= KB_ROW_1_PORT LD B , port 801E:06FD LD B, FD IN A , ( C ) 8020:ED78 IN A, (C) ENDM ENDM End of MACRO keypress 8022:1F RRA 8023:3809 JR C, 802E Expanding MACRO changeAttribute attribute= ORIG_BLOCK LD ( HL ) , attribute 8025:3638 LD (HL), 38 ENDM ENDM End of MACRO changeAttribute Expanding MACRO add_to_hl value= 0020 LD B , 0000 8027:0600 LD B, 00 LD C , value 8029:0E20 LD C, 20 ADD HL , BC 802B:09 ADD HL, BC ENDM ENDM End of MACRO add_to_hl Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 802C:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 802E: label a_not_pressed Expanding MACRO keypress port= KB_ROW_2_PORT LD B , port 802E:06FB LD B, FB IN A , ( C ) 8030:ED78 IN A, (C) ENDM ENDM End of MACRO keypress 8032:1F RRA 8033:380B JR C, 8040 Expanding MACRO changeAttribute attribute= ORIG_BLOCK LD ( HL ) , attribute 8035:3638 LD (HL), 38 ENDM ENDM End of MACRO changeAttribute Expanding MACRO sub_from_hl value= 0020 LD B , 0000 8037:0600 LD B, 00 LD C , value 8039:0E20 LD C, 20 OR A 803B:B7 OR A SBC HL , BC 803C:ED42 SBC HL, BC ENDM ENDM End of MACRO sub_from_hl Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 803E:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 8040: label q_not_pressed 8040:CD4580 CALL 8045 8043:18C3 JR 8008 8045: label delay 8045:061E LD B, 1E 8047: label outer_loop 8047:0E00 LD C, 00 8049: label inner_loop 8049:0D DEC C 804A:20FD JR NZ, 8049 804C:10F9 DJNZ 8047 804E:C9 RET 804F: END 8000 Emiting TAP basic loader Emiting TAP from 8000 to 804E
7. Ovládání hráče joystickem
Na ZX Spectru se pro ovládání her nemusí používat pouze klávesnice. Prakticky u každé hry se setkáme i s nabídkou použití joysticku. Těch existuje několik typů, přičemž se od sebe odlišují způsobem zapojení k ZX Spectru a tím pádem i způsobem čtení jejich stavu (ovšem díky jednoduchosti HW ZX Spectra i snahou o co nejmenší cenu joysticků je čtení jejich stavu triviální). Setkáme se s de-facto standardy pojmenovanými Kempston, Interface II (nebo též Sinclair), Protek, Fuller, Cursor atd.
Obrázek 4: Slavná hra JetPac nabízí pouze jeden joystick, protože vyšla jen několik měsíců po vydání samotného ZX Spectra, kdy nabídka rozhraní pro připojení joysticků nebyla úplná.
Proč však existuje několik (pseudo) standardů? Na rozdíl od tehdejších konkurenčních osmibitových domácích mikropočítačů (Atari od roku 1979, Commodore C64 vyšel přibližně ve stejnou dobu jako ZX Spectrum) neexistoval na původním ZX Spectru žádný konektor pro připojení joysticků. Výrobci periferních zařízení ovšem záhy přišli s řešením – joysticky se budou připojovat přes rozhraní připojené přímo na sběrnici mikroprocesoru, která byla vyvedena z boxu počítače a tedy relativně snadno dostupná. A je logické, že jednotliví výrobci prosazovali svoje řešení, kterých tak vzniklo hned několik (každé se svými přednostmi a zápory, jak ostatně uvidíme v dalším textu).
Obrázek 5: Další hra od stejného výrobce již nabízí dva typy joysticků.
8. „Kurzorový“ joystick
Podívejme se ještě jednou na klávesnici ZX Spectra. Nad klávesami 5, 6, 7 a 8 jsou nakresleny kurzorové šipky – a tyto klávesy (s přeřaďovačem) skutečně jako šipky fungují. Minimálně dvě společnosti (Protek a AGF) vyvinuly rozhraní pro joysticky, které emuluje právě kurzorové šipky a střelba je doplněna na klávesu 0. Předností je fakt, že i hry, které původně žádný joystick nepodporovaly, ale nabízely redefinici ovládacích kláves, mohou „kurzorový“ joystick přímo používat. Nevýhoda (a původní nelogičnost samotného ZX Spectra) spočívá v tom, že všech pět kláves 5, 6, 7, 8 a 0 nelze přečíst z jediného portu, takže se celý program může nepatrně zesložitit.
Obrázek 6: Klávesnice originálního ZX Spectra 48k (zobrazeno v emulátoru Fuse).
9. Realizace čtení polohy kurzorového joysticku
Jak jsme si již řekli v předchozí kapitole, není možné náklon (a střelbu) kurzorového joysticku zjistit přečtením jediného portu, ale je nutno číst stav kláves dvakrát – z fyzického řádku 3 a 4. Celá realizace rozeskoku může vypadat takto:
keypress KB_ROW_3_PORT ; test stisku klávesy 5 (joystick doleva) and 1 << 4 ; test hodnoty pátého bitu jr nz, left_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici dec hl ; posun doleva o jeden bajt changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici left_not_pressed: keypress KB_ROW_4_PORT ; test stisku klávesy 6,7,8 (joystick dolů, nahoru a doprava) rra ; třetí bit do příznaku carry rra rra jr c, right_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici inc hl ; posun doprava o jeden bajt changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici right_not_pressed: rra ; čtvrtý bit do příznaku carry jr c, down_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici sub_from_hl 32 ; posun nahoru (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici down_not_pressed: rra ; pátý bit do příznaku carry jr c, up_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici add_to_hl 32 ; posun dolů (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici
Zbytek programu zůstává stejný, takže se zde otevírá možnost realizovat výběr ovládání samomodifikujícím se kódem.
10. Úplný zdrojový kód dnešního třetího demonstračního příkladu
Úplný zdrojový kód dnešního třetího demonstračního příkladu najdete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/100-cursor-joystick.asm:
ATTRIBUTE_ADR equ $5800 ENTRY_POINT equ $8000 ROM_CLS equ $0DAF org ENTRY_POINT BLINK_BIT equ %10000000 INTENSITY_BIT equ %01000000 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 RED_BLOCK equ INTENSITY_BIT | (RED_COLOR << 3) ORIG_BLOCK equ WHITE_COLOR << 3 INIT_X equ 15 INIT_Y equ 12 INIT_POSITION equ ATTRIBUTE_ADR + INIT_X + 32*INIT_Y KB_ROW_0_PORT equ $fe KB_ROW_1_PORT equ $fd KB_ROW_2_PORT equ $fb KB_ROW_3_PORT equ $f7 KB_ROW_4_PORT equ $ef KB_ROW_5_PORT equ $df KB_ROW_6_PORT equ $bf KB_ROW_7_PORT equ $7f changeAttribute MACRO attribute ld (hl), attribute ENDM keypress MACRO port ld b, port ; adresa portu, ze kterého budeme číst údaje in a, (c) ; vlastní čtení z portu (5 bitů) ENDM add_to_hl MACRO value ld b, 0 ld c, value add hl, bc ENDM sub_from_hl MACRO value ld b, 0 ld c, value or a ; vynulovat carry sbc hl, bc ENDM start: call ROM_CLS ; smazání obrazovky ld hl, INIT_POSITION changeAttribute RED_BLOCK ; vykreslit hráče na startovní pozici zhruba uprostřed obrazovky repeat: ld c, $fe ; port, ze kterého se bude číst keypress KB_ROW_3_PORT ; test stisku klávesy 5 (joystick doleva) and 1 << 4 ; test hodnoty pátého bitu jr nz, left_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici dec hl ; posun doleva o jeden bajt changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici left_not_pressed: keypress KB_ROW_4_PORT ; test stisku klávesy 6,7,8 (joystick dolů, nahoru a doprava) rra ; třetí bit do příznaku carry rra rra jr c, right_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici inc hl ; posun doprava o jeden bajt changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici right_not_pressed: rra ; čtvrtý bit do příznaku carry jr c, down_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici sub_from_hl 32 ; posun nahoru (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici down_not_pressed: rra ; pátý bit do příznaku carry jr c, up_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici add_to_hl 32 ; posun dolů (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici up_not_pressed: call delay ; Z80 je pro nás moc rychlý :-) jr repeat ; opakovat delay: ; zpožďovací rutina ; mění BC (což nám nevadí) ld b, 30 ; počitadlo vnější zpožďovací smyčky outer_loop: ld c, 0 ; počitadlo vnitřní zpožďovací smyčky inner_loop: dec c ; snížení hodnoty počitadla (v první iteraci 256->255) jr NZ, inner_loop ; opakovat, dokud není dosaženo nuly djnz outer_loop ; opakovat vnější smyčku, nyní s počitadlem v B ret ; návrat z podprogramu end ENTRY_POINT
Překlad tohoto demonstračního příkladu do strojového kódu vypadá následovně:
ATTRIBUTE_ADR EQU 5800 ENTRY_POINT EQU 8000 ROM_CLS EQU 0DAF ORG 8000 BLINK_BIT EQU 0080 INTENSITY_BIT EQU 0040 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 RED_BLOCK EQU 0050 ORIG_BLOCK EQU 0038 INIT_X EQU 000F INIT_Y EQU 000C INIT_POSITION EQU 598F KB_ROW_0_PORT EQU 00FE KB_ROW_1_PORT EQU 00FD KB_ROW_2_PORT EQU 00FB KB_ROW_3_PORT EQU 00F7 KB_ROW_4_PORT EQU 00EF KB_ROW_5_PORT EQU 00DF KB_ROW_6_PORT EQU 00BF KB_ROW_7_PORT EQU 007F Defining MACRO changeAttribute Params: attribute Defining MACRO keypress Params: port Defining MACRO add_to_hl Params: value Defining MACRO sub_from_hl Params: value 8000: label start 8000:CDAF0D CALL 0DAF 8003:218F59 LD HL, 598F Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 8006:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 8008: label repeat 8008:0EFE LD C, FE Expanding MACRO keypress port= KB_ROW_3_PORT LD B , port 800A:06F7 LD B, F7 IN A , ( C ) 800C:ED78 IN A, (C) ENDM ENDM End of MACRO keypress 800E:E610 AND 10 8010:2005 JR NZ, 8017 Expanding MACRO changeAttribute attribute= ORIG_BLOCK LD ( HL ) , attribute 8012:3638 LD (HL), 38 ENDM ENDM End of MACRO changeAttribute 8014:2B DEC HL Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 8015:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 8017: label left_not_pressed Expanding MACRO keypress port= KB_ROW_4_PORT LD B , port 8017:06EF LD B, EF IN A , ( C ) 8019:ED78 IN A, (C) ENDM ENDM End of MACRO keypress 801B:1F RRA 801C:1F RRA 801D:1F RRA 801E:3805 JR C, 8025 Expanding MACRO changeAttribute attribute= ORIG_BLOCK LD ( HL ) , attribute 8020:3638 LD (HL), 38 ENDM ENDM End of MACRO changeAttribute 8022:23 INC HL Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 8023:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 8025: label right_not_pressed 8025:1F RRA 8026:380B JR C, 8033 Expanding MACRO changeAttribute attribute= ORIG_BLOCK LD ( HL ) , attribute 8028:3638 LD (HL), 38 ENDM ENDM End of MACRO changeAttribute Expanding MACRO sub_from_hl value= 0020 LD B , 0000 802A:0600 LD B, 00 LD C , value 802C:0E20 LD C, 20 OR A 802E:B7 OR A SBC HL , BC 802F:ED42 SBC HL, BC ENDM ENDM End of MACRO sub_from_hl Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 8031:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 8033: label down_not_pressed 8033:1F RRA 8034:3809 JR C, 803F Expanding MACRO changeAttribute attribute= ORIG_BLOCK LD ( HL ) , attribute 8036:3638 LD (HL), 38 ENDM ENDM End of MACRO changeAttribute Expanding MACRO add_to_hl value= 0020 LD B , 0000 8038:0600 LD B, 00 LD C , value 803A:0E20 LD C, 20 ADD HL , BC 803C:09 ADD HL, BC ENDM ENDM End of MACRO add_to_hl Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 803D:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 803F: label up_not_pressed 803F:CD4480 CALL 8044 8042:18C4 JR 8008 8044: label delay 8044:061E LD B, 1E 8046: label outer_loop 8046:0E00 LD C, 00 8048: label inner_loop 8048:0D DEC C 8049:20FD JR NZ, 8048 804B:10F9 DJNZ 8046 804D:C9 RET 804E: END 8000 Emiting TAP basic loader Emiting TAP from 8000 to 804D
11. Joystick připojený přes Sinclair / Interface 2
Další rozhraní pro joystick (resp. dokonce pro dva joysticky) se nazývá buď Interface 2 nebo (ve hrách) jednoduše Sinclair. Stav joysticku (náklon a střelba) je mapován na klávesy 1–5 pro první joystick a 6–0 pro druhý joystick. Přednosti tohoto rozhraní jsou dvě – jednodušší čtení každého joysticku (čtení z jediného portu pro všech pět bitů) a podpora dvou joysticků. Nevýhodou je, že se nejedná o řešení kompatibilní s kurzorovými šipkami (což ovšem v praxi nijak nevadí).
12. Realizace čtení polohy joysticku připojeného přes Interface 2
Čtení polohy a popř. i tlačítka joysticku připojeného přes Interface 2 je snadné, protože potřebujeme přečíst pouze stav jediného portu pro každý joystick a test jednotlivých bitů již probíhá s využitím instrukce rra, která vždy jeden z bitů vysune do příznaku carry. Celý program tedy bude v případě využití jediného joysticku nepatrně kratší než program předchozí (70 vs 73 bajtů):
ld c, $fe ; port, ze kterého se bude číst keypress KB_ROW_3_PORT ; test stisku klávesy 1 (joystick doleva) rra jr c, left_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici dec hl ; posun doleva o jeden bajt changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici left_not_pressed: rra jr c, right_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici inc hl ; posun doprava o jeden bajt changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici right_not_pressed: rra ; čtvrtý bit do příznaku carry jr c, down_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici add_to_hl 32 ; posun dolů (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici down_not_pressed: rra ; pátý bit do příznaku carry jr c, up_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici sub_from_hl 32 ; posun nahoru (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici up_not_pressed:
13. Úplný zdrojový kód dnešního čtvrtého demonstračního příkladu
Úplný zdrojový kód dnešního čtvrtého demonstračního příkladu najdete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/101-sinclair-joystick.asm:
ATTRIBUTE_ADR equ $5800 ENTRY_POINT equ $8000 ROM_CLS equ $0DAF org ENTRY_POINT BLINK_BIT equ %10000000 INTENSITY_BIT equ %01000000 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 RED_BLOCK equ INTENSITY_BIT | (RED_COLOR << 3) ORIG_BLOCK equ WHITE_COLOR << 3 INIT_X equ 15 INIT_Y equ 12 INIT_POSITION equ ATTRIBUTE_ADR + INIT_X + 32*INIT_Y KB_ROW_0_PORT equ $fe KB_ROW_1_PORT equ $fd KB_ROW_2_PORT equ $fb KB_ROW_3_PORT equ $f7 KB_ROW_4_PORT equ $ef KB_ROW_5_PORT equ $df KB_ROW_6_PORT equ $bf KB_ROW_7_PORT equ $7f changeAttribute MACRO attribute ld (hl), attribute ENDM keypress MACRO port ld b, port ; adresa portu, ze kterého budeme číst údaje in a, (c) ; vlastní čtení z portu (5 bitů) ENDM add_to_hl MACRO value ld b, 0 ld c, value add hl, bc ENDM sub_from_hl MACRO value ld b, 0 ld c, value or a ; vynulovat carry sbc hl, bc ENDM start: call ROM_CLS ; smazání obrazovky ld hl, INIT_POSITION changeAttribute RED_BLOCK ; vykreslit hráče na startovní pozici zhruba uprostřed obrazovky repeat: ld c, $fe ; port, ze kterého se bude číst keypress KB_ROW_3_PORT ; test stisku klávesy 1 (joystick doleva) rra jr c, left_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici dec hl ; posun doleva o jeden bajt changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici left_not_pressed: rra jr c, right_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici inc hl ; posun doprava o jeden bajt changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici right_not_pressed: rra ; čtvrtý bit do příznaku carry jr c, down_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici add_to_hl 32 ; posun dolů (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici down_not_pressed: rra ; pátý bit do příznaku carry jr c, up_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici sub_from_hl 32 ; posun nahoru (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici up_not_pressed: call delay ; Z80 je pro nás moc rychlý :-) jr repeat ; opakovat delay: ; zpožďovací rutina ; mění BC (což nám nevadí) ld b, 30 ; počitadlo vnější zpožďovací smyčky outer_loop: ld c, 0 ; počitadlo vnitřní zpožďovací smyčky inner_loop: dec c ; snížení hodnoty počitadla (v první iteraci 256->255) jr NZ, inner_loop ; opakovat, dokud není dosaženo nuly djnz outer_loop ; opakovat vnější smyčku, nyní s počitadlem v B ret ; návrat z podprogramu end ENTRY_POINT
Překlad tohoto demonstračního příkladu do strojového kódu vypadá následovně:
ATTRIBUTE_ADR EQU 5800 ENTRY_POINT EQU 8000 ROM_CLS EQU 0DAF ORG 8000 BLINK_BIT EQU 0080 INTENSITY_BIT EQU 0040 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 RED_BLOCK EQU 0050 ORIG_BLOCK EQU 0038 INIT_X EQU 000F INIT_Y EQU 000C INIT_POSITION EQU 598F KB_ROW_0_PORT EQU 00FE KB_ROW_1_PORT EQU 00FD KB_ROW_2_PORT EQU 00FB KB_ROW_3_PORT EQU 00F7 KB_ROW_4_PORT EQU 00EF KB_ROW_5_PORT EQU 00DF KB_ROW_6_PORT EQU 00BF KB_ROW_7_PORT EQU 007F Defining MACRO changeAttribute Params: attribute Defining MACRO keypress Params: port Defining MACRO add_to_hl Params: value Defining MACRO sub_from_hl Params: value 8000: label start 8000:CDAF0D CALL 0DAF 8003:218F59 LD HL, 598F Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 8006:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 8008: label repeat 8008:0EFE LD C, FE Expanding MACRO keypress port= KB_ROW_3_PORT LD B , port 800A:06F7 LD B, F7 IN A , ( C ) 800C:ED78 IN A, (C) ENDM ENDM End of MACRO keypress 800E:1F RRA 800F:3805 JR C, 8016 Expanding MACRO changeAttribute attribute= ORIG_BLOCK LD ( HL ) , attribute 8011:3638 LD (HL), 38 ENDM ENDM End of MACRO changeAttribute 8013:2B DEC HL Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 8014:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 8016: label left_not_pressed 8016:1F RRA 8017:3805 JR C, 801E Expanding MACRO changeAttribute attribute= ORIG_BLOCK LD ( HL ) , attribute 8019:3638 LD (HL), 38 ENDM ENDM End of MACRO changeAttribute 801B:23 INC HL Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 801C:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 801E: label right_not_pressed 801E:1F RRA 801F:3809 JR C, 802A Expanding MACRO changeAttribute attribute= ORIG_BLOCK LD ( HL ) , attribute 8021:3638 LD (HL), 38 ENDM ENDM End of MACRO changeAttribute Expanding MACRO add_to_hl value= 0020 LD B , 0000 8023:0600 LD B, 00 LD C , value 8025:0E20 LD C, 20 ADD HL , BC 8027:09 ADD HL, BC ENDM ENDM End of MACRO add_to_hl Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 8028:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 802A: label down_not_pressed 802A:1F RRA 802B:380B JR C, 8038 Expanding MACRO changeAttribute attribute= ORIG_BLOCK LD ( HL ) , attribute 802D:3638 LD (HL), 38 ENDM ENDM End of MACRO changeAttribute Expanding MACRO sub_from_hl value= 0020 LD B , 0000 802F:0600 LD B, 00 LD C , value 8031:0E20 LD C, 20 OR A 8033:B7 OR A SBC HL , BC 8034:ED42 SBC HL, BC ENDM ENDM End of MACRO sub_from_hl Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 8036:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 8038: label up_not_pressed 8038:CD3D80 CALL 803D 803B:18CB JR 8008 803D: label delay 803D:061E LD B, 1E 803F: label outer_loop 803F:0E00 LD C, 00 8041: label inner_loop 8041:0D DEC C 8042:20FD JR NZ, 8041 8044:10F9 DJNZ 803F 8046:C9 RET 8047: END 8000 Emiting TAP basic loader Emiting TAP from 8000 to 8046
14. Joystick připojený přes rozhraní Kempston
Konečně se dostáváme k pravděpodobně nejpopulárnějšímu rozhraní určenému pro připojení joysticků k ZX Spectru. Toto rozhraní bylo navrženo ve firmě Kempston a od všech předchozích rozhraní se liší ve dvou důležitých bodech:
- Neemuluje klávesnici, ale využívá se odlišný port, konkrétně port 31 (0×1f). Nemusí se tedy ani pracovat s registrem B při čtení stavu tohoto portu
- Logika čtení náklonu joysticku a stavu tlačítek je přímá (1=náklon či stisk) a nikoli inverzní, jak je tomu u klávesnice
15. Realizace čtení polohy joysticku připojeného přes rozhraní Kempston
Čtení náklonu joysticku připojeného přes rozhraní Kempston je triviální – pouze nesmíme zapomenout na přímou logiku, což znamená, že přeskok kódu realizujícího posun hráče se provede ve chvíli, kdy je bit s testovaným stavem (například náklon doleva) nulový (a nikoli nenulový):
KEMPSTON_PORT equ 31 repeat: ld bc, KEMPSTON_PORT ; adresa portu in a, (c) ; čtení z portu - zde bez použití registru B rra ; otestovat nejnižší bit jr nc, right_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici inc hl ; posun doprava o jeden bajt changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici right_not_pressed: rra ; otestovat druhý bit jr nc, left_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici dec hl ; posun doleva o jeden bajt changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici left_not_pressed: rra ; třetí bit do příznaku carry jr nc, up_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici add_to_hl 32 ; posun dolů (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici up_not_pressed: rra ; čtvrtý bit do příznaku carry jr nc, down_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici sub_from_hl 32 ; posun nahoru (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici down_not_pressed:
16. Úplný zdrojový kód dnešního pátého demonstračního příkladu
Úplný zdrojový kód dnešního pátého a současně i posledního demonstračního příkladu najdete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/102-kempston-joystick.asm:
ATTRIBUTE_ADR equ $5800 ENTRY_POINT equ $8000 ROM_CLS equ $0DAF org ENTRY_POINT BLINK_BIT equ %10000000 INTENSITY_BIT equ %01000000 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 RED_BLOCK equ INTENSITY_BIT | (RED_COLOR << 3) ORIG_BLOCK equ WHITE_COLOR << 3 INIT_X equ 15 INIT_Y equ 12 INIT_POSITION equ ATTRIBUTE_ADR + INIT_X + 32*INIT_Y KEMPSTON_PORT equ 31 changeAttribute MACRO attribute ld (hl), attribute ENDM add_to_hl MACRO value ld b, 0 ld c, value add hl, bc ENDM sub_from_hl MACRO value ld b, 0 ld c, value or a sbc hl, bc ENDM start: call ROM_CLS ; smazání obrazovky ld hl, INIT_POSITION changeAttribute RED_BLOCK ; vykreslit hráče na startovní pozici zhruba uprostřed obrazovky repeat: ld bc, KEMPSTON_PORT ; adresa portu in a, (c) ; čtení z portu rra ; otestovat nejnižší bit jr nc, right_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici inc hl ; posun doprava o jeden bajt changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici right_not_pressed: rra ; otestovat druhý bit jr nc, left_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici dec hl ; posun doleva o jeden bajt changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici left_not_pressed: rra ; třetí bit do příznaku carry jr nc, up_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici add_to_hl 32 ; posun dolů (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici up_not_pressed: rra ; čtvrtý bit do příznaku carry jr nc, down_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici sub_from_hl 32 ; posun nahoru (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici down_not_pressed: call delay ; Z80 je pro nás moc rychlý :-) jr repeat ; opakovat delay: ; zpožďovací rutina ; mění BC (což nám nevadí) ld b, 30 ; počitadlo vnější zpožďovací smyčky outer_loop: ld c, 0 ; počitadlo vnitřní zpožďovací smyčky inner_loop: dec c ; snížení hodnoty počitadla (v první iteraci 256->255) jr NZ, inner_loop ; opakovat, dokud není dosaženo nuly djnz outer_loop ; opakovat vnější smyčku, nyní s počitadlem v B ret ; návrat z podprogramu end ENTRY_POINT
Překlad tohoto demonstračního příkladu do strojového kódu vypadá následovně:
ATTRIBUTE_ADR EQU 5800 ENTRY_POINT EQU 8000 ROM_CLS EQU 0DAF ORG 8000 BLINK_BIT EQU 0080 INTENSITY_BIT EQU 0040 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 RED_BLOCK EQU 0050 ORIG_BLOCK EQU 0038 INIT_X EQU 000F INIT_Y EQU 000C INIT_POSITION EQU 598F KEMPSTON_PORT EQU 001F Defining MACRO changeAttribute Params: attribute Defining MACRO add_to_hl Params: value Defining MACRO sub_from_hl Params: value 8000: label start 8000:CDAF0D CALL 0DAF 8003:218F59 LD HL, 598F Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 8006:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 8008: label repeat 8008:011F00 LD BC, 001F 800B:ED78 IN A, (C) 800D:1F RRA 800E:3005 JR NC, 8015 Expanding MACRO changeAttribute attribute= ORIG_BLOCK LD ( HL ) , attribute 8010:3638 LD (HL), 38 ENDM ENDM End of MACRO changeAttribute 8012:23 INC HL Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 8013:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 8015: label right_not_pressed 8015:1F RRA 8016:3005 JR NC, 801D Expanding MACRO changeAttribute attribute= ORIG_BLOCK LD ( HL ) , attribute 8018:3638 LD (HL), 38 ENDM ENDM End of MACRO changeAttribute 801A:2B DEC HL Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 801B:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 801D: label left_not_pressed 801D:1F RRA 801E:3009 JR NC, 8029 Expanding MACRO changeAttribute attribute= ORIG_BLOCK LD ( HL ) , attribute 8020:3638 LD (HL), 38 ENDM ENDM End of MACRO changeAttribute Expanding MACRO add_to_hl value= 0020 LD B , 0000 8022:0600 LD B, 00 LD C , value 8024:0E20 LD C, 20 ADD HL , BC 8026:09 ADD HL, BC ENDM ENDM End of MACRO add_to_hl Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 8027:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 8029: label up_not_pressed 8029:1F RRA 802A:300B JR NC, 8037 Expanding MACRO changeAttribute attribute= ORIG_BLOCK LD ( HL ) , attribute 802C:3638 LD (HL), 38 ENDM ENDM End of MACRO changeAttribute Expanding MACRO sub_from_hl value= 0020 LD B , 0000 802E:0600 LD B, 00 LD C , value 8030:0E20 LD C, 20 OR A 8032:B7 OR A SBC HL , BC 8033:ED42 SBC HL, BC ENDM ENDM End of MACRO sub_from_hl Expanding MACRO changeAttribute attribute= RED_BLOCK LD ( HL ) , attribute 8035:3650 LD (HL), 50 ENDM ENDM End of MACRO changeAttribute 8037: label down_not_pressed 8037:CD3C80 CALL 803C 803A:18CC JR 8008 803C: label delay 803C:061E LD B, 1E 803E: label outer_loop 803E:0E00 LD C, 00 8040: label inner_loop 8040:0D DEC C 8041:20FD JR NZ, 8040 8043:10F9 DJNZ 803E 8045:C9 RET 8046: END 8000 Emiting TAP basic loader Emiting TAP from 8000 to 8045
17. 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 třinácti článcích [1] [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], 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 \ 31.tap 32.tap 33.tap 34.tap 35.tap 36.tap 37.tap 38.tap 39.tap 40.tap \ 41.tap 42.tap 43.tap 44.tap 45.tap 46.tap 47.tap 48.tap 49.tap 50.tap \ 51.tap 52.tap 53.tap 54.tap 55.tap 56.tap 57.tap 58.tap 59.tap 60.tap \ 61.tap 62.tap 63.tap 64.tap 65.tap 66.tap 67.tap 68.tap 69.tap 70.tap \ 71.tap 72.tap 73.tap 74.tap 75.tap 76.tap 77.tap 78.tap 79.tap 80.tap \ 81.tap 82.tap 83.tap 84.tap 85.tap 86.tap 87.tap 88.tap 80.tap 90.tap \ 91.tap 92.tap 93.tap 94.tap 95.tap 96.tap 97.tap 98.tap 99.tap 100.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 31.tap: 31-attributes.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 31-attributes.lst 32.tap: 32-fill-in-vram.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 32-fill-in-vram.lst 33.tap: 33-fill-in-vram-no-ret.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 33-fill-in-vram-no-ret.lst 34.tap: 34-fill-in-vram-pattern.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 34-fill-in-vram-pattern.lst 35.tap: 35-slow-fill-in-vram.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 35-slow-fill-in-vram.lst 36.tap: 36-slow-fill-in-vram-no-ret.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 36-slow-fill-in-vram-no-ret.lst 37.tap: 37-fill-block.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 37-fill-block.lst 38.tap: 38-fill-block-with-pattern.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 38-fill-block-with-pattern.lst 39.tap: 39-fill-block-optimized.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 39-fill-block-optimized.lst 40.tap: 40-draw-char.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 40-draw-char.lst 41.tap: 41-draw-any-char.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 41-draw-any-char.lst 42.tap: 42-block-anywhere.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 42-block-anywhere.lst 43.tap: 43-block-anywhere-rrca.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 43-block-anywhere-rrca.lst 44.tap: 44-better-draw-char.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 44-better-draw-char.lst 45.tap: 45-even-better-draw-char.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 45-even-better-draw-char.lst 46.tap: 46-draw-char-at.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 46-draw-char-at.lst 47.tap: 47-draw-char-at-unrolled.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 47-draw-char-at-unrolled.lst 48.tap: 48-incorrect-print-string.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 48-incorrect-print-string.lst 49.tap: 49-correct-print-string.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 49-correct-print-string.lst 50.tap: 50-ascii-table.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 50-ascii-table.lst 51.tap: 51-plot-block.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 51-plot-block.lst 52.tap: 52-plot-pixel.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 52-plot-pixel.lst 53.tap: 53-plot-pixel.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 53-plot-pixel.lst 54.tap: 54-plot-pixel-on-background.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 54-plot-pixel-on-background.lst 55.tap: 55-plot-pixel-on-background.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 55-plot-pixel-on-background.lst 56.tap: 56-inverse-ascii-table.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 56-inverse-ascii-table.lst 57.tap: 57-plot-pixel-on-inverse-background.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 57-plot-pixel-on-inverse-background.lst 58.tap: 58-plot-inverse-pixel-on-inverse-background.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 58-plot-inverse-pixel-on-inverse-background.lst 59.tap: 59-configurable-ascii-table.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 59-configurable-ascii-table.lst 60.tap: 60-plot-over.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 60-plot-over.lst 61.tap: 61-print-number-A.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 61-print-number-A.lst 62.tap: 62-print-number-B.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 62-print-number-B.lst 63.tap: 63-print-number-C.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 63-print-number-C.lst 64.tap: 64-print-number-D.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 64-print-number-D.lst 65.tap: 65-more-numbers-A.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 65-more-numbers-A.lst 66.tap: 66-more-numbers-B.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 66-more-numbers-B.lst 67.tap: 67-print-flags-1.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 67-print-flags-1.lst 68.tap: 68-print-flags-2.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 68-print-flags-2.lst 69.tap: 69-print-flags-3.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 69-print-flags-3.lst 70.tap: 70-print-flags-4.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 70-print-flags-4.lst 71.tap: 71-print-flags-5.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 71-print-flags-5.lst 72.tap: 72-print-flags-6.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 72-print-flags-6.lst 73.tap: 73-print-flags-7.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 73-print-flags-7.lst 74.tap: 74-print-hex-number.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 74-print-hex-number.lst 75.tap: 75-print-hex-number.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 75-print-hex-number.lst 76.tap: 76-print-hex-numbers.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 76-print-hex-numbers.lst 77.tap: 77-add-hex-numbers.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 77-add-hex-numbers.lst 78.tap: 78-add-bcd-numbers.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 78-add-bcd-numbers.lst 79.tap: 79-print-hex-digit-jmp.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 79-print-hex-digit-jmp.lst 80.tap: 80-print-hex-digit-overflow.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 80-print-hex-digit-overflow.lst 81.tap: 81-print-hex-digit-daa.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 81-print-hex-digit-daa.lst 82.tap: 82-print-hex-numbers-daa.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 82-print-hex-numbers-daa.lst 83.tap: 83-print-fp-numbers.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 83-print-fp-numbers.lst 84.tap: 84-print-ascii-table.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 84-print-ascii-table.lst 85.tap: 85-copy-ascii-table.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 85-copy-ascii-table.lst 86.tap: 86-copy-ascii-table-B.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 86-copy-ascii-table-B.lst 87.tap: 87-copy-ascii-table-C.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 87-copy-ascii-table-C.lst 88.tap: 88-copy-ascii-table-D.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 88-copy-ascii-table-D.lst 89.tap: 89-copy-ascii-table-E.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 89-copy-ascii-table-E.lst 90.tap: 90-copy-ascii-table-F.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 90-copy-ascii-table-F.lst 91.tap: 91-copy-ascii-table-G.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 91-copy-ascii-table-G.lst 92.tap: 92-copy-ascii-table-H.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 92-copy-ascii-table-H.lst 93.tap: 93-copy-ascii-table-I.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 93-copy-ascii-table-I.lst 94.tap: 94-color-attribute.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 94-color-attribute.lst 95.tap: 95-keypress.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 95-keypress.lst 96.tap: 96-keypress-row.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 96-keypress-row.lst 97.tap: 97-keypress-all-rows.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 97-keypress-all-rows.lst 98.tap: 98-game-character.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 98-game-character.lst 99.tap: 99-game-character-2.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 99-game-character-2.lst 100.tap: 100-cursor-joystick.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 100-cursor-joystick.lst 101.tap: 101-sinclair-joystick.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 101-sinclair-joystick.lst 102.tap: 102-kempston-joystick.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 102-kempston-joystick.lst
18. 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 | 31-attributes.asm | modifikace atributů pro tisk řetězce subrutinou uloženou v ROM | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/31-attributes.asm |
32 | 32-fill-in-vram.asm | vyplnění celé bitmapy barvou popředí, návrat do systému | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/32-fill-in-vram.asm |
33 | 33-fill-in-vram-no-ret.asm | vyplnění celé bitmapy barvou popředí, bez návratu do systému | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/33-fill-in-vram-no-ret.asm |
34 | 34-fill-in-vram-pattern.asm | vyplnění celé bitmapy zvoleným vzorkem | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/34-fill-in-vram-pattern.asm |
35 | 35-slow-fill-in-vram.asm | pomalé vyplnění celé bitmapy, vizualizace struktury bitmapy | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/35-slow-fill-in-vram.asm |
36 | 36-slow-fill-in-vram-no-ret.asm | pomalé vyplnění celé bitmapy, vizualizace struktury bitmapy, bez návratu do systému | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/36-slow-fill-in-vram-no-ret.asm |
37 | 37-fill-block.asm | vykreslení bloku 8×8 pixelů | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/37-fill-block.asm |
38 | 38-fill-block-with-pattern.asm | vykreslení bloku 8×8 pixelů zvoleným vzorkem | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/38-fill-block-with-pattern.asm |
39 | 39-fill-block-optimized.asm | optimalizace předchozího příkladu | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/39-fill-block-optimized.asm |
40 | 40-draw-char.asm | vykreslení znaku do levého horního rohu | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/40-draw-char.asm |
41 | 41-draw-any-char.asm | podprogram pro vykreslení libovolně zvoleného znaku do levého horního rohu | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/41-draw-any-char.asm |
42 | 42-block-anywhere.asm | podprogramy pro vykreslení bloku 8×8 pixelů kamkoli na obrazovku | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/42-block-anywhere.asm |
43 | 43-block-anywhere-rrca.asm | podprogramy pro vykreslení bloku 8×8 pixelů kamkoli na obrazovku, vylepšená varianta | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/43-block-anywhere-rrca.asm |
44 | 44-better-draw-char.asm | vykreslení znaku v masce 8×8 pixelů, vylepšená varianta | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/44-better-draw-char.asm |
45 | 45-even-better-draw-char.asm | posun offsetu pro vykreslení dalšího znaku | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/45-even-better-draw-char.asm |
46 | 46-draw-char-at.asm | vykreslení znaku v masce 8×8 pixelů kamkoli na obrazovku | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/46-draw-char-at.asm |
47 | 47-draw-char-at-unrolled.asm | vykreslení znaku v masce 8×8 pixelů kamkoli na obrazovku | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/47-draw-char-at-unrolled.asm |
48 | 48-incorrect-print-string.asm | tisk řetězce, nekorektní varianta | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/48-incorrect-print-string.asm |
49 | 49-correct-print-string.asm | tisk řetězce, korektní varianta | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/49-correct-print-string.asm |
50 | 50-ascii-table.asm | tisk několika bloků ASCII tabulky | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/50-ascii-table.asm |
51 | 51-plot-block.asm | vykreslení pixelu verze 1: zápis celého bajtu na pozici pixelu | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/51-plot-block.asm |
52 | 52-plot-pixel.asm | vykreslení pixelu verze 2: korektní vykreslení jednoho pixelu, ovšem překreslení celého bajtu | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/52-plot-pixel.asm |
53 | 53-plot-pixel.asm | vykreslení pixelu verze 3: vylepšená verze předchozího demonstračního příkladu | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/53-plot-pixel.asm |
54 | 54-plot-pixel-on-background.asm | vykreslení pixelu vůči pozadí (nekorektní varianta) | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/54-plot-pixel-on-background.asm |
55 | 55-plot-pixel-on-background.asm | vykreslení pixelu vůči pozadí (korektní varianta) | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/55-plot-pixel-on-background.asm |
56 | 56-inverse-ascii-table.asm | vykreslení ASCII tabulky inverzní barvou (inkoust vs. papír) | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/56-inverse-ascii-table.asm |
57 | 57-plot-pixel-on-inverse-background.asm | vykreslení pixelů barvou papíru proti inverzní ASCII tabulce | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/57-plot-pixel-on-inverse-background.asm |
58 | 58-plot-inverse-pixel-on-inverse-background.asm | vykreslení pixelů inverzní barvou proti inverzní ASCII tabulce | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm58-plot-inverse-pixel-on-inverse-background.asm/ |
59 | 59-configurable-ascii-table.asm | vykreslení ASCII tabulky buď přímo inkoustem nebo inverzně | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/59-configurable-ascii-table.asm |
60 | 60-plot-over.asm | přibližná implementace příkazu PLOT OVER | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/60-plot-over.asm |
61 | 61-print-number-A.asm | ukázka použití podprogramu pro tisk celého čísla | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/61-print-number-A.asm |
62 | 62-print-number-B.asm | pokus o vytištění záporných čísel | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/62-print-number-B.asm |
63 | 63-print-number-C.asm | tisk maximální podporované hodnoty 9999 | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/63-print-number-C.asm |
64 | 64-print-number-D.asm | tisk vyšší než podporované hodnoty 10000 | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/64-print-number-D.asm |
65 | 65-more-numbers-A.asm | vytištění číselné řady | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/65-more-numbers-A.asm |
66 | 66-more-numbers-B.asm | kombinace tisku celočíselných hodnot s dalšími subrutinami | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/66-more-numbers-B.asm |
67 | 67-print-flags-1.asm | příznakové bity po provedení celočíselné operace 1+2 | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/67-print-flags-1.asm |
68 | 68-print-flags-2.asm | příznakové bity po provedení celočíselné operace 0+0 | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/68-print-flags-2.asm |
69 | 69-print-flags-3.asm | příznakové bity po provedení operace 255+1 | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/69-print-flags-3.asm |
70 | 70-print-flags-4.asm | příznakové bity po provedení operace 254+1 | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/70-print-flags-4.asm |
71 | 71-print-flags-5.asm | příznakové bity po provedení operace 255+255 | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/71-print-flags-5.asm |
72 | 72-print-flags-6.asm | výsledek operace 100+100, nastavení příznakových bitů | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/72-print-flags-6.asm |
73 | 73-print-flags-7.asm | výsledek operace 128+128, nastavení příznakových bitů | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/73-print-flags-7.asm |
74 | 74-print-hex-number.asm | tisk hexadecimálního čísla v rozsahu 0×00 až 0×ff (neoptimalizovaná varianta) | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/74-print-hex-number.asm |
75 | 75-print-hex-number.asm | tisk hexadecimálního čísla v rozsahu 0×00 až 0×ff (optimalizovaná varianta) | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/75-print-hex-number.asm |
76 | 76-print-hex-numbers.asm | tisk několika hexadecimálních hodnot | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/76-print-hex-numbers.asm |
77 | 77-add-hex-numbers.asm | součet dvou osmibitových hexadecimálních hodnot s tiskem všech výsledků | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/77-add-hex-numbers.asm |
78 | 78-add-bcd-numbers.asm | součet dvou osmibitových BCD hodnot s tiskem všech výsledků | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/78-add-bcd-numbers.asm |
79 | 79-print-hex-digit-jmp.asm | tisk jedné hexadecimální cifry s využitím podmíněného skoku | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/79-print-hex-digit-jmp.asm |
80 | 80-print-hex-digit-overflow.asm | otestování, jaký znak je vytištěn pro hodnoty větší než 15 | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/80-print-hex-digit-overflow.asm |
81 | 81-print-hex-digit-daa.asm | tisk jedné hexadecimální cifry s využitím instrukce DAA | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/81-print-hex-digit-daa.asm |
82 | 82-print-hex-numbers-daa.asm | tisk série hexadecimálních hodnot s využitím instrukce DAA | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/82-print-hex-numbers-daa.asm |
83 | 83-print-fp-numbers.asm | tisk numerických hodnot reprezentovaných v systému plovoucí řádové tečky | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/83-print-fp-numbers.asm |
84 | 84-print-ascii-table.asm | tisk jednoho bloku s ASCII tabulkou | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/84-print-ascii-table.asm |
85 | 85-copy-ascii-table.asm | kopie bloku bajt po bajtu založená na naivní programové smyčce | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/85-copy-ascii-table.asm |
86 | 86-copy-ascii-table-B.asm | kopie bloku s využitím instrukce LDIR | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/86-copy-ascii-table-B.asm |
87 | 87-copy-ascii-table-C.asm | kopie bloku bajt po bajtu založená na programové smyčce a instrukci LDI | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/87-copy-ascii-table-C.asm |
88 | 88-copy-ascii-table-D.asm | rozbalení programové smyčky s instrukcí LDI | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/88-copy-ascii-table-D.asm |
89 | 89-copy-ascii-table-E.asm | korektní smyčka pro všechny možné velikosti bloků | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/89-copy-ascii-table-E.asm |
90 | 90-copy-ascii-table-F.asm | kostra programu, který pro kopii bloků (16 bajtů) využívá zásobník | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/90-copy-ascii-table-F.asm |
91 | 91-copy-ascii-table-G.asm | definice makra a několikeré použití (aplikace) tohoto makra | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/91-copy-ascii-table-G.asm |
92 | 92-copy-ascii-table-H.asm | opakování makra založené na REPT | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/92-copy-ascii-table-H.asm |
93 | 93-copy-ascii-table-I.asm | vícenásobná kopie části obrazovky | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/93-copy-ascii-table-I.asm |
94 | 94-color-attribute.asm | modifikace jednoho barvového atributu na obrazovce ZX Spectra | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/94-color-attribute.asm |
95 | 95-keypress.asm | detekce stisku jedné klávesy s vizualizací stisku | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/95-keypress.asm |
96 | 96-keypress-row.asm | detekce stisku kláves v jednom fyzickém řádku | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/96-keypress-row.asm |
97 | 97-keypress-all-rows.asm | detekce stisku všech kláves klávesnice ZX Spectra 48k | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/97-keypress-all-rows.asm |
98 | 98-game-character.asm | zajištění pohybu hráče v herní scéně s využitím klávesnice | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/98-game-character.asm |
99 | 99-game-character-2.asm | vylepšení předchozího demonstračního příkladu | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/99-game-character-2.asm |
100 | 100-cursor-joystick.asm | zajištění pohybu hráče v herní scéně kurzorovým joystickem | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/100-cursor-joystick.asm |
101 | 101-sinclair-joystick.asm | zajištění pohybu hráče v herní scéně joystickem připojeným přes Interface 2 | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/101-sinclair-joystick.asm |
102 | 102-kempston-joystick.asm | zajištění pohybu hráče v herní scéně joystickem připojeným přes rozhraní Kempston | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/102-kempston-joystick.asm |
103 | 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 |
19. 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/ - The system variables
https://worldofspectrum.org/ZXBasicManual/zxmanchap25.html - ZX Spectrum manual: chapter #17 Graphics
https://worldofspectrum.org/ZXBasicManual/zxmanchap17.html - Why does Sinclair BASIC have two formats for storing numbers in the same structure?
https://retrocomputing.stackexchange.com/questions/8834/why-does-sinclair-basic-have-two-formats-for-storing-numbers-in-the-same-structu - Plovoucí řádová čárka na ZX Spectru
https://www.root.cz/clanky/norma-ieee-754-a-pribuzni-formaty-plovouci-radove-tecky/#k05 - Norma IEEE 754 a příbuzní: formáty plovoucí řádové tečky
https://www.root.cz/clanky/norma-ieee-754-a-pribuzni-formaty-plovouci-radove-tecky/#k05 - 1A1B: THE ‚REPORT AND LINE NUMBER PRINTING‘ SUBROUTINE
https://skoolkid.github.io/rom/asm/1A1B.html - 2DE3: THE ‚PRINT A FLOATING-POINT NUMBER‘ SUBROUTINE
https://skoolkid.github.io/rom/asm/2DE3.html - 5C63: STKBOT – Address of bottom of calculator stack
https://skoolkid.github.io/rom/asm/5C63.html - 5C65: STKEND – Address of start of spare space
https://skoolkid.github.io/rom/asm/5C65.html - Why does Sinclair BASIC have two formats for storing numbers in the same structure?
https://retrocomputing.stackexchange.com/questions/8834/why-does-sinclair-basic-have-two-formats-for-storing-numbers-in-the-same-structu - Chapter 24: The memory
https://worldofspectrum.org/ZXBasicManual/zxmanchap24.html - Survey of Floating-Point Formats
https://mrob.com/pub/math/floatformats.html - Convert an 8bit number to hex in z80 assembler
https://stackoverflow.com/questions/22838444/convert-an-8bit-number-to-hex-in-z80-assembler - 80 MICROPROCESSOR Instruction Set Summary
http://www.textfiles.com/programming/CARDS/z80 - Extended Binary Coded Decimal Interchange Code
http://en.wikipedia.org/wiki/EBCDIC - ASCII/EBCDIC Conversion Table
http://docs.hp.com/en/32212–90008/apcs01.html - EBCDIC
http://www.hansenb.pdx.edu/DMKB/dict/tutorials/ebcdic.php - EBCDIC tables
http://home.mnet-online.de/wzwz.de/temp/ebcdic/cc_en.htm - The Mainframe Blog
http://mainframe.typepad.com/blog/2006/11/my_personal_mai.html - Binary-coded decimal
https://en.wikipedia.org/wiki/Binary-coded_decimal - BCD
https://cs.wikipedia.org/wiki/BCD - Z80 heaven: Floating Point
http://z80-heaven.wikidot.com/floating-point - Z80, the 8-bit Number Cruncher
http://www.andreadrian.de/oldcpu/Z80_number_cruncher.html - Floating-point library for Z80
https://github.com/DW0RKiN/Floating-point-Library-for-Z80 - z80float
https://github.com/Zeda/z80float - Fixed point arithmetic
https://www.root.cz/clanky/fixed-point-arithmetic/ - ZX Spectrum BASIC Programming – 2nd Edition
https://archive.org/details/zx-spectrum-basic-programming/page/n167/mode/2up - ZX Spectrum BASIC Programming – 2nd Edition
https://archive.org/details/zx-spectrum-basic-programming/page/n169/mode/2up - How fast is memcpy on the Z80?
https://retrocomputing.stackexchange.com/questions/4744/how-fast-is-memcpy-on-the-z80 - How do Z80 Block Transfer instructions work?
https://retrocomputing.stackexchange.com/questions/5416/how-do-z80-block-transfer-instructions-work - Retro Programming Made Simple: Keyboard
http://www.breakintoprogram.co.uk/hardware/computers/zx-spectrum/keyboard - How ZX Spectrum avoided key ghosting
https://retrocomputing.stackexchange.com/questions/16235/how-zx-spectrum-avoided-key-ghosting - ZX Spectrum Keyboard Visualized
http://www.kameli.net/marq/?p=2055 - Sinclair ZX Spectrum Joysticks Explained
https://www.retroisle.com/general/spectrum_joysticks.php