Ovládání hráčů ve hře klávesnicí nebo joystickem na ZX Spectru

25. 5. 2023
Doba čtení: 59 minut

Sdílet

 Autor: Depositphotos
Ukážeme si 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í: Kempston, Interface-2 atd.

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

7. Ovládání hráče joystickem

8. „Kurzorový“ joystick

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

19. Odkazy na Internetu

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).

Poznámka: v příkladech nijak neřešíme „vyjetí“ hráče z obrazovky. Ostatně si to můžeme vyzkoušet – vyjedeme s hráčem přes horní okraj obrazovky, čímž se zápisy začnou provádět přímo do bitmapové části obrazové paměti:

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
Poznámka: povšimněte si, že ve druhém případě musíme vynulovat příznak carry, jinak by posun hráče byl nikoli nahoru, ale šikmo nahoru+doleva.

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
Poznámka: celková délka kódu dosahuje 86 bajtů

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
Poznámka: velikost přeloženého strojového kódu klesla na 78 bajtů oproti původním 86 bajtům.

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.

Poznámka: relativně jednoduchým přeskládáním kódu a modifikací instrukcí pro rotaci lze program nepatrně zkrátit i nepatrně urychlit. Přijdete na to, v jakém místě kódu?

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:

  1. 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
  2. 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
Poznámka: v emulátoru Fuse může být podpora pro Kempston chybná (záleží na verzi Fuse), proto je lepší použít jiný emulátor ZX Spectra.

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ě:

ict ve školství 24

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

  1. z80 standalone assembler
    https://www.asm80.com/one­page/asmz80.html
  2. The ZX BASIC Compiler
    https://www.boriel.com/pages/the-zx-basic-compiler.html
  3. Z80 Assembly programming for the ZX Spectrum
    https://www.chibiakumas.com/z80/ZXSpec­trum.php
  4. 8-BIT SMACKDOWN! 65C02 vs. Z80: slithy VLOGS #6
    https://www.youtube.com/wat­ch?v=P1paVoFEvyc
  5. Instrukce mikroprocesoru Z80
    https://clrhome.org/table/
  6. Z80 instructions: adresní režimy atd.
    https://jnz.dk/z80/instructions.html
  7. Z80 Instruction Groups
    https://jnz.dk/z80/instgroups.html
  8. Elena, New programming language for the ZX Spectrum Next
    https://vintageisthenewold.com/elena-new-programming-language-for-the-zx-spectrum-next/
  9. Sinclair BASIC
    https://worldofspectrum.net/legacy-info/sinclair-basic/
  10. Grafika na osmibitových počítačích firmy Sinclair
    https://www.root.cz/clanky/grafika-na-osmibitovych-pocitacich-firmy-sinclair/
  11. Grafika na osmibitových počítačích firmy Sinclair II
    https://www.root.cz/clanky/grafika-na-osmibitovych-pocitacich-firmy-sinclair-ii/
  12. HiSoft BASIC
    https://worldofspectrum.net/in­foseekid.cgi?id=0008249
  13. YS MegaBasic
    https://worldofspectrum.net/in­foseekid.cgi?id=0008997
  14. Beta Basic
    https://worldofspectrum.net/in­foseekid.cgi?id=0007956
  15. BASIC+
    https://worldofspectrum.net/in­foseekid.php?id=0014277
  16. Spectrum ROM Memory Map
    https://skoolkit.ca/disas­semblies/rom/maps/all.html
  17. Goto subroutine
    https://skoolkit.ca/disas­semblies/rom/asm/7783.html
  18. Spectrum Next: The Evolution of the Speccy
    https://www.specnext.com/about/
  19. Sedmdesátiny assemblerů: lidsky čitelný strojový kód
    https://www.root.cz/clanky/sed­mdesatiny-assembleru-lidsky-citelny-strojovy-kod/
  20. Programovací jazyk BASIC na osmibitových mikropočítačích
    https://www.root.cz/clanky/pro­gramovaci-jazyk-basic-na-osmibitovych-mikropocitacich/
  21. Programovací jazyk BASIC na osmibitových mikropočítačích (2)
    https://www.root.cz/clanky/pro­gramovaci-jazyk-basic-na-osmibitovych-mikropocitacich-2/#k06
  22. Programovací jazyk BASIC na osmibitových mikropočítačích (3)
    https://www.root.cz/clanky/pro­gramovaci-jazyk-basic-na-osmibitovych-mikropocitacich-3/
  23. Sinclair BASIC (Wikipedia CZ)
    http://cs.wikipedia.org/wi­ki/Sinclair_BASIC
  24. Assembly Language: Still Relevant Today
    http://wilsonminesco.com/AssyDefense/
  25. Programovani v assembleru na OS Linux
    http://www.cs.vsb.cz/gryga­rek/asm/asmlinux.html
  26. Why Assembly Language Programming? (Why Learning Assembly Language Is Still a Good Idea)
    https://wdc65×x.com/market­s/education/why-assembly-language-programming/
  27. Low Fat Computing
    http://www.ultratechnology­.com/lowfat.htm
  28. Assembly Language
    https://www.cleverism.com/skills-and-tools/assembly-language/
  29. Why do we need assembly language?
    https://cs.stackexchange.com/qu­estions/13287/why-do-we-need-assembly-language
  30. Assembly language (Wikipedia)
    https://en.wikipedia.org/wi­ki/Assembly_language#Histo­rical_perspective
  31. Assembly languages
    https://curlie.org/Computer­s/Programming/Languages/As­sembly/
  32. vasm
    http://sun.hasenbraten.de/vasm/
  33. B-ELITE
    https://jsj.itch.io/b-elite
  34. ZX-Spectrum Child
    http://www.dotkam.com/2008/11/19/zx-spectrum-child/
  35. Speccy.cz
    http://www.speccy.cz/
  36. Planet Sinclair
    http://www.nvg.ntnu.no/sinclair/
  37. World of Spectrum
    http://www.worldofspectrum.org/
  38. The system variables
    https://worldofspectrum.or­g/ZXBasicManual/zxmanchap25­.html
  39. ZX Spectrum manual: chapter #17 Graphics
    https://worldofspectrum.or­g/ZXBasicManual/zxmanchap17­.html
  40. Why does Sinclair BASIC have two formats for storing numbers in the same structure?
    https://retrocomputing.stac­kexchange.com/questions/8834/why-does-sinclair-basic-have-two-formats-for-storing-numbers-in-the-same-structu
  41. Plovoucí řádová čárka na ZX Spectru
    https://www.root.cz/clanky/norma-ieee-754-a-pribuzni-formaty-plovouci-radove-tecky/#k05
  42. 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
  43. 1A1B: THE ‚REPORT AND LINE NUMBER PRINTING‘ SUBROUTINE
    https://skoolkid.github.i­o/rom/asm/1A1B.html
  44. 2DE3: THE ‚PRINT A FLOATING-POINT NUMBER‘ SUBROUTINE
    https://skoolkid.github.i­o/rom/asm/2DE3.html
  45. 5C63: STKBOT – Address of bottom of calculator stack
    https://skoolkid.github.i­o/rom/asm/5C63.html
  46. 5C65: STKEND – Address of start of spare space
    https://skoolkid.github.i­o/rom/asm/5C65.html
  47. Why does Sinclair BASIC have two formats for storing numbers in the same structure?
    https://retrocomputing.stac­kexchange.com/questions/8834/why-does-sinclair-basic-have-two-formats-for-storing-numbers-in-the-same-structu
  48. Chapter 24: The memory
    https://worldofspectrum.or­g/ZXBasicManual/zxmanchap24­.html
  49. Survey of Floating-Point Formats  
    https://mrob.com/pub/math/flo­atformats.html
  50. Convert an 8bit number to hex in z80 assembler
    https://stackoverflow.com/qu­estions/22838444/convert-an-8bit-number-to-hex-in-z80-assembler
  51. 80 MICROPROCESSOR Instruction Set Summary
    http://www.textfiles.com/pro­gramming/CARDS/z80
  52. Extended Binary Coded Decimal Interchange Code
    http://en.wikipedia.org/wiki/EBCDIC
  53. ASCII/EBCDIC Conversion Table
    http://docs.hp.com/en/32212–90008/apcs01.html
  54. EBCDIC
    http://www.hansenb.pdx.edu/DMKB/dic­t/tutorials/ebcdic.php
  55. EBCDIC tables
    http://home.mnet-online.de/wzwz.de/temp/eb­cdic/cc_en.htm
  56. The Mainframe Blog
    http://mainframe.typepad.com/blog/2006/11/my_per­sonal_mai.html
  57. Binary-coded decimal
    https://en.wikipedia.org/wiki/Binary-coded_decimal
  58. BCD
    https://cs.wikipedia.org/wiki/BCD
  59. Z80 heaven: Floating Point
    http://z80-heaven.wikidot.com/floating-point
  60. Z80, the 8-bit Number Cruncher
    http://www.andreadrian.de/ol­dcpu/Z80_number_cruncher.html
  61. Floating-point library for Z80
    https://github.com/DW0RKiN/Floating-point-Library-for-Z80
  62. z80float
    https://github.com/Zeda/z80float
  63. Fixed point arithmetic
    https://www.root.cz/clanky/fixed-point-arithmetic/
  64. ZX Spectrum BASIC Programming – 2nd Edition
    https://archive.org/details/zx-spectrum-basic-programming/page/n167/mode/2up
  65. ZX Spectrum BASIC Programming – 2nd Edition
    https://archive.org/details/zx-spectrum-basic-programming/page/n169/mode/2up
  66. How fast is memcpy on the Z80?
    https://retrocomputing.stac­kexchange.com/questions/4744/how-fast-is-memcpy-on-the-z80
  67. How do Z80 Block Transfer instructions work?
    https://retrocomputing.stac­kexchange.com/questions/5416/how-do-z80-block-transfer-instructions-work
  68. Retro Programming Made Simple: Keyboard
    http://www.breakintoprogram­.co.uk/hardware/computers/zx-spectrum/keyboard
  69. How ZX Spectrum avoided key ghosting
    https://retrocomputing.stac­kexchange.com/questions/16235/how-zx-spectrum-avoided-key-ghosting
  70. ZX Spectrum Keyboard Visualized
    http://www.kameli.net/marq/?p=2055
  71. Sinclair ZX Spectrum Joysticks Explained
    https://www.retroisle.com/ge­neral/spectrum_joysticks.php

Autor článku

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