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