VBI (Vertical Blank Interrupt) na osmibitových mikropočítačích Atari

14. 5. 2026
Doba čtení: 72 minut

Sdílet

Projekt Atari perex.
Autor: Michal Tauchman, podle licence: CC BY-SA 4.0
Projekt Atari perex.
Popíšeme si VBI, tedy Vertical Blank Interrupt. Jde o subrutiny volané po dokončení vykreslování snímku, či na začátku vykreslování dalšího snímku. Mnohé hry mají své jádro (kernel) implementované právě přímo ve VBI.

VBI – Vertical Blank Interrupt

Co se dozvíte v článku
  1. VBI – Vertical Blank Interrupt
  2. Krátké připomenutí: příklad s aktivním čekáním na dokončení překreslení snímku
  3. Podprogram pro pohyb hráče joystickem realizovaný ve VBI
  4. První způsob nastavení vektoru pro VBI
  5. Úplný zdrojový kód druhého demonstračního příkladu
  6. Druhý způsob nastavení vektoru pro VBI
  7. Úplný zdrojový kód třetího demonstračního příkladu
  8. Kombinace DLI a VBI v jednom programu
  9. Úplný zdrojový kód čtvrtého demonstračního příkladu
  10. Odstranění nadbytečné instrukce RTS na konci obsluhy VBI
  11. Úplný zdrojový kód pátého demonstračního příkladu
  12. Refaktoring kódu v assembleru: subrutiny a makra
  13. Přepis všech částí programu do formy podprogramů (subrutin)
  14. Úplný zdrojový kód šestého demonstračního příkladu
  15. Přepis všech částí programu do formy maker
  16. Úplný zdrojový kód sedmého demonstračního příkladu
  17. Obsah navazujícího článku
  18. Příloha: Makefile pro překlad všech demonstračních příkladů
  19. Repositář s demonstračními příklady
  20. Odkazy na Internetu

V předchozím článku o vývoji her a dalších aplikací pro osmibitové domácí mikropočítače Atari jsme si představili základní koncepty DLI neboli Display List Interruptu. Připomeňme si, že přímo v display listu, který popisuje strukturu obrazové paměti i způsob jejího vykreslení, je možné u libovolných řádků povolit tzv. DLI. Čip ANTIC u takových řádků (nepřímo) zavolá podprogram (subrutinu), která DLI obslouží. Tyto podprogramy musí být poměrně rychlé, protože pro obsluhu DLI je k dispozici přibližně 114 cyklů, přičemž jedna strojová instrukce trvá 2 až 8 cyklů. V DLI se tedy provádí jen základní operace, které souvisí s jednotlivými částmi obrazovky (zobrazení více spritů, vícebarevné pozadí, přepnutí znakové sady atd.).

Ovšem navíc a prakticky zcela nezávisle na DLI je možné naprogramovat subrutinu či subrutiny, které se spouští po vykreslení celého snímku, tedy ještě před začátkem dalšího snímku. Popř. je možné sice začít s výpočtem před začátkem dalšího snímku, ale výpočet může pokračovat i při jeho vykreslování (více než 20000 strojových cyklů). K tomuto účelu slouží VBI neboli Vertical Blank Interrupt. Výhodou VBI je, že programátor má k dispozici mnohem větší počet strojových cyklů, takže se mnohdy celá herní logika vejde právě do VBI. Obsluha VBI je nepatrně složitější, než v případě DLI. Celé zpracování je totiž rozděleno do čtyř částí (což jsou jednotlivé podprogramy, které se vzájemně volají):

Rutina Poznámka
VBLANK lze naprogramovat, přibližně 2500 strojových cyklů (3800 bez systémové části)
SYSVBV systémový podprogram
Odložený VBLANK cca 20000 cyklů (cca 4500 instrukcí), z toho přibližně 2778 při kreslení prázdných řádků na začátku obrazovky
XITVBV zavoláno při opouštění odloženého VBLANKu

Programátor tedy může vytvořit dva podprogramy pro obsluhu VBI. První podprogram by měl mít délku do cca 2500 strojových cyklů a jeho předností je, že je skutečně vykonáván tehdy, pokud se neprovádí vykreslování (posílají se SYNCy do televizoru a paprsek se vrací na začátek obrazovky). Druhý podprogram pro „odložený“ VBLANK může být mnohem delší, protože se provádí během vykreslování snímku. Ovšem na začátku obrazovky se typicky nachází 24 prázdných obrazových řádků, takže několik set cyklů (uvádí se 2778, ovšem podle mě je to méně, 2778 cyklů odpovídá 24×63,5µs) lze využít pro provádění grafických operací, které nezpůsobí problikávání obrazovky atd. (například pohyby spritů).

Poznámka: odložený VBLANK musí v každém případě skončit dřív, než nastane další VBI. Příště si otestujeme, co se stane, pokud tato podmínka není splněna.

Krátké připomenutí: příklad s aktivním čekáním na dokončení překreslení snímku

V předchozích částech tohoto seriálu jsme si mj. ukázali způsob vykreslování PMG (Player Missile Graphics), tj. pohyblivých objektů na obrazovce (neboli spritů). Dokonce jsme tyto sprity ovládali s využitím joysticku. Ovšem právě při ovládání spritů, což je vlastně jedna z forem primitivní animace, bylo nutné zajistit, aby se rychlost pohybu sesynchronizovala s generováním snímků na obrazovce. Tím se zajistí, že rychlost výsledné hry bude konstantní a nebude zapotřebí hlídat časovače atd.

Poznámka: Ve skutečnosti je zde velký rozdíl mezi normami PAL a NTSC, o tomto problému však vyjde samostatný článek).

Připomeňme si, že čekání na dokončení snímku jsme (alespoň prozatím) prováděli aktivním čekáním na změnu hodnoty časovače RTCLOK, přesněji řečeno na změnu jeho nejnižšího bajtu. Využívalo se přitom toho faktu, že časovač je modifikován právě po dokreslení celého snímku:

; ---------------------------------------------------------------------
; subrutina pro čekání na konec snímku
; ---------------------------------------------------------------------
.proc   _wait_vsync
        ldx     RTCLOK+2        ; čekání na konec snímku
@wt:    cpx     RTCLOK+2
        beq     @wt
        rts
.endproc

Úplný zdrojový kód příkladu, ve kterém je realizován pohyb prvním hráčem s využitím joysticku, vypadal následovně:

; ---------------------------------------------------------------------
; Ovládání PMG joystickem v horizontálním směru.
; Aktivní čekání na dokončení vykreslování snímku.
; ---------------------------------------------------------------------
 
.include "atari.inc"
 
.CODE
 
PLAYER_0_OFFSET = 512
PLAYER_1_OFFSET = PLAYER_0_OFFSET + 128
PLAYER_2_OFFSET = PLAYER_1_OFFSET + 128
PLAYER_3_OFFSET = PLAYER_2_OFFSET + 128
 
 
; ---------------------------------------------------------------------
; vstupní bod do programu
; ---------------------------------------------------------------------
.proc main
        lda #80                 ; horizontální pozice prvního hráče
        sta HPOSP0              ; uložit do řídicího registru HPOSP0 na čipu GTIA
 
        lda #100                ; horizontální pozice druhého hráče
        sta HPOSP1              ; uložit do řídicího registru HPOSP1 na čipu GTIA
 
        lda #120                ; horizontální pozice třetího hráče
        sta HPOSP2              ; uložit do řídicího registru HPOSP2 na čipu GTIA
 
        lda #140                ; horizontální pozice čtvrtého hráče
        sta HPOSP3              ; uložit do řídicího registru HPOSP3 na čipu GTIA
 
        lda #HUE_GREEN<<4 + 12  ; barva prvního hráče (odstín+intenzita)
        sta PCOLR0              ; uložit do řídicího registru PCOLR0 na čipu GTIA
 
        lda #HUE_YELLOW<<4 + 12 ; barva druhého hráče (odstín+intenzita)
        sta PCOLR1              ; uložit do řídicího registru PCOLR1 na čipu GTIA
 
        lda #HUE_MAGENTA<<4 + 12 ; barva třetího hráče (odstín+intenzita)
        sta PCOLR2              ; uložit do řídicího registru PCOLR2 na čipu GTIA
 
        lda #HUE_CYAN<<4 + 12   ; barva čtvrtého hráče (odstín+intenzita)
        sta PCOLR3              ; uložit do řídicího registru PCOLR3 na čipu GTIA
 
        lda #$ff                ; bitová maska všech hráčů
        sta GRAFP0              ; uložit do řídicího registru GRAFP0 na čipu GTIA
        sta GRAFP1              ; uložit do řídicího registru GRAFP1 na čipu GTIA
        sta GRAFP2              ; uložit do řídicího registru GRAFP2 na čipu GTIA
        sta GRAFP3              ; uložit do řídicího registru GRAFP3 na čipu GTIA
 
        lda #3                  ; bitové pole: povolení hráčů i střel
        sta GRACTL              ; uložit do řídicího registru GRACTL na čipu GTIA
 
        lda #0                  ; priorita hráčů a pozadí
        sta GPRIOR              ; uložit do řídicího registru GPRIOR na čipu GTIA
 
        lda #152                ; paměťová stránka číslo 152
        sta PMBASE
 
        addr = 152*256
        ldx #8                  ; začneme na hodnotě o 1 vyšší
next_line:
        lda sprite-1, x         ; načíst
        sta addr+PLAYER_0_OFFSET+50, x  ; uložit byte - první hráč
        sta addr+PLAYER_1_OFFSET+50, x  ; uložit byte - druhý hráč
        sta addr+PLAYER_2_OFFSET+50, x  ; uložit byte - třetí hráč
        sta addr+PLAYER_3_OFFSET+50, x  ; uložit byte - čtvrtý hráč
        dex                     ; snížit offset + nastavit příznaky
        bne next_line           ; další byte spritu
 
        lda #46                 ; povolení PMG DMA
        sta SDMCTL
 
loop:
        jsr horizontal_movement
        jmp loop
.endproc
 
 
; ---------------------------------------------------------------------
; subrutina pro horizontální posun prvního hráče
; ---------------------------------------------------------------------
.proc   horizontal_movement
        ldx x_pos               ; původní pozice prvního hráče
        txa                     ; uložení obsahu X do akumulátoru
        jsr _wait_vsync         ; čekání na další snímek
        jsr _wait_vsync         ; čekání na další snímek
        tax                     ; obnovení obsahu X z akumulátoru
 
        lda STICK0              ; čtení joysticku
        cmp #11                 ; je nakloněn doleva?
        bne not_left
        dex                     ; posun hráče doleva
not_left:
        cmp #7                  ; je nakloněn doprava?
        bne not_right
        inx                     ; posun hráče doprava
not_right:
        stx HPOSP0              ; změna pozice prvního hráče
        stx x_pos               ; zapamatovat si pozici prvního hráče
        rts
.endproc
 
 
; ---------------------------------------------------------------------
; subrutina pro čekání na konec snímku
; ---------------------------------------------------------------------
.proc   _wait_vsync
        ldx     RTCLOK+2        ; čekání na konec snímku
@wt:    cpx     RTCLOK+2
        beq     @wt
        rts
.endproc
 
 
; data
sprite:   .byte 24, 60, 126, 219, 255, 36, 90, 165
 
; horizontální pozice hráče
x_pos:    .byte 80
 
end:
 
 
.segment "EXEHDR"
.word   $ffff                   ; uvodni sekvence bajtu v souboru XEX
.word   main                    ; zacatek kodoveho segmentu
.word   end - 1                 ; konec kodoveho segmentu
 
 
.segment "AUTOSTRT"             ; segment s pocatecni adresou
.word   RUNAD                   ; naplni se pouze adresy RUNAD a RUNAD+1
.word   RUNAD+1
.word   main                    ; adresa vstupniho bodu do programu
 
; finito

Podprogram pro pohyb hráče joystickem realizovaný ve VBI

Předchozí demonstrační příklad ovšem není v žádném případě dokonalý. Jedním z problémů je fakt, že je změna pozice hráče realizována přímo v hlavní programové smyčce a druhý problém spočívá v nutnosti aktivního čekání na vykreslení snímku. Tím se ovšem zbytečně „pálí“ strojové cykly, kterých pochopitelně mikroprocesor MOS 6502 nemá nekonečné množství. Jedno z možných řešení obou problémů (současně) je přesun kódu pro posun hráče s využitím joysticku přímo do obsluhy VBI. Samotný přesun kódu je snadný; výsledná subrutina vypadá následovně (již neobsahuje volání subrutiny _wait_vsync, tu totiž vůbec nepotřebujeme):

; ---------------------------------------------------------------------
; subrutina pro obsluhu VBI
; ---------------------------------------------------------------------
.proc   horizontal_movement
        ldx x_pos               ; původní pozice prvního hráče
 
        lda STICK0              ; čtení joysticku
        cmp #11                 ; je nakloněn doleva?
        bne not_left
        dex                     ; posun hráče doleva
not_left:
        cmp #7                  ; je nakloněn doprava?
        bne not_right
        inx                     ; posun hráče doprava
not_right:
        stx HPOSP0              ; změna pozice prvního hráče
        stx x_pos               ; zapamatovat si pozici prvního hráče
        jmp XITVBV              ; zpracovat zbytek odloženého VBLANKu
        rts
.endproc
Poznámka: důležitá je předposlední instrukce, která zavolá systémový kód určený pro dokončení obsluhy VBI. Teoreticky je možné toto volání vynechat (například v kritických smyčkách ve hrách a demech), ovšem mnohé operace za nás dělá operační systém zadarmo, takže proč je nevyužít?
Posun spritů je řešen v rámci VBI.

Obrázek 1: Posun spritů je řešen v rámci VBI.

Autor: tisnik, podle licence: Rights Managed

Posun spritů je řešen v rámci VBI (první sprite byl posunut joystickem).

Obrázek 2: Posun spritů je řešen v rámci VBI (první sprite byl posunut joystickem).

Autor: tisnik, podle licence: Rights Managed

Posun spritů je řešen v rámci VBI (první sprite lze posunout až přes okraj obrazovky).

Obrázek 3: Posun spritů je řešen v rámci VBI (první sprite lze posunout až přes okraj obrazovky).

Autor: tisnik, podle licence: Rights Managed

První způsob nastavení vektoru pro VBI

Prozatím jsme vytvořili nový podprogram (subrutinu) nazvanou horizontal_movement. Assembler pochopitelně v pozdější fázi překladu zná počáteční adresu tohoto podprogramu. Jedná se o šestnáctibitovou adresu, kterou je možné s využitím operátorů > a < rozdělit na vyšší a nižší bajt adresy. Tato vlastnost assembleru se nám bude hodit, protože musíme adresu subrutiny horizontal_movement uložit do vektoru VVBLKD, jenž je umístěný na adresách 0×224 a 0×225:

VVBLKD  = $0224         ;DEFERRED VERTICAL BLANK NMI VECTOR

Poněkud naivní (a ne zcela bezpečné) zaregistrování subrutiny horizontal_movement může vypadat takto:

        ; nastavit vektor pro odloženou VBI
        lda #>horizontal_movement
        sta VVBLKD+1
        lda #<horizontal_movement
        sta VVBLKD
Poznámka: proč je tento kód potenciálně nebezpečný? Teoreticky totiž, i když je to velmi málo pravděpodobné, může VBI nastat přesně v okamžiku, kdy jsme modifikovali jen první polovinu adresy. To znamená, že bude proveden skok do odlišného místa paměti a program pravděpodobně zhavaruje nebo se zasekne (záleží na tom, zda dříve narazí na bajt s kódem instrukce RTS či naopak instrukce BRK).

Hlavní herní smyčka se nyní zredukuje do následující triviální podoby, protože ovládání hráče je provedeno v obslužné subrutině VBI:

loop:
        jmp loop                ; program vlastně nice nedělá - jen cyklí!

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

Dnešní druhý demonstrační příklad, ve kterém je pohyb hráče řešen v obsluze VBI, vypadá následovně:

; ---------------------------------------------------------------------
; Ovládání PMG joystickem v horizontálním směru.
; Pohyb PMG realizovaný ve VBI.
;
; ---------------------------------------------------------------------
 
.include "atari.inc"
 
.CODE
 
PLAYER_0_OFFSET = 512
PLAYER_1_OFFSET = PLAYER_0_OFFSET + 128
PLAYER_2_OFFSET = PLAYER_1_OFFSET + 128
PLAYER_3_OFFSET = PLAYER_2_OFFSET + 128
 
 
; ---------------------------------------------------------------------
; vstupní bod do programu
; ---------------------------------------------------------------------
.proc main
        lda #80                 ; horizontální pozice prvního hráče
        sta HPOSP0              ; uložit do řídicího registru HPOSP0 na čipu GTIA
 
        lda #100                ; horizontální pozice druhého hráče
        sta HPOSP1              ; uložit do řídicího registru HPOSP1 na čipu GTIA
 
        lda #120                ; horizontální pozice třetího hráče
        sta HPOSP2              ; uložit do řídicího registru HPOSP2 na čipu GTIA
 
        lda #140                ; horizontální pozice čtvrtého hráče
        sta HPOSP3              ; uložit do řídicího registru HPOSP3 na čipu GTIA
 
        lda #HUE_GREEN<<4 + 12  ; barva prvního hráče (odstín+intenzita)
        sta PCOLR0              ; uložit do řídicího registru PCOLR0 na čipu GTIA
 
        lda #HUE_YELLOW<<4 + 12 ; barva druhého hráče (odstín+intenzita)
        sta PCOLR1              ; uložit do řídicího registru PCOLR1 na čipu GTIA
 
        lda #HUE_MAGENTA<<4 + 12 ; barva třetího hráče (odstín+intenzita)
        sta PCOLR2              ; uložit do řídicího registru PCOLR2 na čipu GTIA
 
        lda #HUE_CYAN<<4 + 12   ; barva čtvrtého hráče (odstín+intenzita)
        sta PCOLR3              ; uložit do řídicího registru PCOLR3 na čipu GTIA
 
        lda #$ff                ; bitová maska všech hráčů
        sta GRAFP0              ; uložit do řídicího registru GRAFP0 na čipu GTIA
        sta GRAFP1              ; uložit do řídicího registru GRAFP1 na čipu GTIA
        sta GRAFP2              ; uložit do řídicího registru GRAFP2 na čipu GTIA
        sta GRAFP3              ; uložit do řídicího registru GRAFP3 na čipu GTIA
 
        lda #3                  ; bitové pole: povolení hráčů i střel
        sta GRACTL              ; uložit do řídicího registru GRACTL na čipu GTIA
 
        lda #0                  ; priorita hráčů a pozadí
        sta GPRIOR              ; uložit do řídicího registru GPRIOR na čipu GTIA
 
        lda #152                ; paměťová stránka číslo 152
        sta PMBASE
 
        addr = 152*256
        ldx #8                  ; začneme na hodnotě o 1 vyšší
next_line:
        lda sprite-1, x         ; načíst
        sta addr+PLAYER_0_OFFSET+50, x  ; uložit byte - první hráč
        sta addr+PLAYER_1_OFFSET+50, x  ; uložit byte - druhý hráč
        sta addr+PLAYER_2_OFFSET+50, x  ; uložit byte - třetí hráč
        sta addr+PLAYER_3_OFFSET+50, x  ; uložit byte - čtvrtý hráč
        dex                     ; snížit offset + nastavit příznaky
        bne next_line           ; další byte spritu
 
        lda #46                 ; povolení PMG DMA
        sta SDMCTL
 
        ; nastavit vektor pro odloženou VBI
        lda #>horizontal_movement
        sta VVBLKD+1
        lda #<horizontal_movement
        sta VVBLKD
loop:
        jmp loop                ; program vlastně nice nedělá - jen cyklí!
.endproc
 
 
; ---------------------------------------------------------------------
; subrutina pro obsluhu VBI
; ---------------------------------------------------------------------
.proc   horizontal_movement
        ldx x_pos               ; původní pozice prvního hráče
 
        lda STICK0              ; čtení joysticku
        cmp #11                 ; je nakloněn doleva?
        bne not_left
        dex                     ; posun hráče doleva
not_left:
        cmp #7                  ; je nakloněn doprava?
        bne not_right
        inx                     ; posun hráče doprava
not_right:
        stx HPOSP0              ; změna pozice prvního hráče
        stx x_pos               ; zapamatovat si pozici prvního hráče
        jmp XITVBV              ; zpracovat zbytek odloženého VBLANKu
        rts
.endproc
 
 
; data
sprite:   .byte 24, 60, 126, 219, 255, 36, 90, 165
 
; horizontální pozice hráče
x_pos:    .byte 80
 
end:
 
 
.segment "EXEHDR"
.word   $ffff                   ; uvodni sekvence bajtu v souboru XEX
.word   main                    ; zacatek kodoveho segmentu
.word   end - 1                 ; konec kodoveho segmentu
 
 
.segment "AUTOSTRT"             ; segment s pocatecni adresou
.word   RUNAD                   ; naplni se pouze adresy RUNAD a RUNAD+1
.word   RUNAD+1
.word   main                    ; adresa vstupniho bodu do programu
 
; finito

Druhý způsob nastavení vektoru pro VBI

Jak jsme si řekli v předchozím textu, nemusí být přímá modifikace adresy uložené do vektoru VVBLKD zcela bezpečná. Vhodnější je využít systémový podprogram (nebo, chcete-li, službu operačního systému) nazvanou SETVBV. Tato služba se zavolá skokem do subrutiny se stejným jménem, ovšem navíc je zapotřebí nastavit pracovní registry mikroprocesoru MOS 6502 následujícím způsobem:

  1. Do akumulátoru A se uloží konstanta 6, pokud měníme subrutinu zavolanou přímo při vzniku VBI (zde je ovšem počet cyklů omezen) nebo hodnotu 7, pokud měníme „odloženou“ obsluhu VBI.
  2. Do index registru X je uložen vyšší bajt adresy obslužné subrutiny.
  3. Do index registru Y je uložen nižší bajt adresy obslužné subrutiny.

To tedy znamená, že nastavení adresy „odložené“ obsluhy VBI může vypadat následovně:

        ; nastavit vektor pro odloženou VBI
        lda #7                  ; změna vektoru pro odložené VBI
        ldx #>horizontal_movement
        ldy #<horizontal_movement
        jsr SETVBV              ; zavolat službu systému pro nastavení vektoru

Hlavní herní smyčka zůstává stále stejná, tj.:

loop:
        jmp loop                ; program vlastně nice nedělá - jen cyklí!
Poznámka: systémová služba SETVBV může posloužit i pro nastavení obsluhy časovačů. Pro tyto účely se akumulátor A musí nastavit na hodnotu od 1 do 5. To však již přesahuje rámec dnešního článku.

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

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

; ---------------------------------------------------------------------
; Ovládání PMG joystickem v horizontálním směru.
; Pohyb PMG realizovaný ve VBI.
; ---------------------------------------------------------------------
 
.include "atari.inc"
 
.CODE
 
PLAYER_0_OFFSET = 512
PLAYER_1_OFFSET = PLAYER_0_OFFSET + 128
PLAYER_2_OFFSET = PLAYER_1_OFFSET + 128
PLAYER_3_OFFSET = PLAYER_2_OFFSET + 128
 
 
; ---------------------------------------------------------------------
; vstupní bod do programu
; ---------------------------------------------------------------------
.proc main
        lda #80                 ; horizontální pozice prvního hráče
        sta HPOSP0              ; uložit do řídicího registru HPOSP0 na čipu GTIA
 
        lda #100                ; horizontální pozice druhého hráče
        sta HPOSP1              ; uložit do řídicího registru HPOSP1 na čipu GTIA
 
        lda #120                ; horizontální pozice třetího hráče
        sta HPOSP2              ; uložit do řídicího registru HPOSP2 na čipu GTIA
 
        lda #140                ; horizontální pozice čtvrtého hráče
        sta HPOSP3              ; uložit do řídicího registru HPOSP3 na čipu GTIA
 
        lda #HUE_GREEN<<4 + 12  ; barva prvního hráče (odstín+intenzita)
        sta PCOLR0              ; uložit do řídicího registru PCOLR0 na čipu GTIA
 
        lda #HUE_YELLOW<<4 + 12 ; barva druhého hráče (odstín+intenzita)
        sta PCOLR1              ; uložit do řídicího registru PCOLR1 na čipu GTIA
 
        lda #HUE_MAGENTA<<4 + 12 ; barva třetího hráče (odstín+intenzita)
        sta PCOLR2              ; uložit do řídicího registru PCOLR2 na čipu GTIA
 
        lda #HUE_CYAN<<4 + 12   ; barva čtvrtého hráče (odstín+intenzita)
        sta PCOLR3              ; uložit do řídicího registru PCOLR3 na čipu GTIA
 
        lda #$ff                ; bitová maska všech hráčů
        sta GRAFP0              ; uložit do řídicího registru GRAFP0 na čipu GTIA
        sta GRAFP1              ; uložit do řídicího registru GRAFP1 na čipu GTIA
        sta GRAFP2              ; uložit do řídicího registru GRAFP2 na čipu GTIA
        sta GRAFP3              ; uložit do řídicího registru GRAFP3 na čipu GTIA
 
        lda #3                  ; bitové pole: povolení hráčů i střel
        sta GRACTL              ; uložit do řídicího registru GRACTL na čipu GTIA
 
        lda #0                  ; priorita hráčů a pozadí
        sta GPRIOR              ; uložit do řídicího registru GPRIOR na čipu GTIA
 
        lda #152                ; paměťová stránka číslo 152
        sta PMBASE
 
        addr = 152*256
        ldx #8                  ; začneme na hodnotě o 1 vyšší
next_line:
        lda sprite-1, x         ; načíst
        sta addr+PLAYER_0_OFFSET+50, x  ; uložit byte - první hráč
        sta addr+PLAYER_1_OFFSET+50, x  ; uložit byte - druhý hráč
        sta addr+PLAYER_2_OFFSET+50, x  ; uložit byte - třetí hráč
        sta addr+PLAYER_3_OFFSET+50, x  ; uložit byte - čtvrtý hráč
        dex                     ; snížit offset + nastavit příznaky
        bne next_line           ; další byte spritu
 
        lda #46                 ; povolení PMG DMA
        sta SDMCTL
 
        ; nastavit vektor pro odloženou VBI
        lda #7                  ; změna vektoru pro odložené VBI
        ldx #>horizontal_movement
        ldy #<horizontal_movement
        jsr SETVBV              ; zavolat službu systému pro nastavení vektoru
loop:
        jmp loop                ; program vlastně nice nedělá - jen cyklí!
.endproc
 
 
; ---------------------------------------------------------------------
; subrutina pro obsluhu VBI
; ---------------------------------------------------------------------
.proc   horizontal_movement
        ldx x_pos               ; původní pozice prvního hráče
 
        lda STICK0              ; čtení joysticku
        cmp #11                 ; je nakloněn doleva?
        bne not_left
        dex                     ; posun hráče doleva
not_left:
        cmp #7                  ; je nakloněn doprava?
        bne not_right
        inx                     ; posun hráče doprava
not_right:
        stx HPOSP0              ; změna pozice prvního hráče
        stx x_pos               ; zapamatovat si pozici prvního hráče
        jmp XITVBV              ; zpracovat zbytek odloženého VBLANKu
        rts
.endproc
 
 
; data
sprite:   .byte 24, 60, 126, 219, 255, 36, 90, 165
 
; horizontální pozice hráče
x_pos:    .byte 80
 
end:
 
 
.segment "EXEHDR"
.word   $ffff                   ; uvodni sekvence bajtu v souboru XEX
.word   main                    ; zacatek kodoveho segmentu
.word   end - 1                 ; konec kodoveho segmentu
 
 
.segment "AUTOSTRT"             ; segment s pocatecni adresou
.word   RUNAD                   ; naplni se pouze adresy RUNAD a RUNAD+1
.word   RUNAD+1
.word   main                    ; adresa vstupniho bodu do programu
 
; finito

Kombinace DLI a VBI v jednom programu

V předchozím článku jsme si popsali způsob nastavení DLI v display listu i to, jak může vypadat subrutina, která DLI obslouží. A dnes jsme se zabývali naprogramováním subrutiny zavolané při VBI, tj. při dokončení vykreslení snímku. Nabízí se tedy pochopitelná otázka – je možné DLI a VBI zkombinovat v jednom programu? Samozřejmě to možné je a právě tento způsob je využit v mnoha hrách pro osmibitové mikropočítače Atari. Pouze si musíme uvědomit, že subrutiny pro obsluhu DLI (pochopitelně) vyžadují určitý počet strojových cyklů MOS 6502. A tyto cykly potom budou chybět pro odložené VBI.

Připomeňme si, že zatímco VBI je po resetu Atari povoleno (resp. se o to postará operační systém), je nutné DLI povolit explicitně, například takto:

        ; povolení DLI
        NMIEN_DLI=$80           ; maska povolení DLI
        NMIEN_VBI=$40           ; maska povolení VBI
        lda #NMIEN_DLI | NMIEN_VBI ; povolení DLI
        sta NMIEN

Poté již můžeme nastavit oba vektory obsahující adresy pro obsluhu DLI a VBI:

        ; vektor DLI
        lda #<dli               ; nastavení DLI
        sta VDSLST
        lda #>dli
        sta VDSLST+1
 
        ; -------------------------------------------------
 
        ; nastavit vektor pro odloženou VBI
        lda #7                  ; změna vektoru pro odložené VBI
        ldx #>horizontal_movement
        ldy #<horizontal_movement
        jsr SETVBV              ; zavolat službu systému pro nastavení vektoru

Obslužná subrutina pro DLI končí takto:

        rti                     ; návrat z DLI

Zatímco obslužná rutina pro odložené VBI bude končit:

        jmp XITVBV              ; zpracovat zbytek odloženého VBLANKu
Posun spritů je řešen v rámci VBI, změna barev pozadí pomocí DLI.

Obrázek 4: Posun spritů je řešen v rámci VBI, změna barev pozadí pomocí DLI.

Autor: tisnik, podle licence: Rights Managed

Posun spritů je řešen v rámci VBI, změna barev pozadí pomocí DLI (posun prvního spritu joystickem).

Obrázek 5: Posun spritů je řešen v rámci VBI, změna barev pozadí pomocí DLI (posun prvního spritu joystickem).

Autor: tisnik, podle licence: Rights Managed

Posun spritů je řešen v rámci VBI, změna barev pozadí pomocí DLI (posun prvního spritu joystickem až na okraj obrazovky).

Obrázek 6: Posun spritů je řešen v rámci VBI, změna barev pozadí pomocí DLI (posun prvního spritu joystickem až na okraj obrazovky).

Autor: tisnik, podle licence: Rights Managed

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

Oba podprogramy, z nichž jeden je vyvolán při každém DLI a druhý při VBI, byly zakomponovány do jediného programu, jehož úplný zdrojový kód vypadá následovně:

; ---------------------------------------------------------------------
; Ovládání PMG joystickem v horizontálním směru.
; Změna pozice PMG realizovaná ve VBI.
; Změna barvy herního pole realizovaná v DLI.
; ---------------------------------------------------------------------
 
.include "atari.inc"
 
.CODE
 
PLAYER_0_OFFSET = 512
PLAYER_1_OFFSET = PLAYER_0_OFFSET + 128
PLAYER_2_OFFSET = PLAYER_1_OFFSET + 128
PLAYER_3_OFFSET = PLAYER_2_OFFSET + 128
 
 
; ---------------------------------------------------------------------
; vstupní bod do programu
; ---------------------------------------------------------------------
.proc main
        lda #<dlist             ; nižší byte adresy display listu
        sta SDLSTL
        lda #>dlist             ; vyšší byte adresy display listu
        sta SDLSTH
 
        ldy #0                  ; počitadlo zápisů
clear:
        tya                     ; kód vypisovaného znaku
        sta screen, y           ; tisk znaku na zvolené místo na obrazovce
        sta screen+40*8, y
        sta screen+40*16, y
        iny                     ; zvětšit hodnotu počitadla a offsetu
        cpy #$80
        bne clear               ; skok
 
        ; vektor DLI
        lda #<dli               ; nastavení DLI
        sta VDSLST
        lda #>dli
        sta VDSLST+1
 
        lda #80                 ; horizontální pozice prvního hráče
        sta HPOSP0              ; uložit do řídicího registru HPOSP0 na čipu GTIA
 
        lda #100                ; horizontální pozice druhého hráče
        sta HPOSP1              ; uložit do řídicího registru HPOSP1 na čipu GTIA
 
        lda #120                ; horizontální pozice třetího hráče
        sta HPOSP2              ; uložit do řídicího registru HPOSP2 na čipu GTIA
 
        lda #140                ; horizontální pozice čtvrtého hráče
        sta HPOSP3              ; uložit do řídicího registru HPOSP3 na čipu GTIA
 
        lda #HUE_GREEN<<4 + 12  ; barva prvního hráče (odstín+intenzita)
        sta PCOLR0              ; uložit do řídicího registru PCOLR0 na čipu GTIA
 
        lda #HUE_YELLOW<<4 + 12 ; barva druhého hráče (odstín+intenzita)
        sta PCOLR1              ; uložit do řídicího registru PCOLR1 na čipu GTIA
 
        lda #HUE_MAGENTA<<4 + 12 ; barva třetího hráče (odstín+intenzita)
        sta PCOLR2              ; uložit do řídicího registru PCOLR2 na čipu GTIA
 
        lda #HUE_CYAN<<4 + 12   ; barva čtvrtého hráče (odstín+intenzita)
        sta PCOLR3              ; uložit do řídicího registru PCOLR3 na čipu GTIA
 
        lda #$ff                ; bitová maska všech hráčů
        sta GRAFP0              ; uložit do řídicího registru GRAFP0 na čipu GTIA
        sta GRAFP1              ; uložit do řídicího registru GRAFP1 na čipu GTIA
        sta GRAFP2              ; uložit do řídicího registru GRAFP2 na čipu GTIA
        sta GRAFP3              ; uložit do řídicího registru GRAFP3 na čipu GTIA
 
        lda #3                  ; bitové pole: povolení hráčů i střel
        sta GRACTL              ; uložit do řídicího registru GRACTL na čipu GTIA
 
        lda #1                   ; priorita hráčů a pozadí
        sta GPRIOR              ; uložit do řídicího registru GPRIOR na čipu GTIA
 
        lda #152                ; paměťová stránka číslo 152
        sta PMBASE
 
        addr = 152*256
        ldx #8                  ; začneme na hodnotě o 1 vyšší
next_line:
        lda sprite-1, x         ; načíst
        sta addr+PLAYER_0_OFFSET+100, x  ; uložit byte - první hráč
        sta addr+PLAYER_1_OFFSET+100, x  ; uložit byte - druhý hráč
        sta addr+PLAYER_2_OFFSET+100, x  ; uložit byte - třetí hráč
        sta addr+PLAYER_3_OFFSET+100, x  ; uložit byte - čtvrtý hráč
        dex                     ; snížit offset + nastavit příznaky
        bne next_line           ; další byte spritu
 
        lda #46                 ; povolení PMG DMA
        sta SDMCTL
 
        ; nastavit vektor pro odloženou VBI
        lda #7                  ; změna vektoru pro odložené VBI
        ldx #>horizontal_movement
        ldy #<horizontal_movement
        jsr SETVBV              ; zavolat službu systému pro nastavení vektoru
 
        ; povolení DLI
        NMIEN_DLI=$80           ; maska povolení DLI
        NMIEN_VBI=$40           ; maska povolení VBI
        lda #NMIEN_DLI | NMIEN_VBI ; povolení DLI
        sta NMIEN
 
loop:
        jmp loop                ; program vlastně nice nedělá - jen cyklí!
.endproc
 
 
; ---------------------------------------------------------------------
; subrutina pro obsluhu VBI
; ---------------------------------------------------------------------
.proc   horizontal_movement
        ldx x_pos               ; původní pozice prvního hráče
 
        lda STICK0              ; čtení joysticku
        cmp #11                 ; je nakloněn doleva?
        bne not_left
        dex                     ; posun hráče doleva
not_left:
        cmp #7                  ; je nakloněn doprava?
        bne not_right
        inx                     ; posun hráče doprava
not_right:
        stx HPOSP0              ; změna pozice prvního hráče
        stx x_pos               ; zapamatovat si pozici prvního hráče
        jmp XITVBV              ; zpracovat zbytek odloženého VBLANKu
        rts
.endproc
 
 
; ---------------------------------------------------------------------
; obsluha DLI
; ---------------------------------------------------------------------
dli:
        pha                     ; uschovat akumulátor
        lda color               ; barva pozadí
        sta COLPF2              ; přímo nastavit zápisem do HW registru
        eor #%10000000          ; negovat nejvyšší bit
        sta color
        pla                     ; obnovit akumulátor
        rti                     ; návrat z DLI
 
 
dlist:
.byte DL_BLK8, DL_BLK8, DL_BLK8 ; 3x8=24 prázdných obrazových řádků
.byte DL_LMS+DL_CHR40x8x1       ; určení počáteční adresy obrazové paměti + jeden řádek režimu 2 (GR.0)
.byte <screen, >screen          ; počáteční adresa obrazové paměti 
.res 6, DL_CHR40x8x1            ; opakovat řádky textového režimu 2 (GR.0)
.byte DL_DLI+DL_CHR40x8x1       ; GR.0 ovšem navíc s povolením DLI
.res 7, DL_CHR40x8x1            ; opakovat řádky textového režimu 2 (GR.0)
.byte DL_DLI+DL_CHR40x8x1       ; GR.0 ovšem navíc s povolením DLI
.res 8, DL_CHR40x8x1            ; opakovat řádky textového režimu 2 (GR.0)
.byte DL_JVB, <dlist, >dlist    ; skok na začátek display listu
 
 
color:
.byte $c4                       ; původní barva
 
 
; data
sprite:   .byte 24, 60, 126, 219, 255, 36, 90, 165
 
; horizontální pozice hráče
x_pos:    .byte 80
 
end:
 
 
.BSS
screen: .res 40*24
 
.segment "EXEHDR"
.word   $ffff                   ; uvodni sekvence bajtu v souboru XEX
.word   main                    ; zacatek kodoveho segmentu
.word   end - 1                 ; konec kodoveho segmentu
 
 
.segment "AUTOSTRT"             ; segment s pocatecni adresou
.word   RUNAD                   ; naplni se pouze adresy RUNAD a RUNAD+1
.word   RUNAD+1
.word   main                    ; adresa vstupniho bodu do programu
 
; finito

Odstranění nadbytečné instrukce RTS na konci obsluhy VBI

Ještě jednou se vraťme k podprogramu horizontal_movement, který se volá v rámci obsluhy VBI:

; ---------------------------------------------------------------------
; subrutina pro obsluhu VBI
; ---------------------------------------------------------------------
.proc   horizontal_movement
        ldx x_pos               ; původní pozice prvního hráče

        lda STICK0              ; čtení joysticku
        cmp #11                 ; je nakloněn doleva?
        bne not_left
        dex                     ; posun hráče doleva
not_left:
        cmp #7                  ; je nakloněn doprava?
        bne not_right
        inx                     ; posun hráče doprava
not_right:
        stx HPOSP0              ; změna pozice prvního hráče
        stx x_pos               ; zapamatovat si pozici prvního hráče
        jmp XITVBV              ; zpracovat zbytek odloženého VBLANKu
        rts
.endproc

Zajímavé jsou poslední dvě instrukce:

        jmp XITVBV              ; zpracovat zbytek odloženého VBLANKu
        rts

První instrukce provede přímý skok na adresu XITVBV, druhá provádí návrat z podprogramu. Ovšem to je zajímavé – jak se vlastně procesor dozví, že se má nejdříve vrátit za volání XITVBV, aby mohl rts vykonat? Odpovědí je, že se do tohoto místa programu řízení nevrátí, protože XITVBV samo končí instrukcí rts nebo rti. Tudíž je „naše“ rts nadbytečná a můžeme ji odstranit:

; ---------------------------------------------------------------------
; subrutina pro obsluhu VBI
; ---------------------------------------------------------------------
.proc   horizontal_movement
        ldx x_pos               ; původní pozice prvního hráče

        lda STICK0              ; čtení joysticku
        cmp #11                 ; je nakloněn doleva?
        bne not_left
        dex                     ; posun hráče doleva
not_left:
        cmp #7                  ; je nakloněn doprava?
        bne not_right
        inx                     ; posun hráče doprava
not_right:
        stx HPOSP0              ; změna pozice prvního hráče
        stx x_pos               ; zapamatovat si pozici prvního hráče
        jmp XITVBV              ; zpracovat zbytek odloženého VBLANKu
.endproc

Úplný zdrojový kód pátého demonstračního příkladu

Dnešní pátý demonstrační příklad se příliš neliší od příkladu čtvrtého, pouze v něm došlo k odstranění nadbytečné instrukce rts. Pro úplnost si ale ukážeme i takto upravený zdrojový kód:

; ---------------------------------------------------------------------
; Ovládání PMG joystickem v horizontálním směru.
; Změna pozice PMG realizovaná ve VBI.
; Změna barvy herního pole realizovaná v DLI.
; Odstranění nadbytečné instrukce RTS ve VBI.
;
; ---------------------------------------------------------------------
 
.include "atari.inc"
 
.CODE
 
PLAYER_0_OFFSET = 512
PLAYER_1_OFFSET = PLAYER_0_OFFSET + 128
PLAYER_2_OFFSET = PLAYER_1_OFFSET + 128
PLAYER_3_OFFSET = PLAYER_2_OFFSET + 128
 
 
; ---------------------------------------------------------------------
; vstupní bod do programu
; ---------------------------------------------------------------------
.proc main
        lda #<dlist             ; nižší byte adresy display listu
        sta SDLSTL
        lda #>dlist             ; vyšší byte adresy display listu
        sta SDLSTH
 
        ldy #0                  ; počitadlo zápisů
clear:
        tya                     ; kód vypisovaného znaku
        sta screen, y           ; tisk znaku na zvolené místo na obrazovce
        sta screen+40*8, y
        sta screen+40*16, y
        iny                     ; zvětšit hodnotu počitadla a offsetu
        cpy #$80
        bne clear               ; skok
 
        ; vektor DLI
        lda #<dli               ; nastavení DLI
        sta VDSLST
        lda #>dli
        sta VDSLST+1
 
        lda #80                 ; horizontální pozice prvního hráče
        sta HPOSP0              ; uložit do řídicího registru HPOSP0 na čipu GTIA
 
        lda #100                ; horizontální pozice druhého hráče
        sta HPOSP1              ; uložit do řídicího registru HPOSP1 na čipu GTIA
 
        lda #120                ; horizontální pozice třetího hráče
        sta HPOSP2              ; uložit do řídicího registru HPOSP2 na čipu GTIA
 
        lda #140                ; horizontální pozice čtvrtého hráče
        sta HPOSP3              ; uložit do řídicího registru HPOSP3 na čipu GTIA
 
        lda #HUE_GREEN<<4 + 12  ; barva prvního hráče (odstín+intenzita)
        sta PCOLR0              ; uložit do řídicího registru PCOLR0 na čipu GTIA
 
        lda #HUE_YELLOW<<4 + 12 ; barva druhého hráče (odstín+intenzita)
        sta PCOLR1              ; uložit do řídicího registru PCOLR1 na čipu GTIA
 
        lda #HUE_MAGENTA<<4 + 12 ; barva třetího hráče (odstín+intenzita)
        sta PCOLR2              ; uložit do řídicího registru PCOLR2 na čipu GTIA
 
        lda #HUE_CYAN<<4 + 12   ; barva čtvrtého hráče (odstín+intenzita)
        sta PCOLR3              ; uložit do řídicího registru PCOLR3 na čipu GTIA
 
        lda #$ff                ; bitová maska všech hráčů
        sta GRAFP0              ; uložit do řídicího registru GRAFP0 na čipu GTIA
        sta GRAFP1              ; uložit do řídicího registru GRAFP1 na čipu GTIA
        sta GRAFP2              ; uložit do řídicího registru GRAFP2 na čipu GTIA
        sta GRAFP3              ; uložit do řídicího registru GRAFP3 na čipu GTIA
 
        lda #3                  ; bitové pole: povolení hráčů i střel
        sta GRACTL              ; uložit do řídicího registru GRACTL na čipu GTIA
 
        lda #1                   ; priorita hráčů a pozadí
        sta GPRIOR              ; uložit do řídicího registru GPRIOR na čipu GTIA
 
        lda #152                ; paměťová stránka číslo 152
        sta PMBASE
 
        addr = 152*256
        ldx #8                  ; začneme na hodnotě o 1 vyšší
next_line:
        lda sprite-1, x         ; načíst
        sta addr+PLAYER_0_OFFSET+100, x  ; uložit byte - první hráč
        sta addr+PLAYER_1_OFFSET+100, x  ; uložit byte - druhý hráč
        sta addr+PLAYER_2_OFFSET+100, x  ; uložit byte - třetí hráč
        sta addr+PLAYER_3_OFFSET+100, x  ; uložit byte - čtvrtý hráč
        dex                     ; snížit offset + nastavit příznaky
        bne next_line           ; další byte spritu
 
        lda #46                 ; povolení PMG DMA
        sta SDMCTL
 
        ; nastavit vektor pro odloženou VBI
        lda #7                  ; změna vektoru pro odložené VBI
        ldx #>horizontal_movement
        ldy #<horizontal_movement
        jsr SETVBV              ; zavolat službu systému pro nastavení vektoru
 
        ; povolení DLI
        NMIEN_DLI=$80           ; maska povolení DLI
        NMIEN_VBI=$40           ; maska povolení VBI
        lda #NMIEN_DLI | NMIEN_VBI ; povolení DLI
        sta NMIEN
 
loop:
        jmp loop                ; program vlastně nice nedělá - jen cyklí!
.endproc
 
 
; ---------------------------------------------------------------------
; subrutina pro obsluhu VBI
; ---------------------------------------------------------------------
.proc   horizontal_movement
        ldx x_pos               ; původní pozice prvního hráče
 
        lda STICK0              ; čtení joysticku
        cmp #11                 ; je nakloněn doleva?
        bne not_left
        dex                     ; posun hráče doleva
not_left:
        cmp #7                  ; je nakloněn doprava?
        bne not_right
        inx                     ; posun hráče doprava
not_right:
        stx HPOSP0              ; změna pozice prvního hráče
        stx x_pos               ; zapamatovat si pozici prvního hráče
        jmp XITVBV              ; zpracovat zbytek odloženého VBLANKu
.endproc
 
 
; ---------------------------------------------------------------------
; obsluha DLI
; ---------------------------------------------------------------------
dli:
        pha                     ; uschovat akumulátor
        lda color               ; barva pozadí
        sta COLPF2              ; přímo nastavit zápisem do HW registru
        eor #%10000000          ; negovat nejvyšší bit
        sta color
        pla                     ; obnovit akumulátor
        rti                     ; návrat z DLI
 
 
dlist:
.byte DL_BLK8, DL_BLK8, DL_BLK8 ; 3x8=24 prázdných obrazových řádků
.byte DL_LMS+DL_CHR40x8x1       ; určení počáteční adresy obrazové paměti + jeden řádek režimu 2 (GR.0)
.byte <screen, >screen          ; počáteční adresa obrazové paměti 
.res 6, DL_CHR40x8x1            ; opakovat řádky textového režimu 2 (GR.0)
.byte DL_DLI+DL_CHR40x8x1       ; GR.0 ovšem navíc s povolením DLI
.res 7, DL_CHR40x8x1            ; opakovat řádky textového režimu 2 (GR.0)
.byte DL_DLI+DL_CHR40x8x1       ; GR.0 ovšem navíc s povolením DLI
.res 8, DL_CHR40x8x1            ; opakovat řádky textového režimu 2 (GR.0)
.byte DL_JVB, <dlist, >dlist    ; skok na začátek display listu
 
 
color:
.byte $c4                       ; původní barva
 
 
; data
sprite:   .byte 24, 60, 126, 219, 255, 36, 90, 165
 
; horizontální pozice hráče
x_pos:    .byte 80
 
end:
 
 
.BSS
screen: .res 40*24
 
.segment "EXEHDR"
.word   $ffff                   ; uvodni sekvence bajtu v souboru XEX
.word   main                    ; zacatek kodoveho segmentu
.word   end - 1                 ; konec kodoveho segmentu
 
 
.segment "AUTOSTRT"             ; segment s pocatecni adresou
.word   RUNAD                   ; naplni se pouze adresy RUNAD a RUNAD+1
.word   RUNAD+1
.word   main                    ; adresa vstupniho bodu do programu
 
; finito

Refaktoring kódu v assembleru: subrutiny a makra

Již ve druhém článku o programování pro osmibitová Atari jsme si řekli, že programy psané v assembleru jsou psány na relativně nízké úrovni abstrakce. Proto je prakticky nutné, alespoň u rozsáhlejších aplikací, nějakým způsobem neustále provádět jejich refaktoring, protože v opačném případě bychom získali „špagetový kód“ skládající se z nic neříkajících instrukcí. Assemblery a do jisté míry i samotné mikroprocesory nám nabízí dvě základní techniky, které je možné využít a různým způsobem je kombinovat. Jedná se o rozdělení úlohy na jednotlivé podprogramy (subrutiny), ideálně s rozumně nastaveným rozhraním, které specifikuje, jakým způsobem se mají do subrutin předávat parametry. A druhou technologií jsou makra, kterými jsme se zabývali ve třetím článku. Ovšem již samotné rozdělení programu na podprogramy může zvětšit čitelnost a vlastně se dostat na vyšší úroveň abstrakce (o programu budeme uvažovat jako o vzájemně se volajících blocích, nikoli jako o sekvenci instrukcí).

Program, který využívá jak DL a PMG, tak i DLI a VBI (to je zkratek), je již relativně komplikovaný, takže se může vyplatit jeho refaktoring. Oba způsoby, tedy rozdělení na podprogramy popř. do maker, si ukážeme v navazujících kapitolách.

Poznámka: ukážeme se tedy všechny tři extrémy – špagetový kód (to jsme již viděli), vše rozdělené čistě do podprogramů a naopak vše realizované formou maker. V praxi se ovšem vyplatí rozumná kombinace obou dvou „struturovaných“ přístupů (tedy s vyloučením špagetového kódu).

Přepis všech částí programu do formy podprogramů (subrutin)

Přepis programu do formy s podprogramy může vypadat jednoduše. Hlavní část je dobře čitelná, ovšem jak uvidíme dále, ve skutečnosti není příliš obecná. Nalezneme zde pouze volání podprogramů realizované instrukcí JSR (Jump to SubRoutine):

; ---------------------------------------------------------------------
; vstupní bod do programu
; ---------------------------------------------------------------------
.proc main
        jsr set_display_list    ; nastavení display listu
        jsr fill_screen         ; výpis znaků na obrazovku
        jsr setup_sprites
        jsr set_dli_handler     ; nastavení obsluhy DLI
        jsr set_vbi_handler     ; nastavení obsluhy VBI
        jsr enable_interrupts
loop:
        jmp loop                ; program vlastně nice nedělá - jen cyklí!

Další části programu jsou realizovány subrutinami a tedy končí instrukcí RTS (ReTurn from Subroutine). Nevýhodou je, že se sice jedná o subrutiny, ale ty pracují s (de facto) globálními symboly screen, dlist a x_pos (a také s adresami obslužných programů pro DLI a VBI):

; ---------------------------------------------------------------------
; subrutina pro vyplnění obrazovky znaky
; ---------------------------------------------------------------------
.proc   fill_screen
        ldy #0                  ; počitadlo zápisů
clear:
        tya                     ; kód vypisovaného znaku
        sta screen, y           ; tisk znaku na zvolené místo na obrazovce
        sta screen+40*8, y
        sta screen+40*16, y
        iny                     ; zvětšit hodnotu počitadla a offsetu
        cpy #$80
        bne clear               ; skok
        rts
.endproc
; ---------------------------------------------------------------------
; subrutina pro nastavení display listu
; ---------------------------------------------------------------------
.proc   set_display_list
        lda #<dlist             ; nižší byte adresy display listu
        sta SDLSTL
        lda #>dlist             ; vyšší byte adresy display listu
        sta SDLSTH
        rts
.endproc
; ---------------------------------------------------------------------
; subrutina pro nastavení všech spritů
; ---------------------------------------------------------------------
.proc   setup_sprites
        lda #80                 ; horizontální pozice prvního hráče
        sta HPOSP0              ; uložit do řídicího registru HPOSP0 na čipu GTIA
 
        lda #100                ; horizontální pozice druhého hráče
        sta HPOSP1              ; uložit do řídicího registru HPOSP1 na čipu GTIA
 
        lda #120                ; horizontální pozice třetího hráče
        sta HPOSP2              ; uložit do řídicího registru HPOSP2 na čipu GTIA
 
        lda #140                ; horizontální pozice čtvrtého hráče
        sta HPOSP3              ; uložit do řídicího registru HPOSP3 na čipu GTIA
 
        lda #HUE_GREEN<<4 + 12  ; barva prvního hráče (odstín+intenzita)
        sta PCOLR0              ; uložit do řídicího registru PCOLR0 na čipu GTIA
 
        lda #HUE_YELLOW<<4 + 12 ; barva druhého hráče (odstín+intenzita)
        sta PCOLR1              ; uložit do řídicího registru PCOLR1 na čipu GTIA
 
        lda #HUE_MAGENTA<<4 + 12 ; barva třetího hráče (odstín+intenzita)
        sta PCOLR2              ; uložit do řídicího registru PCOLR2 na čipu GTIA
 
        lda #HUE_CYAN<<4 + 12   ; barva čtvrtého hráče (odstín+intenzita)
        sta PCOLR3              ; uložit do řídicího registru PCOLR3 na čipu GTIA
 
        lda #$ff                ; bitová maska všech hráčů
        sta GRAFP0              ; uložit do řídicího registru GRAFP0 na čipu GTIA
        sta GRAFP1              ; uložit do řídicího registru GRAFP1 na čipu GTIA
        sta GRAFP2              ; uložit do řídicího registru GRAFP2 na čipu GTIA
        sta GRAFP3              ; uložit do řídicího registru GRAFP3 na čipu GTIA
 
        lda #3                  ; bitové pole: povolení hráčů i střel
        sta GRACTL              ; uložit do řídicího registru GRACTL na čipu GTIA
 
        lda #1                   ; priorita hráčů a pozadí
        sta GPRIOR              ; uložit do řídicího registru GPRIOR na čipu GTIA
 
        lda #152                ; paměťová stránka číslo 152
        sta PMBASE
 
        addr = 152*256
        ldx #8                  ; začneme na hodnotě o 1 vyšší
next_line:
        lda sprite-1, x         ; načíst
        sta addr+PLAYER_0_OFFSET+100, x  ; uložit byte - první hráč
        sta addr+PLAYER_1_OFFSET+100, x  ; uložit byte - druhý hráč
        sta addr+PLAYER_2_OFFSET+100, x  ; uložit byte - třetí hráč
        sta addr+PLAYER_3_OFFSET+100, x  ; uložit byte - čtvrtý hráč
        dex                     ; snížit offset + nastavit příznaky
        bne next_line           ; další byte spritu
 
        lda #46                 ; povolení PMG DMA
        sta SDMCTL
        rts
.endproc
; ---------------------------------------------------------------------
; subrutina pro povolení DLI i VBI
; ---------------------------------------------------------------------
.proc   enable_interrupts
        NMIEN_DLI=$80           ; maska povolení DLI
        NMIEN_VBI=$40           ; maska povolení VBI
        lda #NMIEN_DLI | NMIEN_VBI ; povolení DLI
        sta NMIEN
        rts
.endproc
; ---------------------------------------------------------------------
; subrutina pro nastavení obsluhy VBI
; ---------------------------------------------------------------------
.proc   set_vbi_handler
        ; nastavit vektor pro odloženou VBI
        lda #7                  ; změna vektoru pro odložené VBI
        ldx #>horizontal_movement
        ldy #<horizontal_movement
        jsr SETVBV              ; zavolat službu systému pro nastavení vektoru
        rts
.endproc
; ---------------------------------------------------------------------
; subrutina pro obsluhu VBI
; ---------------------------------------------------------------------
.proc   horizontal_movement
        ldx x_pos               ; původní pozice prvního hráče
 
        lda STICK0              ; čtení joysticku
        cmp #11                 ; je nakloněn doleva?
        bne not_left
        dex                     ; posun hráče doleva
not_left:
        cmp #7                  ; je nakloněn doprava?
        bne not_right
        inx                     ; posun hráče doprava
not_right:
        stx HPOSP0              ; změna pozice prvního hráče
        stx x_pos               ; zapamatovat si pozici prvního hráče
        jmp XITVBV              ; zpracovat zbytek odloženého VBLANKu
        rts
.endproc
; ---------------------------------------------------------------------
; obsluha DLI
; ---------------------------------------------------------------------
dli:
        pha                     ; uschovat akumulátor
        lda color               ; barva pozadí
        sta COLPF2              ; přímo nastavit zápisem do HW registru
        eor #%10000000          ; negovat nejvyšší bit
        sta color
        pla                     ; obnovit akumulátor
        rti                     ; návrat z DLI

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

Po překladu došlo k nárůstu délky programu, protože bylo nutné zakódovat všechny nové instrukce JSR a RTS. Původní délka:

Segment list:
-------------
Name                   Start     End    Size  Align
----------------------------------------------------
AUTOSTRT              000000  000005  000006  00001
EXEHDR                000000  000005  000006  00001
CODE                  002000  0020E4  0000E5  00001
BSS                   002400  0027BF  0003C0  00001

Nová délka téměř dosahuje velikosti jedné stránky paměti, tj. celých 1/256 adresovací kapacity mikroprocesoru:

Segment list:
-------------
Name                   Start     End    Size  Align
----------------------------------------------------
AUTOSTRT              000000  000005  000006  00001
EXEHDR                000000  000005  000006  00001
CODE                  002000  0020FD  0000FE  00001
BSS                   002400  0027BF  0003C0  00001

A výsledný zdrojový kód? Ten vypadá takto:

; ---------------------------------------------------------------------
; Ovládání PMG joystickem v horizontálním směru.
;
; ---------------------------------------------------------------------
 
.include "atari.inc"
 
.CODE
 
PLAYER_0_OFFSET = 512
PLAYER_1_OFFSET = PLAYER_0_OFFSET + 128
PLAYER_2_OFFSET = PLAYER_1_OFFSET + 128
PLAYER_3_OFFSET = PLAYER_2_OFFSET + 128
 
 
; ---------------------------------------------------------------------
; vstupní bod do programu
; ---------------------------------------------------------------------
.proc main
        jsr set_display_list    ; nastavení display listu
        jsr fill_screen         ; výpis znaků na obrazovku
        jsr setup_sprites
        jsr set_dli_handler     ; nastavení obsluhy DLI
        jsr set_vbi_handler     ; nastavení obsluhy VBI
        jsr enable_interrupts
 
loop:
        jmp loop                ; program vlastně nice nedělá - jen cyklí!
.endproc
 
 
; ---------------------------------------------------------------------
; subrutina pro vyplnění obrazovky znaky
; ---------------------------------------------------------------------
.proc   fill_screen
        ldy #0                  ; počitadlo zápisů
clear:
        tya                     ; kód vypisovaného znaku
        sta screen, y           ; tisk znaku na zvolené místo na obrazovce
        sta screen+40*8, y
        sta screen+40*16, y
        iny                     ; zvětšit hodnotu počitadla a offsetu
        cpy #$80
        bne clear               ; skok
        rts
.endproc
 
 
; ---------------------------------------------------------------------
; subrutina pro nastavení display listu
; ---------------------------------------------------------------------
.proc   set_display_list
        lda #<dlist             ; nižší byte adresy display listu
        sta SDLSTL
        lda #>dlist             ; vyšší byte adresy display listu
        sta SDLSTH
        rts
.endproc
 
 
; ---------------------------------------------------------------------
; subrutina pro nastavení všech spritů
; ---------------------------------------------------------------------
.proc   setup_sprites
        lda #80                 ; horizontální pozice prvního hráče
        sta HPOSP0              ; uložit do řídicího registru HPOSP0 na čipu GTIA
 
        lda #100                ; horizontální pozice druhého hráče
        sta HPOSP1              ; uložit do řídicího registru HPOSP1 na čipu GTIA
 
        lda #120                ; horizontální pozice třetího hráče
        sta HPOSP2              ; uložit do řídicího registru HPOSP2 na čipu GTIA
 
        lda #140                ; horizontální pozice čtvrtého hráče
        sta HPOSP3              ; uložit do řídicího registru HPOSP3 na čipu GTIA
 
        lda #HUE_GREEN<<4 + 12  ; barva prvního hráče (odstín+intenzita)
        sta PCOLR0              ; uložit do řídicího registru PCOLR0 na čipu GTIA
 
        lda #HUE_YELLOW<<4 + 12 ; barva druhého hráče (odstín+intenzita)
        sta PCOLR1              ; uložit do řídicího registru PCOLR1 na čipu GTIA
 
        lda #HUE_MAGENTA<<4 + 12 ; barva třetího hráče (odstín+intenzita)
        sta PCOLR2              ; uložit do řídicího registru PCOLR2 na čipu GTIA
 
        lda #HUE_CYAN<<4 + 12   ; barva čtvrtého hráče (odstín+intenzita)
        sta PCOLR3              ; uložit do řídicího registru PCOLR3 na čipu GTIA
 
        lda #$ff                ; bitová maska všech hráčů
        sta GRAFP0              ; uložit do řídicího registru GRAFP0 na čipu GTIA
        sta GRAFP1              ; uložit do řídicího registru GRAFP1 na čipu GTIA
        sta GRAFP2              ; uložit do řídicího registru GRAFP2 na čipu GTIA
        sta GRAFP3              ; uložit do řídicího registru GRAFP3 na čipu GTIA
 
        lda #3                  ; bitové pole: povolení hráčů i střel
        sta GRACTL              ; uložit do řídicího registru GRACTL na čipu GTIA
 
        lda #1                   ; priorita hráčů a pozadí
        sta GPRIOR              ; uložit do řídicího registru GPRIOR na čipu GTIA
 
        lda #152                ; paměťová stránka číslo 152
        sta PMBASE
 
        addr = 152*256
        ldx #8                  ; začneme na hodnotě o 1 vyšší
next_line:
        lda sprite-1, x         ; načíst
        sta addr+PLAYER_0_OFFSET+100, x  ; uložit byte - první hráč
        sta addr+PLAYER_1_OFFSET+100, x  ; uložit byte - druhý hráč
        sta addr+PLAYER_2_OFFSET+100, x  ; uložit byte - třetí hráč
        sta addr+PLAYER_3_OFFSET+100, x  ; uložit byte - čtvrtý hráč
        dex                     ; snížit offset + nastavit příznaky
        bne next_line           ; další byte spritu
 
        lda #46                 ; povolení PMG DMA
        sta SDMCTL
        rts
.endproc
 
 
; ---------------------------------------------------------------------
; subrutina pro nastavení DLI i VBI
; ---------------------------------------------------------------------
.proc   enable_interrupts
        NMIEN_DLI=$80           ; maska povolení DLI
        NMIEN_VBI=$40           ; maska povolení VBI
        lda #NMIEN_DLI | NMIEN_VBI ; povolení DLI
        sta NMIEN
        rts
.endproc
 
 
; ---------------------------------------------------------------------
; subrutina pro povolení VBI
; ---------------------------------------------------------------------
.proc   set_vbi_handler
        ; nastavit vektor pro odloženou VBI
        lda #7                  ; změna vektoru pro odložené VBI
        ldx #>horizontal_movement
        ldy #<horizontal_movement
        jsr SETVBV              ; zavolat službu systému pro nastavení vektoru
        rts
.endproc
 
 
; ---------------------------------------------------------------------
; subrutina pro nastavení obsluhy DLI
; ---------------------------------------------------------------------
.proc   set_dli_handler
        ; vektor DLI
        lda #<dli               ; nastavení DLI
        sta VDSLST
        lda #>dli
        sta VDSLST+1
        rts
.endproc
 
 
; ---------------------------------------------------------------------
; subrutina pro obsluhu VBI
; ---------------------------------------------------------------------
.proc   horizontal_movement
        ldx x_pos               ; původní pozice prvního hráče
 
        lda STICK0              ; čtení joysticku
        cmp #11                 ; je nakloněn doleva?
        bne not_left
        dex                     ; posun hráče doleva
not_left:
        cmp #7                  ; je nakloněn doprava?
        bne not_right
        inx                     ; posun hráče doprava
not_right:
        stx HPOSP0              ; změna pozice prvního hráče
        stx x_pos               ; zapamatovat si pozici prvního hráče
        jmp XITVBV              ; zpracovat zbytek odloženého VBLANKu
        rts
.endproc
 
 
; ---------------------------------------------------------------------
; obsluha DLI
; ---------------------------------------------------------------------
dli:
        pha                     ; uschovat akumulátor
        lda color               ; barva pozadí
        sta COLPF2              ; přímo nastavit zápisem do HW registru
        eor #%10000000          ; negovat nejvyšší bit
        sta color
        pla                     ; obnovit akumulátor
        rti                     ; návrat z DLI
 
 
dlist:
.byte DL_BLK8, DL_BLK8, DL_BLK8 ; 3x8=24 prázdných obrazových řádků
.byte DL_LMS+DL_CHR40x8x1       ; určení počáteční adresy obrazové paměti + jeden řádek režimu 2 (GR.0)
.byte @lt;screen, >screen          ; počáteční adresa obrazové paměti 
.res 6, DL_CHR40x8x1            ; opakovat řádky textového režimu 2 (GR.0)
.byte DL_DLI+DL_CHR40x8x1       ; GR.0 ovšem navíc s povolením DLI
.res 7, DL_CHR40x8x1            ; opakovat řádky textového režimu 2 (GR.0)
.byte DL_DLI+DL_CHR40x8x1       ; GR.0 ovšem navíc s povolením DLI
.res 8, DL_CHR40x8x1            ; opakovat řádky textového režimu 2 (GR.0)
.byte DL_JVB, <dlist, >dlist    ; skok na začátek display listu
 
 
color:
.byte $c4                       ; původní barva
 
 
; data
sprite:   .byte 24, 60, 126, 219, 255, 36, 90, 165
 
; horizontální pozice hráče
x_pos:    .byte 80
 
end:
 
 
.BSS
screen: .res 40*24
 
.segment "EXEHDR"
.word   $ffff                   ; uvodni sekvence bajtu v souboru XEX
.word   main                    ; zacatek kodoveho segmentu
.word   end - 1                 ; konec kodoveho segmentu
 
 
.segment "AUTOSTRT"             ; segment s pocatecni adresou
.word   RUNAD                   ; naplni se pouze adresy RUNAD a RUNAD+1
.word   RUNAD+1
.word   main                    ; adresa vstupniho bodu do programu
 
; finito

Přepis všech částí programu do formy maker

Zajímavější a potenciálně užitečnější může být přepis částí programu do formy maker. Předností tohoto řešení je snadné předávání parametrů do makra, protože to se provádí v době překladu a nejsme tedy omezeni možnostmi čipu MOS 6502, relativně malým zásobníkem atd. atd. Druhou předností je fakt, že program jako celek bude menší a nepatrně rychlejší – ušetří se za instrukce JSR a RTS, ovšem pouze za předpokladu, že každé makro bude použito (expandováno) jen jedenkrát. A je zde ještě jeden malý problém – všechny symboly definované v makru by měly být lokální, aby bylo možné makro v případě potřeby skutečně expandovat vícekrát.

Poznámka: zatímco v jazyku C jsou makra spíše problematickým (ale důležitým) prvkem jazyka, je tomu v assembleru CA65 naopak.

Hlavní část programu v případě, že jsou další jeho části napsané s využitím maker, vypadá poměrně vysokoúrovňově, protože do maker můžeme předávat parametry a vyhnout se tak přímému použití globálních symbolů:

; ---------------------------------------------------------------------
; vstupní bod do programu
; ---------------------------------------------------------------------
.proc main
        set_display_list dlist  ; nastavení display listu
        fill_screen screen      ; výpis znaků na obrazovku
        setup_sprites sprite    ; nastavení spritů
        set_dli_handler dli     ; nastavení obsluhy DLI
        set_vbi_handler vbi     ; nastavení obsluhy VBI
        enable_interrupts       ; povolení přerušení
        game_loop               ; hlavní herní smyčka
.endproc

Samotná makra obsahují i definici parametrů:

; ---------------------------------------------------------------------
; makro pro nastavení display listu
; ---------------------------------------------------------------------
.macro  set_display_list label
        lda #<label             ; nižší byte adresy display listu
        sta SDLSTL
        lda #>label             ; vyšší byte adresy display listu
        sta SDLSTH
.endmacro

Další makro obsahuje návěští, ovšem to je definováno jako lokální symbol:

; ---------------------------------------------------------------------
; makro pro vyplnění obrazovky znaky
; ---------------------------------------------------------------------
.macro  fill_screen screen
        .local clear            ; definice lokálního symbolu
        ldy #0                  ; počitadlo zápisů
clear:
        tya                     ; kód vypisovaného znaku
        sta screen, y           ; tisk znaku na zvolené místo na obrazovce
        sta screen+40*8, y
        sta screen+40*16, y
        iny                     ; zvětšit hodnotu počitadla a offsetu
        cpy #$80
        bne clear               ; skok
.endmacro

Další makro s lokálními symboly (a bez parametrů):

; ---------------------------------------------------------------------
; makro pro nastavení DLI i VBI
; ---------------------------------------------------------------------
.macro  enable_interrupts
        .local NMIEN_DLI        ; definice lokálního symbolu
        .local NMIEN_VBI        ; definice lokálního symbolu
        NMIEN_DLI=$80           ; maska povolení DLI
        NMIEN_VBI=$40           ; maska povolení VBI
        lda #NMIEN_DLI | NMIEN_VBI ; povolení DLI
        sta NMIEN
.endmacro

A konečně si ukažme makra, do kterých se předávají jména subrutin, které mají být zaregistrovány pro obsluhu DLI nebo VBI:

; ---------------------------------------------------------------------
; makro pro nastavení DLI
; ---------------------------------------------------------------------
.macro  set_dli_handler handler
        ; vektor DLI
        lda #<handler           ; nastavení DLI
        sta VDSLST
        lda #>handler
        sta VDSLST+1
.endmacro

a:

; ---------------------------------------------------------------------
; makro pro nastavení VBI
; ---------------------------------------------------------------------
.macro  set_vbi_handler handler
        ; nastavit vektor pro odloženou VBI
        lda #7                  ; změna vektoru pro odložené VBI
        ldx #>handler
        ldy #<handler
        jsr SETVBV              ; zavolat službu systému pro nastavení vektoru
.endmacro

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

Závěrem praktické části dnešního článku si ukážeme úplný zdrojový kód příkladu s DLI i VBI, který je celý realizován s využitím maker:

; ---------------------------------------------------------------------
; Ovládání PMG joystickem v horizontálním směru.
; ---------------------------------------------------------------------
 
.include "atari.inc"
 
.CODE
 
PLAYER_0_OFFSET = 512
PLAYER_1_OFFSET = PLAYER_0_OFFSET + 128
PLAYER_2_OFFSET = PLAYER_1_OFFSET + 128
PLAYER_3_OFFSET = PLAYER_2_OFFSET + 128
 
 
 
; ---------------------------------------------------------------------
; definice maker
; ---------------------------------------------------------------------
 
 
 
; ---------------------------------------------------------------------
; makro pro nastavení display listu
; ---------------------------------------------------------------------
.macro  set_display_list label
        lda #<label             ; nižší byte adresy display listu
        sta SDLSTL
        lda #>label             ; vyšší byte adresy display listu
        sta SDLSTH
.endmacro
 
 
 
; ---------------------------------------------------------------------
; makro pro vyplnění obrazovky znaky
; ---------------------------------------------------------------------
.macro  fill_screen screen
        .local clear            ; definice lokálního symbolu
        ldy #0                  ; počitadlo zápisů
clear:
        tya                     ; kód vypisovaného znaku
        sta screen, y           ; tisk znaku na zvolené místo na obrazovce
        sta screen+40*8, y
        sta screen+40*16, y
        iny                     ; zvětšit hodnotu počitadla a offsetu
        cpy #$80
        bne clear               ; skok
.endmacro
 
 
 
; ---------------------------------------------------------------------
; makro pro nastavení všech spritů
; ---------------------------------------------------------------------
.macro  setup_sprites sprite_address
        lda #80                 ; horizontální pozice prvního hráče
        sta HPOSP0              ; uložit do řídicího registru HPOSP0 na čipu GTIA
 
        lda #100                ; horizontální pozice druhého hráče
        sta HPOSP1              ; uložit do řídicího registru HPOSP1 na čipu GTIA
 
        lda #120                ; horizontální pozice třetího hráče
        sta HPOSP2              ; uložit do řídicího registru HPOSP2 na čipu GTIA
 
        lda #140                ; horizontální pozice čtvrtého hráče
        sta HPOSP3              ; uložit do řídicího registru HPOSP3 na čipu GTIA
 
        lda #HUE_GREEN<<4 + 12  ; barva prvního hráče (odstín+intenzita)
        sta PCOLR0              ; uložit do řídicího registru PCOLR0 na čipu GTIA
 
        lda #HUE_YELLOW<<4 + 12 ; barva druhého hráče (odstín+intenzita)
        sta PCOLR1              ; uložit do řídicího registru PCOLR1 na čipu GTIA
 
        lda #HUE_MAGENTA<<4 + 12 ; barva třetího hráče (odstín+intenzita)
        sta PCOLR2              ; uložit do řídicího registru PCOLR2 na čipu GTIA
 
        lda #HUE_CYAN<<4 + 12   ; barva čtvrtého hráče (odstín+intenzita)
        sta PCOLR3              ; uložit do řídicího registru PCOLR3 na čipu GTIA
 
        lda #$ff                ; bitová maska všech hráčů
        sta GRAFP0              ; uložit do řídicího registru GRAFP0 na čipu GTIA
        sta GRAFP1              ; uložit do řídicího registru GRAFP1 na čipu GTIA
        sta GRAFP2              ; uložit do řídicího registru GRAFP2 na čipu GTIA
        sta GRAFP3              ; uložit do řídicího registru GRAFP3 na čipu GTIA
 
        lda #3                  ; bitové pole: povolení hráčů i střel
        sta GRACTL              ; uložit do řídicího registru GRACTL na čipu GTIA
 
        lda #1                   ; priorita hráčů a pozadí
        sta GPRIOR              ; uložit do řídicího registru GPRIOR na čipu GTIA
 
        lda #152                ; paměťová stránka číslo 152
        sta PMBASE
 
        .local addr             ; definice lokálního symbolu
        addr = 152*256
 
        .local next_line        ; definice lokálního symbolu
        ldx #8                  ; začneme na hodnotě o 1 vyšší
next_line:
        lda sprite_address-1, x          ; načíst
        sta addr+PLAYER_0_OFFSET+100, x  ; uložit byte - první hráč
        sta addr+PLAYER_1_OFFSET+100, x  ; uložit byte - druhý hráč
        sta addr+PLAYER_2_OFFSET+100, x  ; uložit byte - třetí hráč
        sta addr+PLAYER_3_OFFSET+100, x  ; uložit byte - čtvrtý hráč
        dex                     ; snížit offset + nastavit příznaky
        bne next_line           ; další byte spritu
 
        lda #46                 ; povolení PMG DMA
        sta SDMCTL
.endmacro
 
 
 
; ---------------------------------------------------------------------
; makro pro nastavení DLI i VBI
; ---------------------------------------------------------------------
.macro  enable_interrupts
        .local NMIEN_DLI        ; definice lokálního symbolu
        .local NMIEN_VBI        ; definice lokálního symbolu
        NMIEN_DLI=$80           ; maska povolení DLI
        NMIEN_VBI=$40           ; maska povolení VBI
        lda #NMIEN_DLI | NMIEN_VBI ; povolení DLI
        sta NMIEN
.endmacro
 
 
 
; ---------------------------------------------------------------------
; makro pro nastavení VBI
; ---------------------------------------------------------------------
.macro  set_vbi_handler handler
        ; nastavit vektor pro odloženou VBI
        lda #7                  ; změna vektoru pro odložené VBI
        ldx #>handler
        ldy #<handler
        jsr SETVBV              ; zavolat službu systému pro nastavení vektoru
.endmacro
 
 
 
; ---------------------------------------------------------------------
; makro pro nastavení DLI
; ---------------------------------------------------------------------
.macro  set_dli_handler handler
        ; vektor DLI
        lda #<handler           ; nastavení DLI
        sta VDSLST
        lda #>handler
        sta VDSLST+1
.endmacro
 
 
 
; ---------------------------------------------------------------------
; hlavní herní smyčka
; ---------------------------------------------------------------------
.macro  game_loop
        .local loop             ; definice lokálního symbolu
loop:
        jmp loop                ; program vlastně nice nedělá - jen cyklí!
.endmacro
 
 
 
; ---------------------------------------------------------------------
; vstupní bod do programu
; ---------------------------------------------------------------------
.proc main
        set_display_list dlist  ; nastavení display listu
        fill_screen screen      ; výpis znaků na obrazovku
        setup_sprites sprite    ; nastavení spritů
        set_dli_handler dli     ; nastavení obsluhy DLI
        set_vbi_handler vbi     ; nastavení obsluhy VBI
        enable_interrupts       ; povolení přerušení
        game_loop               ; hlavní herní smyčka
.endproc
 
 
 
; ---------------------------------------------------------------------
; subrutina pro obsluhu VBI
; ---------------------------------------------------------------------
.proc   vbi
        ldx x_pos               ; původní pozice prvního hráče
 
        lda STICK0              ; čtení joysticku
        cmp #11                 ; je nakloněn doleva?
        bne not_left
        dex                     ; posun hráče doleva
not_left:
        cmp #7                  ; je nakloněn doprava?
        bne not_right
        inx                     ; posun hráče doprava
not_right:
        stx HPOSP0              ; změna pozice prvního hráče
        stx x_pos               ; zapamatovat si pozici prvního hráče
        jmp XITVBV              ; zpracovat zbytek odloženého VBLANKu
.endproc
 
 
; ---------------------------------------------------------------------
; obsluha DLI
; ---------------------------------------------------------------------
dli:
        pha                     ; uschovat akumulátor
        lda color               ; barva pozadí
        sta COLPF2              ; přímo nastavit zápisem do HW registru
        eor #%10000000          ; negovat nejvyšší bit
        sta color
        pla                     ; obnovit akumulátor
        rti                     ; návrat z DLI
 
 
dlist:
.byte DL_BLK8, DL_BLK8, DL_BLK8 ; 3x8=24 prázdných obrazových řádků
.byte DL_LMS+DL_CHR40x8x1       ; určení počáteční adresy obrazové paměti + jeden řádek režimu 2 (GR.0)
.byte <screen, >screen          ; počáteční adresa obrazové paměti 
.res 6, DL_CHR40x8x1            ; opakovat řádky textového režimu 2 (GR.0)
.byte DL_DLI+DL_CHR40x8x1       ; GR.0 ovšem navíc s povolením DLI
.res 7, DL_CHR40x8x1            ; opakovat řádky textového režimu 2 (GR.0)
.byte DL_DLI+DL_CHR40x8x1       ; GR.0 ovšem navíc s povolením DLI
.res 8, DL_CHR40x8x1            ; opakovat řádky textového režimu 2 (GR.0)
.byte DL_JVB, >dlist, >dlist    ; skok na začátek display listu
 
 
color:
.byte $c4                       ; původní barva
 
 
; data
sprite:   .byte 24, 60, 126, 219, 255, 36, 90, 165
 
; horizontální pozice hráče
x_pos:    .byte 80
 
end:
 
 
.BSS
screen: .res 40*24
 
.segment "EXEHDR"
.word   $ffff                   ; uvodni sekvence bajtu v souboru XEX
.word   main                    ; zacatek kodoveho segmentu
.word   end - 1                 ; konec kodoveho segmentu
 
 
.segment "AUTOSTRT"             ; segment s pocatecni adresou
.word   RUNAD                   ; naplni se pouze adresy RUNAD a RUNAD+1
.word   RUNAD+1
.word   main                    ; adresa vstupniho bodu do programu
 
; finito

Obsah navazujícího článku

Popisem čipu ANTIC jsme se zabývali již ve čtyřech článcích, a to z toho důvodu, že se jedná o integrovaný obvod nabízející programátorům poměrně velké možnosti. Příště jeho popis dokončíme. Zabývat se budeme především realizací takzvaného jemného scrollingu. Čip ANTIC totiž umožňuje provádění horizontálního a/nebo vertikálního scrollingu s přesností na jednotlivé pixely, a to bez nutnosti přenosu dat ve video paměti. Scrolling je možné realizovat ve všech režimech, ovšem význam má především v režimech textových a pseudotextových (GR.13, GR.14). Ovšem to není vše. Navíc je ještě možné nastavit šířku herního pole (playfiend). K dispozici jsou tři šířky, které se uvádí v počtu takzvaných color cyklů (odpovídá frekvenci změny barvové složky TV signálu): 128 cyklů, 160 cyklů a 192 cyklů. Počet color cyklů odpovídá horizontálnímu rozlišení v grafických režimech B, C, D a E. Naproti tomu v režimu F (GR.8) se jedná o 256, 320 a 384 pixelů (maximální dosažitelné rozlišení je tak přibližně rovno 384×224 pixelů).

Příloha: Makefile pro překlad všech demonstračních příkladů

Všechny minule i dnes popsané demonstrační příklady, pro jejichž překlad je zapotřebí použít assembler ca65 a linker ld65, je možné přeložit s využitím souboru Makefile, jehož obsah je vypsán pod tímto odstavcem:

Školení Kubernetes

execs := dummy.xex print_a.xex \
         background_color_1.xex  background_color_2.xex \
         color_computation_1.xex color_computation_2.xex \
         subroutine_1.xex        subroutine_2.xex \
         hex_number_1.xex        hex_number_2.xex \
         hex_number_3.xex        hex_number_4.xex \
         hex_number_5.xex        hex_number_6.xex \
         hex_number_7.xex        hex_number_8.xex \
         hex_number_9.xex \
         fill_block_1.xex        fill_block_2.xex \
         fill_block_3.xex        fill_block_4.xex \
         fill_block_5.xex \
         pmg_01.xex              pmg_02.xex \
         pmg_03.xex              pmg_04.xex \
         pmg_05.xex              pmg_06.xex \
         pmg_07.xex              pmg_08.xex \
         pmg_09.xex              pmg_10.xex \
         pmg_11.xex              pmg_12.xex \
         pmg_13.xex              pmg_14.xex \
         pmg_15.xex              pong.xex \
         pmg_stick_1.xex         pmg_stick_2.xex \
         pmg_stick_3.xex         pmg_stick_4.xex \
         pmg_stick_5.xex         pmg_stick_6.xex \
         pmg_collisions_1.xex    pmg_collisions_2.xex \
         pmg_collisions_3.xex    pmg_collisions_4.xex \
         antic_1.xex             antic_2.xex \
         antic_3.xex             antic_4.xex \
         antic_5.xex             antic_6.xex \
         antic_7.xex             antic_8.xex \
         antic_9.xex             antic_A.xex \
         antic_B.xex \
         antic_bitmap_1.xex      antic_bitmap_2.xex \
         antic_bitmap_3.xex      antic_bitmap_4.xex \
         antic_bitmap_5.xex      antic_bitmap_6.xex \
         antic_bitmap_7.xex      antic_bitmap_8.xex \
         antic_dli_1.asm         antic_dli_2.asm \
         antic_dli_3.asm         antic_dli_4.asm \
         antic_dli_5.asm         antic_dli_pmg.asm
 
all: $(execs)
 
clean:
        rm -f *.o
        rm -f *.xex
 
.PHONY: all clean
 
%.o: %.asm
        ca65 $< -t atari -o $@ -l $(basename $<)_list.asm --list-bytes 100
 
%.xex: %.o
        ld65 -C linker.cfg $< -o $@ -m $(basename $<).map
 
antic_bitmap_6.xex:     antic_bitmap_6.o
        ld65 -C linker_image.cfg $< -o $@ -m $(basename $<).map
 
antic_bitmap_7.xex:     antic_bitmap_7.o
        ld65 -C linker_image_2.cfg $< -o $@ -m $(basename $<).map
 
antic_bitmap:   \
        antic_bitmap_1.xex \
        antic_bitmap_2.xex \
        antic_bitmap_3.xex \
        antic_bitmap_4.xex \
        antic_bitmap_5.xex \
        antic_bitmap_6.xex \
        antic_bitmap_7.xex \
        antic_bitmap_8.xex
 
antic_dli:      \
        antic_dli_1.xex \
        antic_dli_2.xex \
        antic_dli_3.xex \
        antic_dli_4.xex \
        antic_dli_5.xex \
        antic_dli_pmg.xex
 
antic_vbi:      \
        antic_vbi_1.xex \
        antic_vbi_2.xex \
        antic_vbi_3.xex \
        antic_vbi_dli_1.xex \
        antic_vbi_dli_2.xex \
        antic_vbi_dli_3.xex \
        antic_vbi_dli_4.xex

Výsledkem překladu jsou soubory s koncovkou .xex, které je možné přímo spustit v emulátoru osmibitových počítačů Atari.

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

Všechny demonstrační příklady, s nimiž jsme se v předchozích článcích i v článku dnešním seznámili a které jsou určeny pro překlad s využitím assembleru ca65, jsou dostupné, jak je zvykem, na GitHubu. V tabulce níže jsou uvedeny odkazy na jednotlivé zdrojové kódy příkladů psané v assembleru i „listingy“ vygenerované samotným assemblerem, ze kterých je patrné, jakým způsobem se jednotlivé příklady přeložily do výsledného XEX souboru:

# Příklad Stručný popis příkladu Adresa
1 Makefile definice cílů pro překlad všech demonstračních příkladů z této tabulky https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/Makefile
2 linker.cfg konfigurační soubor pro linker https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/linker.cfg
       
3 dummy.asm pouze nekonečná smyčka https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/dummy.asm
4 dummy_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/dummy_list.asm
5 dummy_list.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/dummy.map
       
6 background_color1.asm změna barvy pozadí – základní varianta příkladu https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/background_color1.asm
7 background_color1_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/background_color1_list.asm
8 background_color1.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/background_color1.map
       
9 background_color2.asm změna barvy pozadí – využití předdefinovaných konstant https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/background_color2.asm
10 background_color2_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/background_color2_list.asm
11 background_color2.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/background_color2.map
       
12 print_a.asm tisk znaku přímo do obrazové paměti https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/print_a.asm
13 print_a_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/print_a_list.asm
14 print_a.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/print_a.map
       
15 color_computation1.asm výpočet barvy, varianta bez bitových posunů https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/color_computation1.asm
16 color_computation1_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/color_computation1_list.asm
17 color_computation1.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/color_computation1.map
       
18 color_computation2.asm výpočet barvy, varianta s bitovými posuny https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/color_computation2.asm
19 color_computation2_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/color_computation2_list.asm
20 color_computation2.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/color_computation2.map
       
21 subroutine1.asm skok do podprogramu bez předávání parametrů https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/subroutine1.asm
22 subroutine1_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/subroutine1_list.asm
23 subroutine1.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/subroutine1.map
       
24 subroutine2.asm skok do podprogramu s předáním parametru https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/subroutine2.asm
25 subroutine2_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/subroutine2_list.asm
26 subroutine2.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/subroutine2.map
       
27 hex_number1.asm tisk jedné hexadecimální číslice (nekorektní varianta) https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number1.asm
28 hex_number1_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number1_list.asm
29 hex_number1.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number1.map
       
30 hex_number2.asm tisk jedné hexadecimální číslice (korektní varianta) https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number2.asm
31 hex_number2_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number2_list.asm
32 hex_number2.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number2.map
       
33 hex_number3.asm tisk jedné hexadecimální číslice (korektní varianta po refaktoringu) https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number3.asm
34 hex_number3_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number3_list.asm
35 hex_number3.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number3.map
       
36 hex_number4.asm tisk jedné hexadecimální číslice, varianta postavená na makrech https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number4.asm
37 hex_number4_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number4_list.asm
38 hex_number4.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number4.map
       
39 hex_number5.asm tisk jedné hexadecimální číslice, varianta postavená na makrech, lokální automaticky generovaná návěští https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number5.asm
40 hex_number5_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number5_list.asm
41 hex_number5.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number5.map
       
42 hex_number6.asm příprava pro tisk dvouciferné hexadecimální hodnoty https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number6.asm
43 hex_number6_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number6_list.asm
44 hex_number6.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number6.map
       
45 hex_number7.asm realizace tisku dvouciferné hexadecimální hodnoty https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number7.asm
46 hex_number7_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number7_list.asm
47 hex_number7.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number7.map
       
48 hex_number8.asm makro pro logický posun doprava o zadaný počet bitů https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number8.asm
49 hex_number8_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number8_list.asm
50 hex_number8.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number8.map
       
51 hex_number9.asm čekání na stisk klávesy https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number8.asm
52 hex_number9_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number8_list.asm
53 hex_number9.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number8.map
       
54 fill_block1.asm vyplnění bloku, varianta se dvěma index registry https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/fill_block1.asm
55 fill_block1_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/fill_block1_list.asm
56 fill_block1.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/fill_block1.map
       
57 fill_block2.asm vyplnění bloku, nekorektní varianta využívající jeden index registr https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/fill_block2.asm
58 fill_block2_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/fill_block2_list.asm
59 fill_block2.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/fill_block2.map
       
60 fill_block3.asm vyplnění bloku, korektní varianta využívající jeden index registr https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/fill_block3.asm
61 fill_block3_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/fill_block3_list.asm
62 fill_block3.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/fill_block3.map
       
63 fill_block4.asm vyplnění bloku delšího než 256 bajtů https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/fill_block4.asm
64 fill_block4_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/fill_block4_list.asm
65 fill_block4.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/fill_block4.map
       
66 fill_block5.asm vyplnění bloku, čítání směrem nahoru https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/fill_block5.asm
67 fill_block5_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/fill_block5_list.asm
68 fill_block5.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/fill_block5.map
       
69 pmg01.asm inicializace PMG, povolení PMG, nastavení pozice a tvaru prvního hráče https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg01.asm
70 pmg01_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg01_list.asm
71 pmg01.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg01.map
       
72 pmg02.asm nastavení pozice, tvaru a barvy prvního hráče https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg02.asm
73 pmg02_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg02_list.asm
74 pmg02.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg02.map
       
75 pmg03.asm vliv zákazu DMA na zobrazení PMG https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg03.asm
76 pmg03_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg03_list.asm
77 pmg03.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg03.map
       
78 pmg04.asm postupná změna horizontální velikosti hráče https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg04.asm
79 pmg04_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg04_list.asm
80 pmg04.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg04.map
       
81 pmg05.asm odlišná bitová maska tvaru hráče https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg05.asm
82 pmg05_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg05_list.asm
83 pmg05.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg05.map
       
84 pmg06.asm inicializace a zobrazení dvou hráčů, kteří se překrývají https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg06.asm
84 pmg06_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg06_list.asm
86 pmg06.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg06.map
       
87 pmg07.asm naivní způsob nastavení bitmapy prvního hráče https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg07.asm
88 pmg07_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg07_list.asm
89 pmg07.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg07.map
       
90 pmg08.asm elegantnější způsob nastavení bitmapy prvního hráče https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg08.asm
91 pmg08_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg08_list.asm
92 pmg08.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg08.map
       
93 pmg09.asm zobrazení všech čtyř hráčů, změna priority zobrazení https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg09.asm
94 pmg09_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg09_list.asm
95 pmg09.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg09.map
       
96 pmg10.asm nastavení bitmap všech čtyř hráčů https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg10.asm
97 pmg10_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg10_list.asm
98 pmg10.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg10.map
       
99 pmg_stick1.asm ovládání prvního hráče joystickem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_stick1.asm
100 pmg_stick1_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_stick1_list.asm
101 pmg_stick1.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_stick1.map
       
102 pmg_stick2.asm zobrazení všech čtyř střel https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_stick2.asm
103 pmg_stick2_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_stick2_list.asm
104 pmg_stick2.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_stick2.map
       
105 pmg_stick3.asm střely zdánlivě tvoří pátého hráče (ovšem stále jsou samostatné) https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_stick3.asm
106 pmg_stick3_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_stick3_list.asm
107 pmg_stick3.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_stick3.map
       
108 pmg_stick4.asm korektní zobrazení pátého hráče https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_stick4.asm
109 pmg_stick4_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_stick4_list.asm
110 pmg_stick4.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_stick4.map
       
111 pmg_stick5.asm detekce stisku tlačítka joysticku, změna barvy prvního hráče https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_stick5.asm
112 pmg_stick5_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_stick5_list.asm
113 pmg_stick5.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_stick5.map
       
114 pmg11.asm automatický horizontální pohyb prvního hráče, realizace zpožďovací smyčky https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg11.asm
115 pmg11_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg11_list.asm
116 pmg11.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg11.map
       
117 pmg12.asm automatický horizontální pohyb prvního hráče, čekání na další snímek https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg12.asm
118 pmg12_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg12_list.asm
119 pmg12.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg12.map
       
120 pmg13.asm vertikální posun spritu směrem dolů (nekorektní varianta) https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg13.asm
121 pmg13_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg13_list.asm
122 pmg13.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg13.map
       
123 pmg14.asm vertikální posun spritu směrem dolů (korektní varianta) https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg14.asm
124 pmg14_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg14_list.asm
125 pmg14.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg14.map
       
126 pmg15.asm vertikální posun spritu směrem nahoru (korektní varianta) https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg15.asm
127 pmg15_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg15_list.asm
128 pmg15.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg15.map
       
129 pmg_stick6.asm ovládání PMG joystickem v horizontálním i vertikálním směru https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_stick6.asm
130 pmg_stick6_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_stick6_list.asm
131 pmg_stick6.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_stick6.map
       
132 pmg_collision1.asm ovládání PMG joystickem, detekce kolize prvního hráče s dalšími hráči https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_collision1.asm
133 pmg_collision1_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_collision1_list.asm
134 pmg_collision1.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_collision1.map
       
135 pmg_collision2.asm ovládání PMG joystickem, detekce kolize prvního hráče s dalšími hráči https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_collision2.asm
136 pmg_collision2_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_collision2_list.asm
137 pmg_collision2.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_collision2.map
       
138 pmg_collision3.asm ovládání PMG joystickem, detekce kolize prvního hráče s dalšími hráči, detekce kolize první střely s hráči https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_collision3.asm
139 pmg_collision3_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_collision3_list.asm
140 pmg_collision3.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_collision3.map
       
141 pmg_collision4.asm ovládání PMG joystickem, detekce kolize prvního hráče s hracím polem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_collision4.asm
142 pmg_collision4_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_collision4_list.asm
143 pmg_collision4.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pmg_collision4.map
       
144 pong.asm scéna ze hry Pong vykreslená jen s využitím spritů https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pong.asm
145 pong_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pong_list.asm
146 pong.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/pong.map
       
147 antic1.asm nastavení textového režimu se čtyřmi barvami a 20×12 znaky https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic1.asm
148 antic1_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic1_list.asm
149 antic1.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic1.map
       
150 antic2.asm nastavení textového režimu se čtyřmi barvami a 20×12 znaky, zlepšení čitelnosti https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic2.asm
151 antic2_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic2_list.asm
152 antic2.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic2.map
       
153 antic3.asm nastavení režimu, ve kterém se kombinují různé textové a grafické řádky https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic3.asm
154 antic3_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic3_list.asm
155 antic3.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic3.map
       
156 antic4.asm nastavení standardního textového režimu GR.0, výpis 256 znaků https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic4.asm
157 antic4_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic4_list.asm
158 antic4.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic4.map
       
159 antic5.asm volba mezinárodní znakové sady pro textový režim GR.0 https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic5.asm
160 antic5_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic5_list.asm
161 antic5.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic5.map
       
162 antic6.asm volba náhodné stránky pro fonty v textovém režimu GR.0 https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic6.asm
163 antic6_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic6_list.asm
164 antic6.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic6.map
       
165 antic7.asm tisk 64 znaků ve čtyřech barvách v režimu GR.1 https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic7.asm
166 antic7_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic7_list.asm
167 antic7.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic7.map
       
168 antic8.asm určení, které znaky se budou tisknout v režimu GR.1 nebo GR.2 https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic8.asm
169 antic8_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic8_list.asm
170 antic8.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic8.map
       
171 antic9.asm nastavení textového režimu GR.12 a výpis znaků na obrazovku https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic9.asm
172 antic9_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic9_list.asm
173 antic9.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic9.map
       
174 antic_A.asm vlastní znaková sada (naivní přístup) pro textový režim GR.12 https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_A.asm
175 antic_A_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_A_list.asm
176 antic_A.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_A.map
       
177 antic_B.asm nastavení dvoubarevného grafického režimu s rozlišením 80×48 pixelů https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_B.asm
178 antic_B_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_B_list.asm
179 antic_B.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_B.map
       
180 antic_bitmap1.asm nastavení dvoubarevného grafického režimu s rozlišením 80×48 pixelů, zobrazení bitmapy https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap1.asm
181 antic_bitmap1_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap1_list.asm
182 antic_bitmap1.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap1.map
       
183 antic_bitmap2.asm nastavení dvoubarevného grafického režimu s rozlišením 80×48 pixelů, jednodušší zápis display listu https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap2.asm
184 antic_bitmap2_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap2_list.asm
185 antic_bitmap2.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap2.map
       
186 antic_bitmap3.asm nastavení dvoubarevného grafického režimu s rozlišením 160×96 pixelů, zobrazení bitmapy https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap3.asm
187 antic_bitmap3_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap3_list.asm
188 antic_bitmap3.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap3.map
       
189 antic_bitmap4.asm nastavení dvoubarevného grafického režimu s rozlišením 160×192 pixelů, zobrazení bitmapy https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap4.asm
190 antic_bitmap4_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap4_list.asm
191 antic_bitmap4.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap4.map
       
192 antic_bitmap5.asm nastavení dvoubarevného grafického režimu s rozlišením 320×192 pixelů, nekorektní display list, nekorektní zobrazení bitmapy https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap5.asm
193 antic_bitmap5_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap5_list.asm
194 antic_bitmap5.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap5.map
       
195 antic_bitmap6.asm nastavení dvoubarevného grafického režimu s rozlišením 320×192 pixelů, zarovnání bitmapy do bloku 4096 bajtů https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap6.asm
196 antic_bitmap6_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap6_list.asm
197 antic_bitmap6.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap6.map
       
198 antic_bitmap7.asm nastavení dvoubarevného grafického režimu s rozlišením 320×192 pixelů, korektní display list, rozdělená bitmapa https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap7.asm
199 antic_bitmap7_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap7_list.asm
200 antic_bitmap7.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap7.map
       
201 antic_bitmap8.asm nastavení čtyřbarevného grafického režimu s rozlišením 160×96 pixelů, zobrazení čtyřbarevného obrázku https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap8.asm
202 antic_bitmap8_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap8_list.asm
203 antic_bitmap8.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_bitmap8.map
       
204 chars.bas tisk všech znaků na obrazovku (varianta naprogramovaná v BASICu) https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/chars.bas
       
205 image_80×48.asm data obrázku 80×48 ve formě příkazů .byte https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/image_80×48.asm
206 image_160×96.asm data obrázku 160×96 ve formě příkazů .byte https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/image_160×96.asm
207 image_160×192.asm data obrázku 160×192 ve formě příkazů .byte https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/image_160×192.asm
208 image_320×192.bin čistě binární data obrázku 320×192× https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/image_320×192.bin
209 image_320×192_1.bin čistě binární data obrázku 320×96× (první polovina) https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/image_320×192_1.bin
210 image_320×192_2.bin čistě binární data obrázku 320×96× (druhá polovina) https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/image_320×192_2.bin
211 image_160×96×2.bin čistě binární data obrázku 320×192× https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/image_160×96×2.bin
       
212 antic_dli1.asm výpis všech 128 znaků v přímé i inverzní podobě v režimu GR.0 https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_dli1.asm
213 antic_dli1_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_dli1_list.asm
214 antic_dli1.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_dli1.map
       
215 antic_dli2.asm dočasná modifikace barvy pozadí provedená v DLI (dvanáctý textový řádek) https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_dli2.asm
216 antic_dli2_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_dli2_list.asm
217 antic_dli2.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_dli2.map
       
218 antic_dli3.asm opakované čekání na synchronizační pulz v DLI, výběr odlišné barvy pozadí https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_dli3.asm
219 antic_dli3_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_dli3_list.asm
220 antic_dli3.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_dli3.map
       
221 antic_dli4.asm display list obsahující několik instrukcí DLI, opakovaná změna barvy pozadí https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_dli4.asm
222 antic_dli4_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_dli4_list.asm
223 antic_dli4.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_dli4.map
       
224 antic_dli5.asm display list obsahující několik instrukcí DLI, opakovaná změna barvy pozadí https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_dli5.asm
225 antic_dli5_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_dli5_list.asm
226 antic_dli5.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_dli5.map
       
227 antic_dli_pmg.asm zobrazení osmi spritů namísto spritů čtyř s využitím DLI https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_dli_pmg.asm
228 antic_dli_pmg_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_dli_pmg_list.asm
229 antic_dli_pmg.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_dli_pmg.map
       
230 antic_vbi1.asm aktivní čekání na dokončení vykreslení snímku (bez VBI) https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_vbi1.asm
231 antic_vbi1_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_vbi1_list.asm
232 antic_vbi1.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_vbi1.map
       
233 antic_vbi2.asm pohyb PMG realizovaný ve VBI (první způsob nastavení vektoru) https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_vbi2.asm
234 antic_vbi2_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_vbi2_list.asm
235 antic_vbi2.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_vbi2.map
       
235 antic_vbi3.asm pohyb PMG realizovaný ve VBI (druhý způsob nastavení vektoru) https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_vbi3.asm
236 antic_vbi3_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_vbi3_list.asm
238 antic_vbi3.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_vbi3.map
       
239 antic_vbi_dli1.asm změna pozice PMG ve VBI, modifikace barvy herního pole v DLI https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_vbi_dli1.asm
240 antic_vbi_dli1_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_vbi_dli1_list.asm
241 antic_vbi_dli1.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_vbi_dli1.map
       
242 antic_vbi_dli2.asm dtto, ale s odstraněním nadbytečné instrukce RTS ve VBI https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_vbi_dli2.asm
243 antic_vbi_dli2_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_vbi_dli2_list.asm
244 antic_vbi_dli2.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_vbi_dli2.map
       
245 antic_vbi_dli3.asm přepis předchozího příkladu s využitím subrutin https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_vbi_dli3.asm
246 antic_vbi_dli3_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_vbi_dli3_list.asm
247 antic_vbi_dli3.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_vbi_dli3.map
       
248 antic_vbi_dli4.asm přepis předchozího příkladu s využitím maker https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_vbi_dli4.asm
249 antic_vbi_dli4_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_vbi_dli4_list.asm
250 antic_vbi_dli4.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/antic_vbi_dli4.map

Odkazy na Internetu

  1. MOS 6502 instruction set
    http://www.6502.org/users/o­belisk/6502/instructions.html
  2. EXE File Format Description
    https://gury.atari8.info/ref­s/file_formats_exe.php
  3. XEX Filter – A toolkit to analyze and manipulate Atari binary files
    https://www.vitoco.cl/atari/xex-filter/index.html
  4. chkxex.py
    https://raw.githubusercon­tent.com/seban-slt/tcx_tools/refs/heads/mas­ter/chkxex.py
  5. ca65 Users Guide
    https://cc65.github.io/doc/ca65.html
  6. cc65 Users Guide
    https://cc65.github.io/doc/cc65.html
  7. ld65 Users Guide
    https://cc65.github.io/doc/ld65.html
  8. da65 Users Guide
    https://cc65.github.io/doc/da65.html
  9. Překladače jazyka C pro historické osmibitové mikroprocesory
    https://www.root.cz/clanky/prekladace-jazyka-c-pro-historicke-osmibitove-mikroprocesory/
  10. Překladače programovacího jazyka C pro historické osmibitové mikroprocesory (2)
    https://www.root.cz/clanky/prekladace-programovaciho-jazyka-c-pro-historicke-osmibitove-mikroprocesory-2/
  11. Getting Started Programming in C: Coding a Retro Game with C Part 2
    https://retrogamecoders.com/getting-started-with-c-cc65/
  12. NES game development in 6502 assembly – Part 1
    https://kibrit.tech/en/blog/nes-game-development-part-1
  13. NES 6502 Programming Tutorial – Part 1: Getting Started
    https://dev.xenforo.relay­.cool/index.php?threads/nes-6502-programming-tutorial-part-1-getting-started.858389/
  14. Minimal NES example using ca65
    https://github.com/bbbradsmith/NES-ca65-example
  15. List of 6502-based Computers and Consoles
    https://www.retrocompute.co.uk/list-of-6502-based-computers-and-consoles/
  16. 6502 – the first RISC µP
    http://ericclever.com/6500/
  17. 3 Generations of Game Machine Architecture
    http://www.atariarchives.or­g/dev/CGEXPO99.html
  18. “Hello, world” from scratch on a 6502 — Part 1
    https://www.youtube.com/wat­ch?v=LnzuMJLZRdU
  19. A Tour of 6502 Cross-Assemblers
    https://bumbershootsoft.wor­dpress.com/2016/01/31/a-tour-of-6502-cross-assemblers/
  20. Adventures with ca65
    https://atariage.com/forum­s/topic/312451-adventures-with-ca65/
  21. example ca65 startup code
    https://atariage.com/forum­s/topic/209776-example-ca65-startup-code/
  22. 6502 PRIMER: Building your own 6502 computer
    http://wilsonminesco.com/6502primer/
  23. 6502 Instruction Set
    https://www.masswerk.at/6502/6502_in­struction_set.html
  24. Chip Hall of Fame: MOS Technology 6502 Microprocessor
    https://spectrum.ieee.org/tech-history/silicon-revolution/chip-hall-of-fame-mos-technology-6502-microprocessor
  25. Single-board computer
    https://en.wikipedia.org/wiki/Single-board_computer
  26. www.6502.org
    http://www.6502.org/
  27. 6502 PRIMER: Building your own 6502 computer – clock generator
    http://wilsonminesco.com/6502pri­mer/ClkGen.html
  28. Great Microprocessors of the Past and Present (V 13.4.0)
    http://www.cpushack.com/CPU/cpu.html
  29. Jak se zrodil procesor?
    https://www.root.cz/clanky/jak-se-zrodil-procesor/
  30. Osmibitové mikroprocesory a mikrořadiče firmy Motorola (1)
    https://www.root.cz/clanky/osmibitove-mikroprocesory-a-mikroradice-firmy-motorola-1/
  31. Mikrořadiče a jejich použití v jednoduchých mikropočítačích
    https://www.root.cz/clanky/mikroradice-a-jejich-pouziti-v-jednoduchych-mikropocitacich/
  32. Mikrořadiče a jejich aplikace v jednoduchých mikropočítačích (2)
    https://www.root.cz/clanky/mikroradice-a-jejich-aplikace-v-jednoduchych-mikropocitacich-2/
  33. 25 Microchips That Shook the World
    https://spectrum.ieee.org/tech-history/silicon-revolution/25-microchips-that-shook-the-world
  34. Comparison of instruction set architectures
    https://en.wikipedia.org/wi­ki/Comparison_of_instructi­on_set_architectures
  35. How To Start Learning Atari 8 Bit Assembly For Free
    https://forums.atariage.com/to­pic/300732-how-to-start-learning-atari-8-bit-assembly-for-free/
  36. WUDSN (Demo Group)
    https://www.wudsn.com/
  37. Machine Language For Beginners
    https://www.atariarchives.org/mlb/
  38. Assembly language: all about I/O
    https://www.atarimagazines­.com/v3n8/AllAbout_IO.html
  39. Sedmdesátiny assemblerů: lidsky čitelný strojový kód
    https://www.root.cz/clanky/sed­mdesatiny-assembleru-lidsky-citelny-strojovy-kod/
  40. Color names
    https://atariwiki.org/wiki/Wi­ki.jsp?page=Color%20names
  41. ATASCII
    https://en.wikipedia.org/wiki/ATASCII
  42. Put characters in display ram isn't ATASCII?
    https://forums.atariage.com/to­pic/359973-put-characters-in-display-ram-isnt-atascii/
  43. ATASCII And Internal Character Code Values
    https://www.atariarchives­.org/mapping/appendix10.php
  44. Reading ATASCII from the keyboard in assembly
    https://forums.atariage.com/to­pic/361733-reading-atascii-from-the-keyboard-in-assembly/
  45. Why does the 6502 JSR instruction only increment the return address by 2 bytes?
    https://retrocomputing.stac­kexchange.com/questions/19543/why-does-the-6502-jsr-instruction-only-increment-the-return-address-by-2-bytes
  46. Pushing return address to stack off by 1 byte
    https://forums.atariage.com/to­pic/378206-pushing-return-address-to-stack-off-by-1-byte/
  47. Intel x86 documentation has more pages than the 6502 has transistors
    https://www.righto.com/2013/09/intel-x86-documentation-has-more-pages.html
  48. Clearing a Section of Memory
    http://www.6502.org/source/ge­neral/clearmem.htm
  49. Practical Memory Move Routines by Bruce Clark
    http://www.6502.org/source/ge­neral/memory_move.html
  50. 6502 Assembly Programming Guide
    https://neumont-gamedev.github.io/posts/retrogamedev-6502-guide/
  51. Off-by-one error
    https://en.wikipedia.org/wiki/Off-by-one_error
  52. 6502 cycle times
    https://www.nesdev.org/wi­ki/6502_cycle_times
  53. Atari TIA
    http://www.atarihq.com/danb/tia.shtml
  54. TIA Playfield
    http://www.atarihq.com/dan­b/TIA/Playfield.shtml
  55. Atari Inc.:
    ANTIC C012296 (NTSC) Revision D
    Atari Incorporated, Sunnyvale CA, 1982
  56. Atari Inc.:
    GTIA C014805 (NTSC) Revision A
    Atari Incorporated, Sunnyvale CA, 1982
  57. Atari 5200
    http://www.atariage.com/sof­tware_search.html?SystemID=5200
  58. Atari 5200 Hardware and Accessories
    http://www.atariage.com/5200/ar­chives/hardware.html
  59. Atari 5200 Screenshots
    http://www.atariage.com/sys­tem_items.html?SystemID=5200&I­temTypeID=SCREENSHOT
  60. History of video game consoles (second generation): Wikipedia
    http://en.wikipedia.org/wi­ki/History_of_video_game_con­soles_(second_generation)
  61. Atari 5200: Wikipedia
    http://en.wikipedia.org/wi­ki/Atari_5200
  62. Player-Missile Graphics
    https://www.atariarchives­.org/agagd/chapter5.php
  63. Sprite (computer graphics)
    https://en.wikipedia.org/wi­ki/Sprite_(computer_graphic­s)
  64. Atari Graphics Demonstrations by Underground Software, 1985 | Atari 8 bit Demo
    https://www.youtube.com/wat­ch?v=h7N9EYSyCkw
  65. Atari 8-bit Display List Interrupts: A Complete(ish) Tutorial
    https://playermissile.com/dli_tu­torial/
  66. Atari Assembler Editor manual
    https://atariwiki.org/wiki/at­tach/Atari%20Assembler%20E­ditor/ATARI%20Assembler%20E­ditor%20User-s%20Manual-OCR.pdf
Neutrální ikona do widgetu na odběr článků ze seriálů

Zajímá vás toto téma? Chcete se o něm dozvědět víc?

Objednejte si upozornění na nově vydané články do vašeho mailu. Žádný článek vám tak neuteče.


Autor článku

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