Vykreslování spritů a animací na ZX Spectru (2. část)

15. 8. 2023
Doba čtení: 56 minut

Sdílet

Autor: Depositphotos
V předchozím článku jsme si ukázali, jak lze na obrazovku ZX Spectra vykreslit sprite definovaný svojí maskou. Ovšem prozatím není čas na jásání, protože naše vykreslovací rutina má mnoho nedostatků.

Obsah

1. Vykreslování spritů a animací na ZX Spectru (2. část)

2. Urychlení vykreslování – optimalizace subrutiny draw8_lines

3. Úplný zdrojový kód dnešního druhého demonstračního příkladu

4. Nedostatky podprogramu pro vykreslení spritu na obrazovku ZX Spectra

5. Chybějící kontrola, zda sprite nepřesahuje pravý či levý okraj obrazovky

6. Úplný zdrojový kód dnešního druhého demonstračního příkladu

7. Chybějící kontrola, zda sprite nepřesahuje dolní okraj obrazovky

8. Úplný zdrojový kód dnešního třetího demonstračního příkladu

9. Sprite, jehož maska přesahuje přes třetinu obrazovky

10. Úplný zdrojový kód dnešního čtvrtého demonstračního příkladu

11. Chyby při zobrazení spritu na nekonstantním pozadí

12. Vykreslení statického obrázku na obrazovku ZX Spectra

13. Zobrazení spritů ve scéně s obrázkem na pozadí

14. Úplný zdrojový kód dnešního šestého demonstračního příkladu

15. Korektní výpočet adres zapisovaných bajtů při zobrazení spritu

16. Úplný zdrojový kód dnešního sedmého demonstračního příkladu

17. Jak dále?

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

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

20. Odkazy na Internetu

1. Vykreslování spritů a animací na ZX Spectru (2. část)

Na předchozí část seriálu o tvorbě her i dalších aplikací určených pro slavné ZX Spectrum dnes navážeme. Připomeňme si, že minule jsme si ukázali, jakým způsobem je možné na obrazovku ZX Spectra vykreslit takzvaný sprite, což je v kontextu osmibitových mikropočítačů a herních konzolí termín označující pohyblivý a většinou i animovaný obrázek nějaké herní postavičky. Prozatím umíme vykreslit sprite o libovolné velikosti, i když – jak uvidíme dále – má náš postup prozatím velmi mnoho problémů a bude ho nutné v mnoha ohledech vylepšit a taktéž opravit.

Základní verze programu napsaného v assembleru mikroprocesoru Zilog Z80, který je určen pro vykreslení postavičky o rozměru 24×24 pixelů (v tomto případě navíc bez podpory plynulého posunu o jednotlivé pixely) vypadala následovně. Samotná data s maskou spritu jsou v této variantě součástí zdrojového kódu:

SCREEN_ADR      equ $4000
ENTRY_POINT     equ $8000
 
        org ENTRY_POINT
 
start:
        ld b, 15                 ; x-ová souřadnice
        ld c, 3                  ; y-ová souřadnice
        call calc_sprite_address ; výpočet adresy spritu
        call draw_sprite
 
        ld b, 29                 ; x-ová souřadnice
        ld c, 21                 ; y-ová souřadnice
        call calc_sprite_address ; výpočet adresy
        call draw_sprite
 
finish:
        jr finish                ; žádný návrat do systému
 
 
calc_sprite_address:
        ; parametry:
        ; B - x-ová souřadnice (ve znacích, ne pixelech)
        ; C - y-ová souřadnice (ve znacích, ne pixelech)
        ;
        ; návratové hodnoty:
        ; DE - adresa pro zápis bloku
        ;
        ; vzor adresy:
        ; 0 1 0 Y4 Y3 0 0 0 | Y2 Y1 Y0 X4 X3 X2 X1 X0
        ld  a, c
        and %00000111            ; pouze spodní tři bity y-ové souřadnice (řádky 0..7)
        rrca
        rrca
        rrca                     ; nyní jsou čísla řádků v horních třech bitech
        or  b                    ; připočítat x-ovou souřadnici
        ld  e, a                 ; máme spodní bajt adresy
                                 ; Y2 Y1 Y0 X4 X3 X2 X1 X0
 
        ld  a, c                 ; y-ová souřadnice
        and %00011000            ; dva bity s indexem "bloku" 0..3 (dolní tři bity už máme zpracovány)
        or  %01000000            ; "posun" do obrazové paměti (na 0x4000)
        ld  d, a                 ; máme horní bajt adresy
                                 ; 0 1 0 Y5 Y4 0 0 0
        ret                      ; návrat z podprogramu
 
 
add_e MACRO n                    ; zvýšení hodnoty regitru E
        ld   a, e
        add  a, n
        ld   e, a
endm
 
draw_sprite:
        ld hl, SPRITE_ADR        ; adresa, od níž začíná maska spritu
        push de
        call draw_8_lines        ; vykreslit prvních 8 řádků spritu
 
        pop  de
        add_e 32                 ; zvýšit E o hodnotu 32
        push de
        call draw_8_lines        ; vykreslit druhých 8 řádků spritu
 
        pop  de
        add_e 32                 ; zvýšit E o hodnotu 32
        call draw_8_lines        ; vykreslit třetích 8 řádků spritu
 
        ret                      ; návrat z podprogramu
 
 
draw_8_lines:
        ld b, 8                  ; počitadlo zapsaných řádků
 
loop:
        ld  a,(hl)               ; načtení jednoho bajtu z masky
        ld  (de),a               ; zápis hodnoty na adresu (DE)
        inc hl                   ; posun na další bajt masky
        inc e
 
        ld  a,(hl)               ; načtení jednoho bajtu z masky
        ld  (de),a               ; zápis hodnoty na adresu (DE)
        inc hl                   ; posun na další bajt masky
        inc e
 
        ld  a,(hl)               ; načtení jednoho bajtu z masky
        ld  (de),a               ; zápis hodnoty na adresu (DE)
        inc hl                   ; posun na další bajt masky
 
        inc d                    ; posun na definici dalšího obrazového řádku
        dec e                    ; korekce - posun zpět pod první osmici pixelů
        dec e                    ; dtto
        djnz loop                ; vnitřní smyčka: blok s 3x osmi zápisy
        ret                      ; návrat z podprogramu
 
 
SPRITE_ADR
        db %00000000, %00000000, %00000000
        db %00000000, %00000000, %00000000
        db %00000001, %11110000, %00010000
        db %00000011, %00111000, %00010000
        db %00000101, %11010111, %00010000
        db %00000101, %11001100, %00010000
        db %00000101, %00110000, %00010000
        db %00000100, %11001000, %00010000
        db %00000111, %00110110, %00010000
        db %00001100, %11111110, %00111000
        db %00011111, %11111000, %00000000
        db %00000000, %00000000, %00110000
        db %00000011, %11111111, %10110000
        db %00000101, %11111110, %11100000
        db %00001110, %11111101, %11000000
        db %00011000, %11111100, %00000000
        db %00011000, %00000000, %00000000
        db %00000001, %11111000, %00000000
        db %00000011, %11111100, %00000000
        db %00000001, %10110000, %00000000
        db %00000010, %00001100, %00000000
        db %00000111, %00001110, %00000000
        db %00011110, %00000111, %10000000
        db %00000000, %00000000, %00000000
 
 
end ENTRY_POINT

Tento program po svém spuštění vykreslí na obrazovku ZX Spectra dvojici spritů (postaviček). Výsledná scéna bude vypadat následovně:

Obrázek 1: Dvojice spritů vykreslená dnešním prvním demonstračním příkladem na obrazovku ZX Spectra.

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

2. Urychlení vykreslování – optimalizace subrutiny draw8_lines

Podprogram určený pro vykreslení spritu o rozměrech 24×24 pixelů třikrát volá subrutinu nazvanou draw8_lines, která vykreslí „pouze“ osm obrazových řádků spritu, přičemž na každém řádku se zobrazí 24 pixelů. Tato subrutina interně obsahuje programovou smyčku opakovanou pro každý obrazový řádek. Původní varianta této subrutiny s programovou smyčkou vypadá následovně:

draw_8_lines:
        ld b, 8                  ; počitadlo zapsaných řádků
 
loop:
        ld  a,(hl)               ; načtení jednoho bajtu z masky
        ld  (de),a               ; zápis hodnoty na adresu (DE)
        inc hl                   ; posun na další bajt masky
        inc e
 
        ld  a,(hl)               ; načtení jednoho bajtu z masky
        ld  (de),a               ; zápis hodnoty na adresu (DE)
        inc hl                   ; posun na další bajt masky
        inc e
 
        ld  a,(hl)               ; načtení jednoho bajtu z masky
        ld  (de),a               ; zápis hodnoty na adresu (DE)
        inc hl                   ; posun na další bajt masky
 
        inc d                    ; posun na definici dalšího obrazového řádku
        dec e                    ; korekce - posun zpět pod první osmici pixelů
        dec e                    ; dtto
        djnz loop                ; vnitřní smyčka: blok s 3x osmi zápisy
        ret                      ; návrat z podprogramu

V této subrutině se dvojice registrů HL používá pro načtení bajtu z masky spritu a dvojice registrů DE pro zápis (přenos dat je pochopitelně prováděn přes akumulátor). Tuto subrutinu lze ovšem optimalizovat náhradou sekvence instrukcí ld (load) za „blokové“ přenosy (nyní ovšem s počitadlem obsahujícím jak počitadlo smyčky, tak i nižší nepoužitý bajt):

draw_8_lines:
        ld  bc, 8*(256+2)        ; počitadlo zapsaných řádků
loop:
        ldi                      ; přesun jednoho bajtu + úprava stavu počitadla [DE++] = [HL++]; BC--
        ldi                      ; přesun jednoho bajtu + úprava stavu počitadla [DE++] = [HL++]; BC--
        ld  a,(hl)               ; načtení jednoho bajtu z masky
        ld  (de),a               ; zápis hodnoty na adresu (DE)
        inc hl                   ; posun na další bajt masky
        dec e                    ; korekce - posun zpět pod první osmici pixelů
        dec e                    ; korekce
        inc d                    ; posun na definici dalšího obrazového řádku (+256)
        djnz loop                ; vnitřní smyčka: blok s 3x osmi zápisy
        ret                      ; návrat z podprogramu

Výsledek je jak kratší, tak i rychlejší (opět díky _dw!).

Původní strojový kód:

803E:           label draw_8_lines
803E:0608       LD B, 08
8040:           label loop
8040:7E         LD A, (HL)
8041:12         LD (DE), A
8042:23         INC HL
8043:1C         INC E
8044:7E         LD A, (HL)
8045:12         LD (DE), A
8046:23         INC HL
8047:1C         INC E
8048:7E         LD A, (HL)
8049:12         LD (DE), A
804A:23         INC HL
804B:14         INC D
804C:1D         DEC E
804D:1D         DEC E
804E:10F0       DJNZ 8040
8050:C9         RET

Strojový kód po optimalizaci zdrojového kódu:

8040:           label draw_8_lines
8040:011008     LD BC, 0810
8043:           label loop
8043:EDA0       LDI
8045:EDA0       LDI
8047:7E         LD A, (HL)
8048:12         LD (DE), A
8049:23         INC HL
804A:1D         DEC E
804B:1D         DEC E
804C:14         INC D
804D:10F4       DJNZ 8043
804F:C9         RET

3. Úplný zdrojový kód dnešního druhého demonstračního příkladu

Po výše uvedené úpravě získáme program, po jehož spuštění se zobrazí stejná scéna, jako v případě programu předchozího:

Obrázek 2: Dvojice spritů vykreslená dnešním druhým demonstračním příkladem na obrazovku ZX Spectra. Samotná scéna by měla být totožná s prvním obrázkem (až na rozdílný řádek s hlavičkou načítaných dat).

Pro úplnost se podívejme, jak vypadá úplný zdrojový kód takto upraveného příkladu:

SCREEN_ADR      equ $4000
ENTRY_POINT     equ $8000
 
        org ENTRY_POINT
 
start:
        ld b, 15                 ; x-ová souřadnice
        ld c, 3                  ; y-ová souřadnice
        call calc_sprite_address ; výpočet adresy spritu
        call draw_sprite
 
        ld b, 29                 ; x-ová souřadnice
        ld c, 21                 ; y-ová souřadnice
        call calc_sprite_address ; výpočet adresy
        call draw_sprite
 
finish:
        jr finish                ; žádný návrat do systému
 
 
calc_sprite_address:
        ; parametry:
        ; B - x-ová souřadnice (ve znacích, ne pixelech)
        ; C - y-ová souřadnice (ve znacích, ne pixelech)
        ;
        ; návratové hodnoty:
        ; DE - adresa pro zápis bloku
        ;
        ; vzor adresy:
        ; 0 1 0 Y4 Y3 0 0 0 | Y2 Y1 Y0 X4 X3 X2 X1 X0
        ld  a, c
        and %00000111            ; pouze spodní tři bity y-ové souřadnice (řádky 0..7)
        rrca
        rrca
        rrca                     ; nyní jsou čísla řádků v horních třech bitech
        or  b                    ; připočítat x-ovou souřadnici
        ld  e, a                 ; máme spodní bajt adresy
                                 ; Y2 Y1 Y0 X4 X3 X2 X1 X0
 
        ld  a, c                 ; y-ová souřadnice
        and %00011000            ; dva bity s indexem "bloku" 0..3 (dolní tři bity už máme zpracovány)
        or  %01000000            ; "posun" do obrazové paměti (na 0x4000)
        ld  d, a                 ; máme horní bajt adresy
                                 ; 0 1 0 Y5 Y4 0 0 0
        ret                      ; návrat z podprogramu
 
 
add_e MACRO n                    ; zvýšení hodnoty regitru E
        ld   a, e
        add  a, n
        ld   e, a
endm
 
draw_sprite:
        ld hl, SPRITE_ADR        ; adresa, od níž začíná maska spritu
        push de
        call draw_8_lines        ; vykreslit prvních 8 řádků spritu
 
        pop  de
        add_e 32                 ; zvýšit E o hodnotu 32
        push de
        call draw_8_lines        ; vykreslit druhých 8 řádků spritu
 
        pop  de
        add_e 32                 ; zvýšit E o hodnotu 32
        call draw_8_lines        ; vykreslit třetích 8 řádků spritu
 
        ret                      ; návrat z podprogramu
 
 
        ld b, 8                  ; počitadlo zapsaných řádků
 
 
draw_8_lines:
        ld  bc, 8*(256+2)        ; počitadlo zapsaných řádků
loop:
        ldi                      ; přesun jednoho bajtu + úprava stavu počitadla [DE++] = [HL++]; BC--
        ldi                      ; přesun jednoho bajtu + úprava stavu počitadla [DE++] = [HL++]; BC--
        ld  a,(hl)               ; načtení jednoho bajtu z masky
        ld  (de),a               ; zápis hodnoty na adresu (DE)
        inc hl                   ; posun na další bajt masky
        dec e                    ; korekce - posun zpět pod první osmici pixelů
        dec e                    ; korekce
        inc d                    ; posun na definici dalšího obrazového řádku (+256)
        djnz loop                ; vnitřní smyčka: blok s 3x osmi zápisy
        ret                      ; návrat z podprogramu
 
 
SPRITE_ADR
        db %00000000, %00000000, %00000000
        db %00000000, %00000000, %00000000
        db %00000001, %11110000, %00010000
        db %00000011, %00111000, %00010000
        db %00000101, %11010111, %00010000
        db %00000101, %11001100, %00010000
        db %00000101, %00110000, %00010000
        db %00000100, %11001000, %00010000
        db %00000111, %00110110, %00010000
        db %00001100, %11111110, %00111000
        db %00011111, %11111000, %00000000
        db %00000000, %00000000, %00110000
        db %00000011, %11111111, %10110000
        db %00000101, %11111110, %11100000
        db %00001110, %11111101, %11000000
        db %00011000, %11111100, %00000000
        db %00011000, %00000000, %00000000
        db %00000001, %11111000, %00000000
        db %00000011, %11111100, %00000000
        db %00000001, %10110000, %00000000
        db %00000010, %00001100, %00000000
        db %00000111, %00001110, %00000000
        db %00011110, %00000111, %10000000
        db %00000000, %00000000, %00000000
 
 
end ENTRY_POINT
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu naleznete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/126–24×24-faster-sprite.asm.

4. Nedostatky podprogramu pro vykreslení spritu na obrazovku ZX Spectra

Podprogram nazvaný draw_sprite, který jsme si ukázali, sice pracuje zdánlivě korektně (ostatně nám umožnil na obrazovku vykreslit několik postaviček), ale v navazujících kapitolách si ukážeme, že ve skutečnosti má poměrně velké množství problémů, které bude nutné vyřešit. Některé z těchto problémů souvisí s tím, že jsme si práci až příliš zjednodušili, další problémy pak vychází ze specifické struktury obrazové paměti ZX Spectra. Každý z dále zmíněných problémů bude demonstrován v samostatném příkladu:

  1. Chybějící kontrola, zda sprite nepřesahuje pravý či levý okraj obrazovky
  2. Chybějící kontrola, zda sprite nepřesahuje dolní okraj obrazovky
  3. Chybně vykreslený sprite, jehož maska přesahuje přes třetinu obrazovky
  4. Chyby při zobrazení spritu na nekonstantním pozadí

5. Chybějící kontrola, zda sprite nepřesahuje pravý či levý okraj obrazovky

Vykreslovací subrutina prozatím vůbec neprovádí kontrolu, zda sprite nepřesahuje pravý či levý okraj obrazovky (přesněji řečeno pravý okraj obrazovky, protože oba případy mají, pokud se nad tím zamyslíme, naprosto stejné vstupy). Můžeme si to ostatně velmi snadno otestovat tak, že vykreslíme několik spritů blízko pravého okraje obrazovky (povšimněte si x-ových souřadnic předávaných v pracovním registru B):

ld b, 29                 ; x-ová souřadnice
ld c, 2                  ; y-ová souřadnice
call calc_sprite_address ; výpočet adresy spritu
call draw_sprite
 
ld b, 30                 ; x-ová souřadnice
ld c, 5                  ; y-ová souřadnice
call calc_sprite_address ; výpočet adresy
call draw_sprite
 
ld b, 31                 ; x-ová souřadnice
ld c, 9                  ; y-ová souřadnice
call calc_sprite_address ; výpočet adresy
call draw_sprite

Výsledek bude vypadat následovně:

Obrázek 3: Trojice spritů, z nichž dva přesahují přes pravý okraj obrazovky.

Jak je možné tento problém vyřešit? Například tak, že se logikou hry zajistí, že žádná z postaviček nepřesáhne okraj obrazovky (nebo se ho jen dotkne), což je případ velkého množství skutečných her, které pro ZX Spectrum vznikly. Nebo postavička může okrajem „projít“ podobně, jako v našem případě. Korektní ořezání spritu tak, aby mohl být zobrazen jen částečně, je pochopitelně možné, ale dosti pomalé. Podívejme se na příklady:

Obrázek 4: Postavička ve hře JetPac prochází okrajem a zobrazuje se na druhém okraji obrazovky. Podobně přes okraj prochází i NPC, výbuchy atd.

Obrázek 5: Ve hře Starquake se postavička okraje pouze může dotknout. Při dalším pohybu se ihned přejde do další místnosti.

Obrázek 6: Ve hře Draconus je sprite korektně ořezáván, ovšem jen na chvíli, než se přepne místnost. Povšimněte si, že ořezání není provedeno na samotném okraji obrazovky, čímž se problematika zjednodušuje.

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 vypadá následovně:

SCREEN_ADR      equ $4000
ENTRY_POINT     equ $8000
 
        org ENTRY_POINT
 
start:
        ld b, 29                 ; x-ová souřadnice
        ld c, 2                  ; y-ová souřadnice
        call calc_sprite_address ; výpočet adresy spritu
        call draw_sprite
 
        ld b, 30                 ; x-ová souřadnice
        ld c, 5                  ; y-ová souřadnice
        call calc_sprite_address ; výpočet adresy
        call draw_sprite
 
        ld b, 31                 ; x-ová souřadnice
        ld c, 9                  ; y-ová souřadnice
        call calc_sprite_address ; výpočet adresy
        call draw_sprite
 
finish:
        jr finish                ; žádný návrat do systému
 
 
calc_sprite_address:
        ; parametry:
        ; B - x-ová souřadnice (ve znacích, ne pixelech)
        ; C - y-ová souřadnice (ve znacích, ne pixelech)
        ;
        ; návratové hodnoty:
        ; DE - adresa pro zápis bloku
        ;
        ; vzor adresy:
        ; 0 1 0 Y4 Y3 0 0 0 | Y2 Y1 Y0 X4 X3 X2 X1 X0
        ld  a, c
        and %00000111            ; pouze spodní tři bity y-ové souřadnice (řádky 0..7)
        rrca
        rrca
        rrca                     ; nyní jsou čísla řádků v horních třech bitech
        or  b                    ; připočítat x-ovou souřadnici
        ld  e, a                 ; máme spodní bajt adresy
                                 ; Y2 Y1 Y0 X4 X3 X2 X1 X0
 
        ld  a, c                 ; y-ová souřadnice
        and %00011000            ; dva bity s indexem "bloku" 0..3 (dolní tři bity už máme zpracovány)
        or  %01000000            ; "posun" do obrazové paměti (na 0x4000)
        ld  d, a                 ; máme horní bajt adresy
                                 ; 0 1 0 Y5 Y4 0 0 0
        ret                      ; návrat z podprogramu
 
 
add_e MACRO n                    ; zvýšení hodnoty regitru E
        ld   a, e
        add  a, n
        ld   e, a
endm
 
draw_sprite:
        ld hl, SPRITE_ADR        ; adresa, od níž začíná maska spritu
        push de
        call draw_8_lines        ; vykreslit prvních 8 řádků spritu
 
        pop  de
        add_e 32                 ; zvýšit E o hodnotu 32
        push de
        call draw_8_lines        ; vykreslit druhých 8 řádků spritu
 
        pop  de
        add_e 32                 ; zvýšit E o hodnotu 32
        call draw_8_lines        ; vykreslit třetích 8 řádků spritu
 
        ret                      ; návrat z podprogramu
 
 
        ld b, 8                  ; počitadlo zapsaných řádků
 
 
draw_8_lines:
        ld  bc, 8*(256+2)        ; počitadlo zapsaných řádků
loop:
        ldi                      ; přesun jednoho bajtu + úprava stavu počitadla [DE++] = [HL++]; BC--
        ldi                      ; přesun jednoho bajtu + úprava stavu počitadla [DE++] = [HL++]; BC--
        ld  a,(hl)               ; načtení jednoho bajtu z masky
        ld  (de),a               ; zápis hodnoty na adresu (DE)
        inc hl                   ; posun na další bajt masky
        dec e                    ; korekce - posun zpět pod první osmici pixelů
        dec e                    ; korekce
        inc d                    ; posun na definici dalšího obrazového řádku (+256)
        djnz loop                ; vnitřní smyčka: blok s 3x osmi zápisy
        ret                      ; návrat z podprogramu
 
 
 
SPRITE_ADR
        db %00000000, %00000000, %00000000
        db %00000000, %00000000, %00000000
        db %00000001, %11110000, %00010000
        db %00000011, %00111000, %00010000
        db %00000101, %11010111, %00010000
        db %00000101, %11001100, %00010000
        db %00000101, %00110000, %00010000
        db %00000100, %11001000, %00010000
        db %00000111, %00110110, %00010000
        db %00001100, %11111110, %00111000
        db %00011111, %11111000, %00000000
        db %00000000, %00000000, %00110000
        db %00000011, %11111111, %10110000
        db %00000101, %11111110, %11100000
        db %00001110, %11111101, %11000000
        db %00011000, %11111100, %00000000
        db %00011000, %00000000, %00000000
        db %00000001, %11111000, %00000000
        db %00000011, %11111100, %00000000
        db %00000001, %10110000, %00000000
        db %00000010, %00001100, %00000000
        db %00000111, %00001110, %00000000
        db %00011110, %00000111, %10000000
        db %00000000, %00000000, %00000000
 
 
end ENTRY_POINT
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu naleznete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/127-margins.asm.

7. Chybějící kontrola, zda sprite nepřesahuje dolní okraj obrazovky

V případě, že sprite přesáhne přes pravý okraj obrazovky, nemusí být tento problém (a většinou se jedná o problém) příliš viditelný. Obraz sice může být na levém okraji poškozen, ale jedná se o lokální problém, který navíc může u některých her (střílečky) zaniknout v celkovém „chaosu“ na obrazovce. Ovšem zajímavější problém nastane ve chvíli, kdy sprite přesáhne spodní okraj obrazovky. Proč tomu tak je? Připomeňme si, jaká je vlastně organizace obrazové paměti ZX Spectra:

Od Do Délka Stručný popis
4000 47ff 2048 prvních 64 obrazových řádků
4800 5000 2048 obrazové řádky 64–127
5000 57ff 2048 obrazové řádky 128–191
5800 5aff 768 32×24=768 atributů

Z této tabulky je patrné, že ihned za posledním obrazovým řádkem s indexem 191 (čísluje se od nuly) se nachází začátek atributové paměti. U spritu s výškou 24 obrazových řádků se nám může velmi dobře stát, že přepíšeme část této paměti či že dokonce zasáhneme až do adresního prostoru za touto pamětí. Pojďme si to vyzkoušet:

ld b, 14                 ; x-ová souřadnice
ld c, 2                  ; y-ová souřadnice
call calc_sprite_address ; výpočet adresy spritu
call draw_sprite
 
ld b, 14                 ; x-ová souřadnice
ld c, 5                  ; y-ová souřadnice
call calc_sprite_address ; výpočet adresy
call draw_sprite
 
ld b, 31                 ; x-ová souřadnice
ld c, 23                 ; y-ová souřadnice
call calc_sprite_address ; výpočet adresy
call draw_sprite

Poslední sprite leží až na dolním okraji obrazovky, takže při zápisu jeho masky přepíšeme i část atributové paměti:

Obrázek 7: Trojice spritů, z nichž poslední přesahuje před spodní okraj obrazovky a při jehož vykreslování se zasáhlo do oblasti atributové paměti (bílý atribut dokonce bliká, což na statickém screenshotu není patrné).

Poznámka: řešení tohoto problému leží buď v omezení vertikální pozice spritu nebo v „ořezání“ vykreslování přímo v podprogramu pro vykreslování spritu – což je složité, resp. pomalé.

Obrázek 8: Elegantní řešení výše uvedeného problému v legendární hře – šílený horník se nedostane přes spodní okraj obrazovky, protože se do této oblasti nemůže díky designu celé scény ani přiblížit.

8. Úplný zdrojový kód dnešního třetího demonstračního příkladu

Opět si ukažme úplný zdrojový kód příkladu, jenž po svém překladu a následném spuštění zobrazí tři sprity, z nichž jeden překračuje dolní okraj obrazovky a tím pádem zasahuje do oblasti atributové paměti:

SCREEN_ADR      equ $4000
ENTRY_POINT     equ $8000
 
        org ENTRY_POINT
 
start:
        ld b, 14                 ; x-ová souřadnice
        ld c, 2                  ; y-ová souřadnice
        call calc_sprite_address ; výpočet adresy spritu
        call draw_sprite
 
        ld b, 14                 ; x-ová souřadnice
        ld c, 5                  ; y-ová souřadnice
        call calc_sprite_address ; výpočet adresy
        call draw_sprite
 
        ld b, 31                 ; x-ová souřadnice
        ld c, 23                 ; y-ová souřadnice
        call calc_sprite_address ; výpočet adresy
        call draw_sprite
 
finish:
        jr finish                ; žádný návrat do systému
 
 
calc_sprite_address:
        ; parametry:
        ; B - x-ová souřadnice (ve znacích, ne pixelech)
        ; C - y-ová souřadnice (ve znacích, ne pixelech)
        ;
        ; návratové hodnoty:
        ; DE - adresa pro zápis bloku
        ;
        ; vzor adresy:
        ; 0 1 0 Y4 Y3 0 0 0 | Y2 Y1 Y0 X4 X3 X2 X1 X0
        ld  a, c
        and %00000111            ; pouze spodní tři bity y-ové souřadnice (řádky 0..7)
        rrca
        rrca
        rrca                     ; nyní jsou čísla řádků v horních třech bitech
        or  b                    ; připočítat x-ovou souřadnici
        ld  e, a                 ; máme spodní bajt adresy
                                 ; Y2 Y1 Y0 X4 X3 X2 X1 X0
 
        ld  a, c                 ; y-ová souřadnice
        and %00011000            ; dva bity s indexem "bloku" 0..3 (dolní tři bity už máme zpracovány)
        or  %01000000            ; "posun" do obrazové paměti (na 0x4000)
        ld  d, a                 ; máme horní bajt adresy
                                 ; 0 1 0 Y5 Y4 0 0 0
        ret                      ; návrat z podprogramu
 
 
add_e MACRO n                    ; zvýšení hodnoty regitru E
        ld   a, e
        add  a, n
        ld   e, a
endm
 
draw_sprite:
        ld hl, SPRITE_ADR        ; adresa, od níž začíná maska spritu
        push de
        call draw_8_lines        ; vykreslit prvních 8 řádků spritu
 
        pop  de
        add_e 32                 ; zvýšit E o hodnotu 32
        push de
        call draw_8_lines        ; vykreslit druhých 8 řádků spritu
 
        pop  de
        add_e 32                 ; zvýšit E o hodnotu 32
        call draw_8_lines        ; vykreslit třetích 8 řádků spritu
 
        ret                      ; návrat z podprogramu
 
 
        ld b, 8                  ; počitadlo zapsaných řádků
 
 
draw_8_lines:
        ld  bc, 8*(256+2)        ; počitadlo zapsaných řádků
loop:
        ldi                      ; přesun jednoho bajtu + úprava stavu počitadla [DE++] = [HL++]; BC--
        ldi                      ; přesun jednoho bajtu + úprava stavu počitadla [DE++] = [HL++]; BC--
        ld  a,(hl)               ; načtení jednoho bajtu z masky
        ld  (de),a               ; zápis hodnoty na adresu (DE)
        inc hl                   ; posun na další bajt masky
        dec e                    ; korekce - posun zpět pod první osmici pixelů
        dec e                    ; korekce
        inc d                    ; posun na definici dalšího obrazového řádku (+256)
        djnz loop                ; vnitřní smyčka: blok s 3x osmi zápisy
        ret                      ; návrat z podprogramu
 
 
 
SPRITE_ADR
        db %00000000, %00000000, %00000000
        db %00000000, %00000000, %00000000
        db %00000001, %11110000, %00010000
        db %00000011, %00111000, %00010000
        db %00000101, %11010111, %00010000
        db %00000101, %11001100, %00010000
        db %00000101, %00110000, %00010000
        db %00000100, %11001000, %00010000
        db %00000111, %00110110, %00010000
        db %00001100, %11111110, %00111000
        db %00011111, %11111000, %00000000
        db %00000000, %00000000, %00110000
        db %00000011, %11111111, %10110000
        db %00000101, %11111110, %11100000
        db %00001110, %11111101, %11000000
        db %00011000, %11111100, %00000000
        db %00011000, %00000000, %00000000
        db %00000001, %11111000, %00000000
        db %00000011, %11111100, %00000000
        db %00000001, %10110000, %00000000
        db %00000010, %00001100, %00000000
        db %00000111, %00001110, %00000000
        db %00011110, %00000111, %10000000
        db %00000000, %00000000, %00000000
 
 
end ENTRY_POINT

9. Sprite, jehož maska přesahuje přes třetinu obrazovky

Z předchozích článků již víme, že obrazová paměť je rozdělena do čtyř oblastí:

Od Do Délka Stručný popis
4000 47ff 2048 prvních 64 obrazových řádků
4800 5000 2048 obrazové řádky 64–127
5000 57ff 2048 obrazové řádky 128–191
5800 5aff 768 32×24=768 atributů

V každé oblasti jsou navíc řádky uspořádány tak, že za řádkem číslo 1 následuje řádek číslo 8, potom řádek číslo 16 atd. (nejlépe je to patrné při načítání obrázků z kazety). Tento problém jsme už poměrně uspokojivě vyřešili ve vykreslovací rutině, a to i pro sprity vyšší než osm obrazových řádků. Ovšem prozatím jsme „zapomněli“ na to, že pokud sprite přesáhne přes okraj třetiny obrazovky (64 řádek nebo 128 řádek), nebudou výpočty adresy pracovat korektně a zbytek spritu se vykreslí v aktuální třetině obrazovky, a to na jejím horním okraji. Můžeme si to poměrně snadno otestovat na spritech s následujícími souřadnicemi (stále pro jednoduchost počítáme souřadnice v násobcích osmi – to také budeme muset změnit):

ld b, 15                 ; x-ová souřadnice
ld c, 3                  ; y-ová souřadnice
call calc_sprite_address ; výpočet adresy spritu
call draw_sprite
 
ld b, 15                 ; x-ová souřadnice
ld c, 6                  ; y-ová souřadnice
call calc_sprite_address ; výpočet adresy
call draw_sprite
Poznámka: vertikální pozice druhého spritu je obrazový řádek číslo 6×8=48 a výška spritu je 24 obrazových řádků, což je více, než 64 řádků v první třetině obrazovky (48+24=72 obrazových řádků).

Výsledkem bude následující scéna. Povšimněte si, že spodní sprite, který přesáhl přes třetinu obrazovky, je vykreslen chybně – jeho spodní část ve skutečnosti „přetekla“ na prvních osm řádků na obrazovce.

Obrázek 9: Pokus o vykreslení spritu, který přesahuje přes třetinu obrazovky (jedná se o v pořadí druhý sprite, jehož „nohy“ přeskočily až nahoru).

10. Úplný zdrojový kód dnešního čtvrtého demonstračního příkladu

Opět si ukažme úplný zdrojový kód demonstračního příkladu, jenž byl popsán v předchozí kapitole. Tento kód vypadá následovně:

SCREEN_ADR      equ $4000
ENTRY_POINT     equ $8000
 
        org ENTRY_POINT
 
start:
        ld b, 15                 ; x-ová souřadnice
        ld c, 3                  ; y-ová souřadnice
        call calc_sprite_address ; výpočet adresy spritu
        call draw_sprite
 
        ld b, 15                 ; x-ová souřadnice
        ld c, 6                  ; y-ová souřadnice
        call calc_sprite_address ; výpočet adresy
        call draw_sprite
 
finish:
        jr finish                ; žádný návrat do systému
 
 
calc_sprite_address:
        ; parametry:
        ; B - x-ová souřadnice (ve znacích, ne pixelech)
        ; C - y-ová souřadnice (ve znacích, ne pixelech)
        ;
        ; návratové hodnoty:
        ; DE - adresa pro zápis bloku
        ;
        ; vzor adresy:
        ; 0 1 0 Y4 Y3 0 0 0 | Y2 Y1 Y0 X4 X3 X2 X1 X0
        ld  a, c
        and %00000111            ; pouze spodní tři bity y-ové souřadnice (řádky 0..7)
        rrca
        rrca
        rrca                     ; nyní jsou čísla řádků v horních třech bitech
        or  b                    ; připočítat x-ovou souřadnici
        ld  e, a                 ; máme spodní bajt adresy
                                 ; Y2 Y1 Y0 X4 X3 X2 X1 X0
 
        ld  a, c                 ; y-ová souřadnice
        and %00011000            ; dva bity s indexem "bloku" 0..3 (dolní tři bity už máme zpracovány)
        or  %01000000            ; "posun" do obrazové paměti (na 0x4000)
        ld  d, a                 ; máme horní bajt adresy
                                 ; 0 1 0 Y5 Y4 0 0 0
        ret                      ; návrat z podprogramu
 
 
add_e MACRO n                    ; zvýšení hodnoty regitru E
        ld   a, e
        add  a, n
        ld   e, a
endm
 
draw_sprite:
        ld hl, SPRITE_ADR        ; adresa, od níž začíná maska spritu
        push de
        call draw_8_lines        ; vykreslit prvních 8 řádků spritu
 
        pop  de
        add_e 32                 ; zvýšit E o hodnotu 32
        push de
        call draw_8_lines        ; vykreslit druhých 8 řádků spritu
 
        pop  de
        add_e 32                 ; zvýšit E o hodnotu 32
        call draw_8_lines        ; vykreslit třetích 8 řádků spritu
 
        ret                      ; návrat z podprogramu
 
 
        ld b, 8                  ; počitadlo zapsaných řádků
 
 
draw_8_lines:
        ld  bc, 8*(256+2)        ; počitadlo zapsaných řádků
loop:
        ldi                      ; přesun jednoho bajtu + úprava stavu počitadla [DE++] = [HL++]; BC--
        ldi                      ; přesun jednoho bajtu + úprava stavu počitadla [DE++] = [HL++]; BC--
        ld  a,(hl)               ; načtení jednoho bajtu z masky
        ld  (de),a               ; zápis hodnoty na adresu (DE)
        inc hl                   ; posun na další bajt masky
        dec e                    ; korekce - posun zpět pod první osmici pixelů
        dec e                    ; korekce
        inc d                    ; posun na definici dalšího obrazového řádku (+256)
        djnz loop                ; vnitřní smyčka: blok s 3x osmi zápisy
        ret                      ; návrat z podprogramu
 
 
 
SPRITE_ADR
        db %00000000, %00000000, %00000000
        db %00000000, %00000000, %00000000
        db %00000001, %11110000, %00010000
        db %00000011, %00111000, %00010000
        db %00000101, %11010111, %00010000
        db %00000101, %11001100, %00010000
        db %00000101, %00110000, %00010000
        db %00000100, %11001000, %00010000
        db %00000111, %00110110, %00010000
        db %00001100, %11111110, %00111000
        db %00011111, %11111000, %00000000
        db %00000000, %00000000, %00110000
        db %00000011, %11111111, %10110000
        db %00000101, %11111110, %11100000
        db %00001110, %11111101, %11000000
        db %00011000, %11111100, %00000000
        db %00011000, %00000000, %00000000
        db %00000001, %11111000, %00000000
        db %00000011, %11111100, %00000000
        db %00000001, %10110000, %00000000
        db %00000010, %00001100, %00000000
        db %00000111, %00001110, %00000000
        db %00011110, %00000111, %10000000
        db %00000000, %00000000, %00000000
 
 
end ENTRY_POINT

11. Vykreslení spritu na různorodé pozadí

Všechny demonstrační příklady určené pro vykreslení spritů prozatím pracovaly s prázdnou obrazovkou (to ve skutečnosti není zcela přesné, protože na prvním textovém řádku zůstávají zprávy z načítací rutiny). Co se však stane ve chvíli, kdy se pokusíme sprite vykreslit oproti nějakému různorodému pozadí? Uvidíme hned celou řadu problémů, zejména však:

  1. Sprite „zdědí“ původní barvové atributy, a to jak atributy pozadí (což je v pořádku), tak i popředí (+ příznak blikání atd.)
  2. Sprite překreslí pozadí i na těch pozicích, v nichž by měly být jeho pixely průhledné (což odpovídá nulovým bitům v masce pixelu).

Obrázek 10: Manic miner nejenom že prochází stropem, ale navíc jeho sprite přebírá atributy herního pozadí (což ovšem není grafické pozadí, ale naopak popředí) i NPC (robota).

12. Vykreslení statického obrázku na obrazovku ZX Spectra

Ještě předtím, než se pokusíme o vykreslení spritu oproti již připravenému statickému pozadí, si ukažme, jak lze na obrazovku ZX Spectra vykreslit nějaký statický obrázek, který se nachází v jiné oblasti operační paměti. V praxi se můžeme setkat s přímým načtením obrázku (loading screen) do obrazové paměti, nyní ovšem budeme postupovat jinak – data obrázku, tedy jak bitmapu, tak i atributy, triviálně zkopírujeme do obrazové paměti instrukcí pro blokový přenos LDIR, s níž jsme se již v tomto seriálu setkali:

SCREEN_ADR             equ $4000
BITMAP_SIZE            equ 32*192
ATTRIBUTE_BLOCK_SIZE   equ 32*64
SCREEN_SIZE            equ BITMAP_SIZE + ATTRIBUTE_BLOCK_SIZE
ENTRY_POINT            equ $8000
 
        org ENTRY_POINT
 
start:
        ; nejprve přeneseme celý obrázek do obrazové paměti
        ld   hl, LOADING_SCREN   ; adresa zdrojového bloku
        ld   de, SCREEN_ADR      ; adresa cílového bloku
        ld   bc, SCREEN_SIZE     ; velikost přenášených dat
        ldir                     ; provést blokový přenos
 
finish:
        jr finish                ; žádný návrat do systému
 
 
LOADING_SCREN incbin "Alien8.scr"
 
 
 
end ENTRY_POINT
Poznámka: povšimněte si, že data obrázku jsou při překladu uložena v souboru „Alien8.scr“, který obsahuje bitmapu 256×192 bitů a taktéž 32×24 barvových atributů, tedy celkem přesně 256×192/8+32×24=6144+768=6912 bajtů.

Výsledná scéna by po načtení do ZX Spectra či jeho emulátoru měla vypadat následovně:

Obrázek 11: Statický obrázek vykreslený na obrazovku ZX Spectra.

13. Zobrazení spritů ve scéně s obrázkem na pozadí

Nyní zkombinujeme zobrazení pozadí (statického obrázku) se zobrazením spritů. Oproti předchozím demonstračním příkladům ve skutečnosti pouze upravíme začátek kódu, v němž nejprve na obrazovku zkopírujeme statický obrázek a potom přes něj nakreslíme trojici spritů (na vhodná místa):

; nejprve přeneseme celý obrázek do obrazové paměti
ld   hl, LOADING_SCREN   ; adresa zdrojového bloku
ld   de, SCREEN_ADR      ; adresa cílového bloku
ld   bc, SCREEN_SIZE     ; velikost přenášených dat
ldir                     ; provést blokový přenos
 
ld b, 15                 ; x-ová souřadnice
ld c, 4                  ; y-ová souřadnice
call calc_sprite_address ; výpočet adresy spritu
call draw_sprite
 
ld b, 15                 ; x-ová souřadnice
ld c, 18                 ; y-ová souřadnice
call calc_sprite_address ; výpočet adresy spritu
call draw_sprite
 
ld b, 9                  ; x-ová souřadnice
ld c, 12                 ; y-ová souřadnice
call calc_sprite_address ; výpočet adresy
call draw_sprite

Na výsledku jsou velmi dobře patrné oba problémy zmíněné v předchozí kapitole, tj. jak překreslení i těch pixelů, které měly zůstat zachovány, tak i „zdědění“ původních barvových atributů (nejvíce je to patrné na nejvyšším spritu, který zdědil hned tři různé barvy popředí):

Obrázek 12: Zobrazení trojice spritů ve scéně s obrázkem na pozadí.

14. Úplný zdrojový kód dnešního šestého demonstračního příkladu

Úplný zdrojový kód dnešního šestého demonstračního příkladu vypadá následovně:

SCREEN_ADR             equ $4000
BITMAP_SIZE            equ 32*192
ATTRIBUTE_BLOCK_SIZE   equ 32*64
SCREEN_SIZE            equ BITMAP_SIZE + ATTRIBUTE_BLOCK_SIZE
ENTRY_POINT            equ $8000
 
        org ENTRY_POINT
 
start:
        ; nejprve přeneseme celý obrázek do obrazové paměti
        ld   hl, LOADING_SCREN   ; adresa zdrojového bloku
        ld   de, SCREEN_ADR      ; adresa cílového bloku
        ld   bc, SCREEN_SIZE     ; velikost přenášených dat
        ldir                     ; provést blokový přenos
 
        ld b, 15                 ; x-ová souřadnice
        ld c, 4                  ; y-ová souřadnice
        call calc_sprite_address ; výpočet adresy spritu
        call draw_sprite
 
        ld b, 15                 ; x-ová souřadnice
        ld c, 18                 ; y-ová souřadnice
        call calc_sprite_address ; výpočet adresy spritu
        call draw_sprite
 
        ld b, 9                  ; x-ová souřadnice
        ld c, 12                 ; y-ová souřadnice
        call calc_sprite_address ; výpočet adresy
        call draw_sprite
 
finish:
        jr finish                ; žádný návrat do systému
 
 
calc_sprite_address:
        ; parametry:
        ; B - x-ová souřadnice (ve znacích, ne pixelech)
        ; C - y-ová souřadnice (ve znacích, ne pixelech)
        ;
        ; návratové hodnoty:
        ; DE - adresa pro zápis bloku
        ;
        ; vzor adresy:
        ; 0 1 0 Y4 Y3 0 0 0 | Y2 Y1 Y0 X4 X3 X2 X1 X0
        ld  a, c
        and %00000111            ; pouze spodní tři bity y-ové souřadnice (řádky 0..7)
        rrca
        rrca
        rrca                     ; nyní jsou čísla řádků v horních třech bitech
        or  b                    ; připočítat x-ovou souřadnici
        ld  e, a                 ; máme spodní bajt adresy
                                 ; Y2 Y1 Y0 X4 X3 X2 X1 X0
 
        ld  a, c                 ; y-ová souřadnice
        and %00011000            ; dva bity s indexem "bloku" 0..3 (dolní tři bity už máme zpracovány)
        or  %01000000            ; "posun" do obrazové paměti (na 0x4000)
        ld  d, a                 ; máme horní bajt adresy
                                 ; 0 1 0 Y5 Y4 0 0 0
        ret                      ; návrat z podprogramu
 
 
add_e MACRO n                    ; zvýšení hodnoty regitru E
        ld   a, e
        add  a, n
        ld   e, a
endm
 
draw_sprite:
        ld hl, SPRITE_ADR        ; adresa, od níž začíná maska spritu
        push de
        call draw_8_lines        ; vykreslit prvních 8 řádků spritu
 
        pop  de
        add_e 32                 ; zvýšit E o hodnotu 32
        push de
        call draw_8_lines        ; vykreslit druhých 8 řádků spritu
 
        pop  de
        add_e 32                 ; zvýšit E o hodnotu 32
        call draw_8_lines        ; vykreslit třetích 8 řádků spritu
 
        ret                      ; návrat z podprogramu
 
 
        ld b, 8                  ; počitadlo zapsaných řádků
 
 
draw_8_lines:
        ld  bc, 8*(256+2)        ; počitadlo zapsaných řádků
loop:
        ldi                      ; přesun jednoho bajtu + úprava stavu počitadla [DE++] = [HL++]; BC--
        ldi                      ; přesun jednoho bajtu + úprava stavu počitadla [DE++] = [HL++]; BC--
        ld  a,(hl)               ; načtení jednoho bajtu z masky
        ld  (de),a               ; zápis hodnoty na adresu (DE)
        inc hl                   ; posun na další bajt masky
        dec e                    ; korekce - posun zpět pod první osmici pixelů
        dec e                    ; korekce
        inc d                    ; posun na definici dalšího obrazového řádku (+256)
        djnz loop                ; vnitřní smyčka: blok s 3x osmi zápisy
        ret                      ; návrat z podprogramu
 
 
 
SPRITE_ADR
        db %00000000, %00000000, %00000000
        db %00000000, %00000000, %00000000
        db %00000001, %11110000, %00010000
        db %00000011, %00111000, %00010000
        db %00000101, %11010111, %00010000
        db %00000101, %11001100, %00010000
        db %00000101, %00110000, %00010000
        db %00000100, %11001000, %00010000
        db %00000111, %00110110, %00010000
        db %00001100, %11111110, %00111000
        db %00011111, %11111000, %00000000
        db %00000000, %00000000, %00110000
        db %00000011, %11111111, %10110000
        db %00000101, %11111110, %11100000
        db %00001110, %11111101, %11000000
        db %00011000, %11111100, %00000000
        db %00011000, %00000000, %00000000
        db %00000001, %11111000, %00000000
        db %00000011, %11111100, %00000000
        db %00000001, %10110000, %00000000
        db %00000010, %00001100, %00000000
        db %00000111, %00001110, %00000000
        db %00011110, %00000111, %10000000
        db %00000000, %00000000, %00000000
 
 
LOADING_SCREN incbin "Alien8.scr"
 
 
 
end ENTRY_POINT

15. Korektní výpočet adres zapisovaných bajtů při zobrazení spritu

Některé problémy lze ve skutečnosti opravit relativně snadno. Podívejme se například na řešení problému korektního výpočtu adres zapisovaných bajtů (3 bajty na obrazový řádek, 24 obrazových řádků). Prozatím vypadá vykreslení spritu v nejvyšší úrovni abstrakce takto:

ld b, 0                  ; x-ová souřadnice
ld c, 3                  ; y-ová souřadnice
call calc_sprite_address ; výpočet adresy spritu
call draw_sprite

To je v pořádku – adresu vypočteme (mimochodem: složitým způsobem s mnoha bitovými operacemi) jen jedenkrát a poté se již volá subrutina pro vykreslení celého spritu. Ta vypadá následovně:

draw_sprite:
    ld hl, SPRITE_ADR        ; adresa, od níž začíná maska spritu
    push de
    call draw_8_lines        ; vykreslit prvních 8 řádků spritu
 
    pop  de
    add_e 32                 ; zvýšit E o hodnotu 32
    push de
    call draw_8_lines        ; vykreslit druhých 8 řádků spritu
 
    pop  de
    add_e 32                 ; zvýšit E o hodnotu 32
    call draw_8_lines        ; vykreslit třetích 8 řádků spritu
 
    ret                      ; návrat z podprogramu

A zde nastává problém – posun adresy o 32 bajtů skutečně odpovídá přechodu o osm obrazových řádků (ano – obrazová paměť má takový formát), jenže to neplatí u přechodu na další třetinu obrazovky, tj. přes hranici 2048 bajtů. Ovšem můžeme využít triku, který již popsal kolega dw (ještě jednou díky); necháme si adresu vypočítat přímo subrutinou draw8_lines. Tím se nám subrutina pro vykreslení spritu zjednoduší na pouhých pět instrukcí:

draw_sprite:
    ld hl, SPRITE_ADR        ; adresa, od níž začíná maska spritu
    call draw_8_lines        ; vykreslit prvních 8 řádků spritu + upravit DE pro následující řádek
    call draw_8_lines        ; vykreslit druhých 8 řádků spritu + upravit DE pro následující řádek
    call draw_8_lines        ; vykreslit třetích 8 řádků spritu + upravit DE pro následující řádek
    ret                      ; návrat z podprogramu

Naproti tomu ovšem musíme měnit dvojregistr DE v subrutině draw8_lines. On se zde ve skutečnosti modifikoval již předtím, ovšem musíme to nyní provést správně. Budeme zjišťovat, zda se nepřekročila oblast 2048 bajtů a pokud ne, bude DE zvýšeno o 32 (tedy přeskok na další obrazový řádek) a pokud ano, musí se upravit i vyšší bajt adresy, tedy registr D (přeskočíme do další třetiny obrazovky, ovšem na její začátek, přesněji řečeno na jeden z řádků 0 až 7):

draw_8_lines:
    ld  bc, 8*(256+2)        ; počitadlo zapsaných řádků
loop:
    ldi                      ; přesun jednoho bajtu + úprava stavu počitadla [DE++] = [HL++]; BC--
    ldi                      ; přesun jednoho bajtu + úprava stavu počitadla [DE++] = [HL++]; BC--
    ld  a,(hl)               ; načtení jednoho bajtu z masky
    ld  (de),a               ; zápis hodnoty na adresu (DE)
    inc hl                   ; posun na další bajt masky
                             ; nyní je vykresleno všech 24 pixelů na řádku
    dec e                    ; korekce (po prvním LDI)
    dec e                    ; korekce (po druhém LDI)
    inc d                    ; posun na definici dalšího obrazového řádku
                             ; nyní DE ukazuje správně na první bajt na dalším řádku
    djnz loop                ; vnitřní smyčka: blok s 3x osmi zápisy
    ld  a, e                 ; \
    add a, 32                ;  > E += 32
    ld  e, a                 ; /
    ret c                    ; návrat při přenosu (další stránka)
    ld  a, d                 ; \
    sub 8                    ;  > D -= 8
    ld  d, a                 ; /
    ret                      ; návrat z podprogramu

Rozdíly jsou patrné na první pohled:

Obrázek 13: Nekorektní přechody mezi třetinami obrazovky.

Obrázek 14: Korektní přechody mezi třetinami obrazovky.

16. Úplný zdrojový kód dnešního sedmého demonstračního příkladu

Úplný zdrojový kód dnešního sedmého a současně i posledního demonstračního příkladu vypadá následovně:

SCREEN_ADR      equ $4000
ENTRY_POINT     equ $8000
 
    org ENTRY_POINT
 
start:
    ld b, 0                  ; x-ová souřadnice
    ld c, 3                  ; y-ová souřadnice
    call calc_sprite_address ; výpočet adresy spritu
    call draw_sprite
 
    ld b, 4                  ; x-ová souřadnice
    ld c, 4                  ; y-ová souřadnice
    call calc_sprite_address ; výpočet adresy
    call draw_sprite
 
    ld b, 8                  ; x-ová souřadnice
    ld c, 5                  ; y-ová souřadnice
    call calc_sprite_address ; výpočet adresy
    call draw_sprite
 
    ld b, 12                 ; x-ová souřadnice
    ld c, 6                  ; y-ová souřadnice
    call calc_sprite_address ; výpočet adresy
    call draw_sprite
 
    ld b, 16                 ; x-ová souřadnice
    ld c, 7                  ; y-ová souřadnice
    call calc_sprite_address ; výpočet adresy
    call draw_sprite
 
    ld b, 20                 ; x-ová souřadnice
    ld c, 8                  ; y-ová souřadnice
    call calc_sprite_address ; výpočet adresy
    call draw_sprite
 
    ld b, 24                 ; x-ová souřadnice
    ld c, 9                  ; y-ová souřadnice
    call calc_sprite_address ; výpočet adresy
    call draw_sprite
 
finish:
    jr finish                ; žádný návrat do systému
 
 
calc_sprite_address:
    ; parametry:
    ; B - x-ová souřadnice (ve znacích, ne pixelech)
    ; C - y-ová souřadnice (ve znacích, ne pixelech)
    ;
    ; návratové hodnoty:
    ; DE - adresa pro zápis bloku
    ;
    ; vzor adresy:
    ; 0 1 0 Y4 Y3 0 0 0 | Y2 Y1 Y0 X4 X3 X2 X1 X0
    ld  a, c
    and %00000111            ; pouze spodní tři bity y-ové souřadnice (řádky 0..7)
    rrca
    rrca
    rrca                     ; nyní jsou čísla řádků v horních třech bitech
    or  b                    ; připočítat x-ovou souřadnici
    ld  e, a                 ; máme spodní bajt adresy
                             ; Y2 Y1 Y0 X4 X3 X2 X1 X0
 
    ld  a, c                 ; y-ová souřadnice
    and %00011000            ; dva bity s indexem "bloku" 0..3 (dolní tři bity už máme zpracovány)
    or  %01000000            ; "posun" do obrazové paměti (na 0x4000)
    ld  d, a                 ; máme horní bajt adresy
                             ; 0 1 0 Y5 Y4 0 0 0
    ret                      ; návrat z podprogramu
 
 
add_e MACRO n                    ; zvýšení hodnoty regitru E
    ld   a, e
    add  a, n
    ld   e, a
endm
 
 
draw_sprite:
    ld hl, SPRITE_ADR        ; adresa, od níž začíná maska spritu
    call draw_8_lines        ; vykreslit prvních 8 řádků spritu + upravit DE pro následující řádek
    call draw_8_lines        ; vykreslit druhých 8 řádků spritu + upravit DE pro následující řádek
    call draw_8_lines        ; vykreslit třetích 8 řádků spritu + upravit DE pro následující řádek
    ret                      ; návrat z podprogramu
 
 
draw_8_lines:
    ld  bc, 8*(256+2)        ; počitadlo zapsaných řádků
loop:
    ldi                      ; přesun jednoho bajtu + úprava stavu počitadla [DE++] = [HL++]; BC--
    ldi                      ; přesun jednoho bajtu + úprava stavu počitadla [DE++] = [HL++]; BC--
    ld  a,(hl)               ; načtení jednoho bajtu z masky
    ld  (de),a               ; zápis hodnoty na adresu (DE)
    inc hl                   ; posun na další bajt masky
                             ; nyní je vykresleno všech 24 pixelů na řádku
    dec e                    ; korekce (po prvním LDI)
    dec e                    ; korekce (po druhém LDI)
    inc d                    ; posun na definici dalšího obrazového řádku
                             ; nyní DE ukazuje správně na první bajt na dalším řádku
    djnz loop                ; vnitřní smyčka: blok s 3x osmi zápisy
    ld  a, e                 ; \
    add a, 32                ;  > E += 32
    ld  e, a                 ; /
    ret c                    ; návrat při přenosu (další stránka)
    ld  a, d                 ; \
    sub 8                    ;  > D -= 8
    ld  d, a                 ; /
    ret                      ; návrat z podprogramu
 
 
 
SPRITE_ADR
    db %00000000, %00000000, %00000000
    db %00000000, %00000000, %00000000
    db %00000001, %11110000, %00010000
    db %00000011, %00111000, %00010000
    db %00000101, %11010111, %00010000
    db %00000101, %11001100, %00010000
    db %00000101, %00110000, %00010000
    db %00000100, %11001000, %00010000
    db %00000111, %00110110, %00010000
    db %00001100, %11111110, %00111000
    db %00011111, %11111000, %00000000
    db %00000000, %00000000, %00110000
    db %00000011, %11111111, %10110000
    db %00000101, %11111110, %11100000
    db %00001110, %11111101, %11000000
    db %00011000, %11111100, %00000000
    db %00011000, %00000000, %00000000
    db %00000001, %11111000, %00000000
    db %00000011, %11111100, %00000000
    db %00000001, %10110000, %00000000
    db %00000010, %00001100, %00000000
    db %00000111, %00001110, %00000000
    db %00011110, %00000111, %10000000
    db %00000000, %00000000, %00000000
 
 
end ENTRY_POINT

17. Jak dále?

Nejpalčivější problém tedy máme vyřešen, ale zbývá nám dořešit ještě několik dalších problémů, zejména pak:

  1. Výpočet jemného posunu spritu v SW, nikoli jeho předpočítáním.
  2. Správné „proložení“ spritu s bitmapovým pozadím.
  3. Správné zobrazení barvových atributů (to nevyřešíme :-).

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

Výše uvedené demonstrační příklady i příklady, které již byly popsány v předchozích osmnácti článcích [1] [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14], [15], [16], [17], [18], 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, jak je již v tomto seriálu zvykem, 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 \
    101.tap 102.tap 103.tap 104.tap 105.tap 106.tap 107.tap 108.tap 109.tap \
    110.tap 111.tap 112.tap 113.tap 114.tap 115.tap 116.tap 117.tap 118.tap \
    119.tap 120.tap 121.tap 122.tap 123.tap 124.tap 125.tap 126.tap 127.tap \
    128.tap 129.tap 130.tap 131.tap 132.tap 133.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
 
103.tap:        103-beep.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 103-beep.lst
 
104.tap:        104-music-scale.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 104-music-scale.lst
 
105.tap:        105-direct-speaker.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 105-direct-speaker.lst
 
106.tap:        106-direct-speaker-di.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 106-direct-speaker-di.lst
 
107.tap:        107-direct-speaker-border.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 107-direct-speaker-border.lst
 
108.tap:        108-direct-speaker-border-di.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 108-direct-speaker-border-di.lst
 
109.tap:        109-ay-note-a.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 109-ay-note-a.lst
 
110.tap:        110-ay-note-a.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 110-ay-note-a.lst
 
111.tap:        111-ay-two-notes.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 111-ay-two-notes.lst
 
112.tap:        112-ay-noise.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 112-ay-noise.lst
 
113.tap:        113-ay-low-frequency.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 113-ay-low-frequency.lst
 
114.tap:        114-ay-high-frequency.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 114-ay-high-frequency.lst
 
115.tap:        115-ay-low-noise.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 115-ay-low-noise.lst
 
116.tap:        116-ay-envelope.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 116-ay-envelope.lst
 
117.tap:        117-ay-envelope.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 117-ay-envelope.lst
 
118.tap:        118-ay-envelope.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 118-ay-envelope.lst
 
119.tap:        119-noise-envelope.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 119-noise-envelope.lst
 
120.tap:        120-8x8-sprite.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 120-8x8-sprite.lst
 
121.tap:        121-24x24-sprite.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 121-24x24-sprite.lst
 
122.tap:        122-24x24-sprite.asm sprite.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 122-24x24-sprite.lst
 
123.tap:        123-24x24-sprite.asm sprite.bin
        $(ASSEMBLER) -v -d --tapbas $< $@ > 123-24x24-sprite.lst
 
124.tap:        124-shifted-sprite.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 124-shifted-sprite.lst
 
125.tap:        125-shifted-sprite.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 125-shifted-sprite.lst
 
126.tap:        126-24x24-faster-sprite.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 126-24x24-faster-sprite.lst
 
127.tap:        127-margins.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 127-margins.lst
 
128.tap:        128-margins.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 128-margins.lst
 
129.tap:        129-screen-addressing.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 129-screen-addressing.lst
 
130.tap:        130-screen-background.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 130-screen-background.lst
 
131.tap:        131-screen-background-and-sprite.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 131-screen-background-and-sprite.lst
 
132.tap:        132-improper-sprite-addressing.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 132-improper-sprite-addressing.lst
 
133.tap:        133-proper-sprite-addressing.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 133-proper-sprite-addressing.lst

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

V tabulce zobrazené pod tímto odstavcem jsou uvedeny odkazy na všechny prozatím popsané demonstrační příklady určené pro překlad a spuštění na osmibitovém domácím mikropočítači ZX Spectrum (libovolný model či jeho klon), které jsou psány v assembleru mikroprocesoru Zilog Z80. Pro překlad těchto demonstračních příkladů je možné použít například assembler Pasmo (viz též úvodní článek):

# Soubor Stručný popis Adresa
1 01-color-attribute.asm modifikace jednoho barvového atributu https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/01-color-attribute.asm
2 02-blinking-attribute.asm barvový atribut s nastavením bitů pro blikání a vyšší intenzitu https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/02-blinking-attribute.asm
3 03-symbolic-names.asm symbolická jména v assembleru https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/03-symbolic-names.asm
4 04-operators.asm operátory a operace se symbolickými hodnotami https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/04-operators.asm
5 05-better-symbols.asm tradičnější symbolická jména https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/05-better-symbols.asm
6 06-tapbas-v1.asm vygenerování BASICovského loaderu (neúplný příklad) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/06-tapbas-v1.asm
7 07-tapbas-v2.asm vygenerování BASICovského loaderu (úplný příklad) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/07-tapbas-v2.asm
8 08-loop.asm jednoduchá počítaná programová smyčka: naivní varianta https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/08-loop.asm
9 09-loop.asm programová smyčka: zkrácení kódu pro vynulování použitých pracovních registrů https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/09-loop.asm
10 10-loop.asm programová smyčka: optimalizace skoku na konci smyčky (instrukce DJNZ) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/10-loop.asm
11 11-loop.asm programová smyčka: optimalizace využití pracovních registrů https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/11-loop.asm
12 12-loop.asm programová smyčka: použití pracovního registru IX https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/12-loop.asm
13 13-loop.asm programová smyčka: použití pracovního registru IY https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/13-loop.asm
14 14-loop.asm programová smyčka se šestnáctibitovým počitadlem, základní varianta https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/14-loop.asm
15 15-loop.asm programová smyčka se šestnáctibitovým počitadlem, vylepšená varianta https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/15-loop.asm
16 16-loop.asm použití relativního skoku a nikoli skoku absolutního https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/16-loop.asm
17 17-loop.asm programová smyčka: inc l namísto inc hl https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/17-loop.asm
       
18 18-cls.asm smazání obrazovky a otevření kanálu číslo 2 (screen) přes funkci v ROM https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/18-cls.asm
19 19-print-char-call.asm smazání obrazovky a výpis jednoho znaku na obrazovku přes funkci v ROM (použití instrukce CALL) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/19-print-char-call.asm
20 20-print-char-rst.asm smazání obrazovky a výpis jednoho znaku na obrazovku přes funkci v ROM (použití instrukce RST) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/20-print-char-rst.asm
21 21-print-char.asm pouze výpis jednoho znaku na obrazovku bez jejího smazání https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/21-print-char.asm
22 22-print-all-chars.asm výpis znakové sady znak po znaku (nekorektní verze příkladu) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/22-print-all-chars.asm
23 23-print-all-chars.asm výpis znakové sady znak po znaku (korektní verze příkladu) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/23-print-all-chars.asm
24 24-change-color.asm změna barvových atributů (popředí a pozadí) vypisovaných znaků https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/24-change-color.asm
25 25-change-flash.asm povolení či zákaz blikání vypisovaných znaků https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/25-change-flash.asm
26 26-print-at.asm výpis znaku či znaků na určené místo na obrazovce https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/26-print-at.asm
27 27-print-string.asm výpis celého řetězce explicitně zapsanou programovou smyčkou (základní varianta) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/27-print-string.asm
28 28-print-string.asm výpis celého řetězce explicitně zapsanou programovou smyčkou (vylepšená varianta) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/28-print-string.asm
29 29-print-colorized-string.asm výpis řetězce, který obsahuje i řídicí znaky pro změnu barvy atd. https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/29-print-colorized-string.asm
30 30-print-string-ROM.asm výpis řetězce s využitím služby/subrutiny uložené v ROM ZX Spectra https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/30-print-string-ROM.asm
       
31 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 103-beep.asm využití subrutiny v ROM s implementací příkazu BEEP https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/103-beep.asm
104 104-music-scale.asm přehrání celé stupnice https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/104-music-scale.asm
105 105-direct-speaker.asm přímé programové ovládání beeperu https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/105-direct-speaker.asm
106 106-direct-speaker-di.asm zakázání přerušení při přehrávání https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/106-direct-speaker-di.asm
107 107-direct-speaker-border.asm vizualizace frekvence přehrávání změnou okraje v reálném čase https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/107-direct-speaker-border.asm
108 108-direct-speaker-border-di.asm vizualizace frekvence přehrávání změnou okraje v reálném čase https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/108-direct-speaker-border-di.asm
       
109 109-ay-note-a.asm přehrání komorního A na čipu AY-3–8912 na ZX Spectru https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/109-ay-note-a.asm
110 110-ay-note-a.asm přehrání komorního A na čipu AY-3–8912 na ZX Spectru https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/110-ay-note-a.asm
       
111 111-ay-two-notes.asm souběžné přehrání dvojice not https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/111-ay-two-notes.asm
112 112-ay-noise.asm vygenerování šumu https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/112-ay-noise.asm
113 113-ay-low-frequency.asm čistý tón s nízkou frekvencí https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/113-ay-low-frequency.asm
114 114-ay-high-frequency.asm čistý tón s vysokou frekvencí https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/114-ay-high-frequency.asm
115 115-ay-low-noise.asm vygenerování šumu s nízkou frekvencí https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/115-ay-low-noise.asm
116 116-ay-envelope.asm použití obálky založené na trojúhelníkovém signálu https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/116-ay-envelope.asm
117 117-ay-envelope.asm použití obálky založené na trojúhelníkovém signálu s vysokou frekvencí https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/117-ay-envelope.asm
118 118-ay-envelope.asm použití obálky založené na trojúhelníkovém signálu s nízkou frekvencí https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/118-ay-envelope.asm
119 119-noise-envelope.asm použití obálky společně se šumem https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/119-noise-envelope.asm
       
120 120–8×8-sprite.asm vykreslení spritu o velikosti 8×8 pixelů na obrazovku https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/120–8×8-sprite.asm
121 121–24×24-sprite.asm vykreslení spritu o velikosti 24×24 pixelů na obrazovku https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/121–24×24-sprite.asm
122 122–24×24-sprite.asm načtení spritu o velikosti 24×24 pixelů z include souboru a jeho vykreslení na obrazovku https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/122–24×24-sprite.asm
123 123–24×24-sprite.asm načtení spritu o velikosti 24×24 pixelů z binárního souboru a jeho vykreslení na obrazovku https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/123–24×24-sprite.asm
124 124-shifted-sprite.asm načtení spritů posunutých o 0 až 7 pixelů z binárních souborů https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/124-shifted-sprite.asm
125 125-shifted-sprite.asm načtení spritů posunutých o 0 až 7 pixelů z include souborů https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/125-shifted-sprite.asm
       
126 126–24×24-faster-sprite.asm úprava příkladu 121–24×24-sprite.asm do rychlejší podoby https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/126–24×24-faster-sprite.asm
127 127-margins.asm pokus o vykreslení spritu blízko pravého okraje obrazovky https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/127-margins.asm
128 128-margins.asm pokus o vykreslení spritu blízko spodního okraje obrazovky https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/128-margins.asm
129 129-screen-addressing.asm problém uspořádání obrazových řádků na ZX Spectru https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/129-screen-addressing.asm
130 130-screen-background.asm vykreslení statického obrázku na obrazovku ZX Spectra https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/130-screen-background.asm
131 131-screen-background-and-sprite.asm vykreslení spritu na obrazovku se statickým obrázkem https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/131-screen-background-and-sprite.asm
132 132-improper-sprite-addresing.asm větší množství spritů, nekorektní výpočty adres řádků https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/132-improper-sprite-addresing.asm
133 133-proper-sprite-addresing.asm větší množství spritů, korektní výpočty adres řádků https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/133-proper-sprite-addresing.asm
       
134 Makefile Makefile pro překlad a slinkování všech demonstračních příkladů do podoby obrazu magnetické pásky https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/Makefile

20. Odkazy na Internetu

  1. z80 standalone assembler
    https://www.asm80.com/one­page/asmz80.html
  2. The ZX BASIC Compiler
    https://www.boriel.com/pages/the-zx-basic-compiler.html
  3. Z80 Assembly programming for the ZX Spectrum
    https://www.chibiakumas.com/z80/ZXSpec­trum.php
  4. 8-BIT SMACKDOWN! 65C02 vs. Z80: slithy VLOGS #6
    https://www.youtube.com/wat­ch?v=P1paVoFEvyc
  5. Instrukce mikroprocesoru Z80
    https://clrhome.org/table/
  6. Z80 instructions: adresní režimy atd.
    https://jnz.dk/z80/instructions.html
  7. Z80 Instruction Groups
    https://jnz.dk/z80/instgroups.html
  8. Elena, New programming language for the ZX Spectrum Next
    https://vintageisthenewold.com/elena-new-programming-language-for-the-zx-spectrum-next/
  9. Sinclair BASIC
    https://worldofspectrum.net/legacy-info/sinclair-basic/
  10. Grafika na osmibitových počítačích firmy Sinclair
    https://www.root.cz/clanky/grafika-na-osmibitovych-pocitacich-firmy-sinclair/
  11. Grafika na osmibitových počítačích firmy Sinclair II
    https://www.root.cz/clanky/grafika-na-osmibitovych-pocitacich-firmy-sinclair-ii/
  12. HiSoft BASIC
    https://worldofspectrum.net/in­foseekid.cgi?id=0008249
  13. YS MegaBasic
    https://worldofspectrum.net/in­foseekid.cgi?id=0008997
  14. Beta Basic
    https://worldofspectrum.net/in­foseekid.cgi?id=0007956
  15. BASIC+
    https://worldofspectrum.net/in­foseekid.php?id=0014277
  16. Spectrum ROM Memory Map
    https://skoolkit.ca/disas­semblies/rom/maps/all.html
  17. Goto subroutine
    https://skoolkit.ca/disas­semblies/rom/asm/7783.html
  18. Spectrum Next: The Evolution of the Speccy
    https://www.specnext.com/about/
  19. Sedmdesátiny assemblerů: lidsky čitelný strojový kód
    https://www.root.cz/clanky/sed­mdesatiny-assembleru-lidsky-citelny-strojovy-kod/
  20. Programovací jazyk BASIC na osmibitových mikropočítačích
    https://www.root.cz/clanky/pro­gramovaci-jazyk-basic-na-osmibitovych-mikropocitacich/
  21. Programovací jazyk BASIC na osmibitových mikropočítačích (2)
    https://www.root.cz/clanky/pro­gramovaci-jazyk-basic-na-osmibitovych-mikropocitacich-2/#k06
  22. Programovací jazyk BASIC na osmibitových mikropočítačích (3)
    https://www.root.cz/clanky/pro­gramovaci-jazyk-basic-na-osmibitovych-mikropocitacich-3/
  23. Sinclair BASIC (Wikipedia CZ)
    http://cs.wikipedia.org/wi­ki/Sinclair_BASIC
  24. Assembly Language: Still Relevant Today
    http://wilsonminesco.com/AssyDefense/
  25. Programovani v assembleru na OS Linux
    http://www.cs.vsb.cz/gryga­rek/asm/asmlinux.html
  26. Why Assembly Language Programming? (Why Learning Assembly Language Is Still a Good Idea)
    https://wdc65×x.com/market­s/education/why-assembly-language-programming/
  27. Low Fat Computing
    http://www.ultratechnology­.com/lowfat.htm
  28. Assembly Language
    https://www.cleverism.com/skills-and-tools/assembly-language/
  29. Why do we need assembly language?
    https://cs.stackexchange.com/qu­estions/13287/why-do-we-need-assembly-language
  30. Assembly language (Wikipedia)
    https://en.wikipedia.org/wi­ki/Assembly_language#Histo­rical_perspective
  31. Assembly languages
    https://curlie.org/Computer­s/Programming/Languages/As­sembly/
  32. vasm
    http://sun.hasenbraten.de/vasm/
  33. B-ELITE
    https://jsj.itch.io/b-elite
  34. ZX-Spectrum Child
    http://www.dotkam.com/2008/11/19/zx-spectrum-child/
  35. Speccy.cz
    http://www.speccy.cz/
  36. Planet Sinclair
    http://www.nvg.ntnu.no/sinclair/
  37. World of Spectrum
    http://www.worldofspectrum.org/
  38. 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
  72. When A Single Bit Was Enough, Into The Sound Of The ZX Spectrum
    https://hackaday.com/2022/01/20/when-a-single-bit-was-enough-into-the-sound-of-the-zx-spectrum/
  73. 03B5: THE ‚BEEPER‘ SUBROUTINE
    https://skoolkid.github.i­o/rom/asm/03B5.html
  74. How To Write ZX Spectrum Games – Chapter 3
    https://chuntey.wordpress­.com/2013/02/28/how-to-write-zx-spectrum-games-chapter-3/
  75. Understanding computer sound
    https://www.youtube.com/pla­ylist?list=PL0qES-IQZC8w4vqeQhxHxKgxYYqs3CEOx
  76. Understanding Computer Sound. 5. ZX Spectrum
    https://www.youtube.com/wat­ch?v=N5ACJd2LvbY
  77. Dark Fusion (Gremlin Graphics, 1988)
    https://www.youtube.com/wat­ch?v=ADL3mdRMzoA
  78. Arkanoid Spectrum Title Music
    https://www.youtube.com/wat­ch?v=TymO0Lj7Vp8
  79. Tim Follin – „Chronos“ (ZX Spectrum) [Oscilloscope Visualization]
    https://www.youtube.com/wat­ch?v=yJy45MHrPjc
  80. [60 FPS] Wally Beben – „Sanxion Loader“ [ZX Spectrum (Beeper)] (Oscilloscope View)
    https://www.youtube.com/wat­ch?v=JwMxOfQVl7A
  81. Understanding Computer Sound
    http://forgottencomputer.com/re­tro/sound/
  82. AY-3–8912
    https://sinclair.wiki.zxnet­.co.uk/wiki/AY-3–8912
  83. AY-3–8912
    https://github.com/topics/ay-3–8912
  84. Z80 Assembly programming for the ZX Spectrum
    https://www.chibiakumas.com/z80/ZXSpec­trum.php?noui=1
  85. AY-3–8910
    http://vgmpf.com/Wiki/index.php/AY-3–8910
  86. AY-3–8910/8912 Programmable sound generator data manual
    https://f.rdw.se/AY-3–8910-datasheet.pdf
  87. Sprite (computer graphics)
    https://en.wikipedia.org/wi­ki/Sprite_(computer_graphic­s)
  88. Piskel is a free online editor for animated sprites & pixel art
    https://www.piskelapp.com/
  89. TAP format
    https://sinclair.wiki.zxnet­.co.uk/wiki/TAP_format

Autor článku

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