Další tipy a triky při práci s čipem GTIA a využití joysticku

2. 4. 2026
Doba čtení: 45 minut

Sdílet

Projekt Atari perex.
Autor: Michal Tauchman, podle licence: CC BY-SA 4.0
Projekt Atari perex.
V šestém článku o vývoji programů pro osmibitové počítače Atari si popíšeme další možnosti čipu GTIA. Nejprve postavičky na obrazovce rozhýbeme, potom je začneme ovládat joystickem a nakonec vytvoříme pátého hráče.

Horizontální posun spritů po ploše obrazovky

Co se dozvíte v článku
  1. Horizontální posun spritů po ploše obrazovky
  2. Automatický pohyb prvního hráče, koncept čekací smyčky
  3. Úplný zdrojový kód dnešního prvního demonstračního příkladu
  4. Čekání na konec vykreslování snímku
  5. Úplný zdrojový kód dnešního druhého demonstračního příkladu
  6. Posun hráče pomocí joysticku
  7. Nové užitečné instrukce: přesuny dat mezi registry
  8. Korektní realizace posunu hráče pomocí joysticku
  9. Úplný zdrojový kód dnešního třetího demonstračního příkladu
  10. Zobrazení všech čtyř střel společně s hráči
  11. Úplný zdrojový kód dnešního čtvrtého demonstračního příkladu
  12. Čtyři střely nebo pátý hráč?
  13. Úplný zdrojový kód dnešního pátého demonstračního příkladu
  14. Povolení pátého hráče
  15. Úplný zdrojový kód dnešního šestého demonstračního příkladu
  16. Detekce stisku tlačítka joysticku, reakce na stisk tlačítka
  17. Příloha A: Seznam všech doposud popsaných instrukcí mikroprocesoru MOS 6502
  18. Příloha B: Makefile pro překlad všech demonstračních příkladů
  19. Repositář s demonstračními příklady
  20. Odkazy na Internetu

Připomeňme si, že čip GTIA umožňuje horizontální posun spritů po ploše obrazovky. Pro tento účel se používá osm registrů vypsaných v následující tabulce:

Registr Režim Význam
HPOSP0 W horizontální pozice hráče číslo 0
HPOSP1 W horizontální pozice hráče číslo 1
HPOSP2 W horizontální pozice hráče číslo 2
HPOSP3 W horizontální pozice hráče číslo 3
HPOSM0 W horizontální pozice střely číslo 0
HPOSM1 W horizontální pozice střely číslo 1
HPOSM2 W horizontální pozice střely číslo 2
HPOSM3 W horizontální pozice střely číslo 3

Každý z těchto registrů obsahuje osmibitovou hodnotu, což znamená rozsah 0 až 255. Ovšem okolo herního pole jsou okraje a samotné herní pole má šířku 320 pixelů (v nejvyšším rozlišení). Jak se tedy mapuje horizontální pozice spritu a pozice pixelu herního pole? Používá se tento vzoreček:

x_screen = (x_sprite - 48) * 2

Pro grafické režimy se 160 pixely na řádku je to ještě jednodušší:

x_screen = x_sprite - 48

Automatický pohyb prvního hráče, koncept čekací smyčky

V dnešním prvním demonstračním příkladu je realizován horizontální posun prvního hráče. Hráč se neustále pohybuje doprava (s přetečením na levý okraj), což lze programově realizovat velmi snadno pomocí nekonečné smyčky, ve které je horizontální pozice hráče uložena v akumulátoru:

        lda #80                 ; výchozí pozice prvního hráče
loop:
        jsr wait                ; počkáme určitou dobu
        sec
        adc #0
        sta HPOSP0              ; změna pozice prvního hráče
        jmp loop
Poznámka: bylo by ovšem možné použít i jiný registr, kde je snadnější přičítání jedničky operací INX nebo INY. Tuto optimalizaci nyní ponechám na váženém čtenáři.

Zajímavá je realizace podprogramu pro pozastavení výpočtů, který je nazvaný wait. Ten je naprogramován formou vnořené čekací smyčky, protože osmibitové pracovní registry mají nedostatečný rozsah pro čekání s využitím smyčky jediné (doba čekání je totiž velmi krátká). Proto je použita vnější smyčka s počitadlem Y a vnitřní smyčka, která je zopakována 256× (začínáme nulou, ta se ovšem ihned zmenšuje na 255):

.proc wait
        ldy #50
wait1:                          ; vnější čekací smyčka
        ldx #0
wait2:                          ; vnitřní čekací smyčka
        dex                     ; počitadlo vnitřní smyčky
        bne wait2
        dey                     ; počitadlo vnější smyčky
        bne wait1
        rts                     ; návrat ze subrutiny
.endproc
Poznámka: tento podprogram „ničí“ oba index registry X a Y, na což je zapotřebí myslet při jeho volání.

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

Obě techniky popsané v předchozí kapitole byly použity v dnešním prvním demonstračním příkladu. Příklad vykreslí všechny čtyři hráče a poté začne postupně měnit horizontální pozici hráče prvního:

Automatický horizontální posun prvního hráče.

Obrázek 1: Automatický horizontální posun prvního hráče. 

Autor: tisnik, podle licence: Rights Managed

Automatický horizontální posun prvního hráče.

Obrázek 2: Automatický horizontální posun prvního hráče: překryv prvního a druhého hráče.

Autor: tisnik, podle licence: Rights Managed

Automatický horizontální posun prvního hráče.

Obrázek 3: Automatický horizontální posun prvního hráče: překryv prvního a čtvrtého hráče.

Autor: tisnik, podle licence: Rights Managed

Úplný zdrojový kód tohoto příkladu vypadá následovně:

; ---------------------------------------------------------------------
; Initializace PMG, povolení PMG, nastavení pozice, bitmapy a barvy všech
; objektů.
; ---------------------------------------------------------------------
 
.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
 
 
.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
 
        lda #80                 ; výchozí pozice prvního hráče
loop:
        jsr wait                ; počkáme určitou dobu
        sec
        adc #0
        sta HPOSP0              ; změna pozice prvního hráče
        jmp loop
 
.endproc
 
 
.proc wait
        ldy #50
wait1:                          ; vnější čekací smyčka
        ldx #0
wait2:                          ; vnitřní čekací smyčka
        dex                     ; počitadlo vnitřní smyčky
        bne wait2
        dey                     ; počitadlo vnější smyčky
        bne wait1
        rts                     ; návrat ze subrutiny
.endproc
 
 
; data
sprite:   .byte 24, 60, 126, 219, 255, 36, 90, 165
 
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

Čekání na konec vykreslování snímku

Zpomalení posunu hráče lze ovšem realizovat i jinak. Můžeme například čekat na dokončení vykreslování snímku. To lze realizovat buď přímo (ukážeme si to při programování čipu ANTIC), nebo můžeme čekat na jeden „tik“ vnitřních hodin. Jedná se o bajt uložený v nulté stránce paměti, který je automaticky zvyšován každých 1/60 nebo 1/50 sekundy operačním systémem (podle použité televizní normy). Samotná realizace takto pojaté čekací smyčky je vlastně jednoduchá – čekáme na změnu hodnoty přečtené z adresy RTCLOK+2:

.proc   _wait_vsync
        ldx     RTCLOK+2        ; čekání na konec snímku
@wt:    cpx     RTCLOK+2
        beq     @wt
        rts
.endproc
Poznámka: tento podprogram „ničí“ pouze index registr X, na což je ovšem opět zapotřebí myslet při jeho volání.
Zpožďovací smyčka je nyní založena na interních systémových hodinách.

Obrázek 4: Automatický horizontální posun prvního hráče, čekání na dokončení vykreslení obrazovky.

Autor: tisnik, podle licence: Rights Managed

Zpožďovací smyčka je nyní založena na interních systémových hodinách.

Obrázek 5: Automatický horizontální posun prvního hráče, čekání na dokončení vykreslení obrazovky.

Autor: tisnik, podle licence: Rights Managed

Zpožďovací smyčka je nyní založena na interních systémových hodinách.

Obrázek 6: Automatický horizontální posun prvního hráče, čekání na dokončení vykreslení obrazovky.

Autor: tisnik, podle licence: Rights Managed

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

Nová podoba demonstračního příkladu, který posune prvního hráče každé dva snímky obrazovky (rychlost 25 nebo 30 pixelů za sekundu), vypadá takto:

; ---------------------------------------------------------------------
; Initializace PMG, povolení PMG, nastavení pozice, bitmapy a barvy všech
; objektů. Posun prvního hráče s čekáním na další snímek.
; ---------------------------------------------------------------------
 
.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
 
 
.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
 
        lda #80                 ; výchozí pozice prvního hráče
loop:
        jsr _wait_vsync
        jsr _wait_vsync
        jsr _wait_vsync
 
        sec
        adc #0
        sta HPOSP0              ; změna pozice prvního hráče
        jmp loop
 
.endproc
 
 
.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
 
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

Posun hráče pomocí joysticku

V další fázi vylepšování příkladu s PMG budeme prvního hráče ovládat pomocí joysticku. Prozatím dokážeme hráčem pohybovat doleva a doprava, takže se omezíme pouze na tyto dva směry. Můžeme se pokusit naprogramovat první variantu programové smyčky, ve které na základě náklonu joysticku zvýšíme nebo naopak snížíme hodnotu index registru X, který obsahuje horizontální pozici hráče. Vysokoúrovňová varianta vypadá takto:

        ldx #80                 ; výchozí pozice prvního hráče
loop:
        if joystick vlevo  -> dex
        if joystick vpravo -> inx
        stx HPOSP0              ; změna pozice prvního hráče
        jmp loop

Nyní musíme dopsat realizaci podmínek. Stav prvního joysticku je uložen v hardwarovém registru STICK0, přičemž náklon joysticku je zakódován následovně (binární zápis ukazuje, že je v kódech určitá logika – každý směr je zakódován jedním znegovaným bitem):

  Decimálně                   Binárně
 
       14                       1110
        |                         |
    10  | 6                 1010  | 0110
      \ |/                      \ |/
  11-- 15 ---7           1011-- 1111 --0111
      / |\                      / |\
     9  | 5                 1001  | 0101
        |                         |
       13                       1101

My tedy budeme rozpoznávat pouze kódy 11 a 7. Realizace posunu hráče je vlastně velmi jednoduchá a omezuje se na dvojici instrukcí CMP+BNE (test na hodnotu a skok, pokud je hodnota odlišná od hodnoty porovnávané):

        ldx #80                 ; výchozí pozice prvního hráče
loop:
        jsr _wait_vsync
        jsr _wait_vsync
 
        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
        jmp loop
Poznámka: sice to není vidět a assembler nás na to upozorní, ovšem příklad nebude funkční, protože obsah registru X je „zničen“ v subrutině _wait_vsync. Musíme tedy najít jiné řešení (a v rámci tréninku předpokládejme, že není možné použít ani akumulátor, ani registr Y).

Nové užitečné instrukce: přesuny dat mezi registry

V souvislosti s rostoucí komplexností programů se začínají využívat všechny pracovní registry mikroprocesoru MOS 6502. Musíme se tedy seznámit s instrukcemi určenými pro přenos hodnot mezi těmito registry. Tyto instrukce (je jich oficiálně pouze šest) začínají znakem T a obsahují svůj význam přímo v mnemotechnické zkratce instrukce (nemají tedy žádné parametry – zapomeňte na univerzální MOV, u kterého není zřejmé, co je zdrojem a co cílem):

# Instrukce Plné jméno Popis
40 TAX transfer accumulator to X přesun hodnoty z akumulátoru do index registru X
41 TAY transfer accumulator to Y přesun hodnoty z akumulátoru do index registru Y
42 TXA transfer X to accumulator přesun hodnoty z index registru X do akumulátoru
43 TYA transfer Y to accumulator přesun hodnoty z index registru Y do akumulátoru
44 TSX transfer stack pointer to X přesun ukazatele vrcholu zásobníku do index registru X
45 TXS transfer X to stack pointer přesun hodnoty z index registru X do ukazatele vrcholu zásobníku
Poznámka: jak je pro MOS 6502 (a pro mnohé další osmibitové mikroprocesory) typické, není instrukční sada plně ortogonální, což například znamená, že neexistuje přímá instrukce určená pro přesun hodnoty z index registru X do index registru Y (nebo naopak). A přesuny hodnoty ukazatele vrcholu zásobníku se provádí pouze s index registrem X. O to je programování zajímavější.

Korektní realizace posunu hráče pomocí joysticku

Se znalostí instrukcí pro přesuny dat můžeme celou smyčku realizující posun hráče s využitím joysticku upravit. Před voláním subrutiny _wait_vsync uložíme obsah index registru X do akumulátoru a poté ho opět obnovíme (TXA+TAX). Nemusíme se tedy starat o zásobník ani o uložení do operační paměti:

        ldx #80                 ; výchozí pozice prvního hráče
loop:
        txa                     ; uložení obsahu X do akumulátoru
        jsr _wait_vsync
        jsr _wait_vsync
        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
        jmp loop
Poznámka: říkal někdo, že tři registry nestačí?

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

Výše uvedenou programovou smyčku můžeme bez dalších úprav přidat do nové verze demonstračního příkladu, jehož úplný zdrojový kód vypadá následovně:

; ---------------------------------------------------------------------
; Ovládání PMG joystickem.
; ---------------------------------------------------------------------
 
.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
 
 
.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
 
        ldx #80                 ; výchozí pozice prvního hráče
loop:
        txa                     ; uložení obsahu X do akumulátoru
        jsr _wait_vsync
        jsr _wait_vsync
        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
        jmp loop
 
.endproc
 
 
.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
 
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

Zobrazení všech čtyř střel společně s hráči

Připomeňme si, že kromě čtyř hráčů o šířce osmi pixelů a výšce 128 nebo 256 pixelů je možné čipem GTIA ovládat i takzvané střely (missiles), které mají šířku pouhé dva pixely. Tvary všech čtyř střel jsou uloženy v jediném bloku (128 nebo 256 bajtů), a to konkrétně od offsetu 384 v rámci adresového rozsahu 0..1024, který vyhradíme pro sprity:

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
MISSILES_OFFSET = 384

Řídit je možné horizontální pozice všech čtyř střel, a to nezávisle na hráčích a nezávisle na ostatních střelách:

Registr Režim Význam
HPOSM0 W horizontální pozice střely číslo 0
HPOSM1 W horizontální pozice střely číslo 1
HPOSM2 W horizontální pozice střely číslo 2
HPOSM3 W horizontální pozice střely číslo 3

Ovšem barva střel je závislá na barvě hráčů (nebo naopak), což je patrné i z následujícího screenshotu:

Zobrazení čtyř hráčů i čtyř střel.

Obrázek 7: Čtyři hráči a čtyři střely. 

Autor: tisnik, podle licence: Rights Managed

Poznámka: první hráč má stejnou barvu jako první střela, dtto pro druhého, třetího a čtvrtého hráče.

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

Další úprava demonstračního příkladu spočívá v přidání všech čtyř střel na obrazovku. Povšimněte si, že každá střela je skutečně široká pouze dva pixely a tudíž každé střele odpovídají jen dva bity z bitmapy 8×128 nebo 8×256 pixelů. Navíc je patrné, že střely mají stejnou barvu jako odpovídající hráči:

; ---------------------------------------------------------------------
; Ovládání PMG joystickem.
; ---------------------------------------------------------------------
 
.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
MISSILES_OFFSET = 384
 
 
.proc main
        lda #80                 ; horizontální pozice prvního hráče
        sta HPOSP0              ; uložit do řídicího registru HPOSP0 na čipu GTIA
 
        lda #95                 ; horizontální pozice druhého hráče
        sta HPOSP1              ; uložit do řídicího registru HPOSP1 na čipu GTIA
 
        lda #110                ; horizontální pozice třetího hráče
        sta HPOSP2              ; uložit do řídicího registru HPOSP2 na čipu GTIA
 
        lda #125                ; horizontální pozice čtvrtého hráče
        sta HPOSP3              ; uložit do řídicího registru HPOSP3 na čipu GTIA
 
        lda #140                ; horizontální pozice první střely
        sta HPOSM0              ; uložit do řídicího registru HPOSP0 na čipu GTIA
 
        lda #150                ; horizontální pozice druhé střely
        sta HPOSM1              ; uložit do řídicího registru HPOSP1 na čipu GTIA
 
        lda #160                ; horizontální pozice třetí střely
        sta HPOSM2              ; uložit do řídicího registru HPOSP2 na čipu GTIA
 
        lda #170                ; horizontální pozice čtvrté střely
        sta HPOSM3              ; 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áč
        sta addr+MISSILES_OFFSET+50, x  ; uložit byte - střely
        dex                     ; snížit offset + nastavit příznaky
        bne next_line           ; další byte spritu
 
        lda #46                 ; povolení PMG DMA
        sta SDMCTL
 
        ldx #80                 ; výchozí pozice prvního hráče
loop:
        txa                     ; uložení obsahu X do akumulátoru
        jsr _wait_vsync
        jsr _wait_vsync
        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
        jmp loop
 
.endproc
 
 
.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
 
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

Čtyři střely nebo pátý hráč?

Vzhledem k tomu, že střely mají šířku dvou pixelů a celkem je možné zobrazit čtyři střely, nabízí se otázka, jestli z nich nelze vytvořit „pátého hráče“. Prvním krokem k pátému hráči je horizontální posun střel takovým způsobem, aby od sebe byly posunuty přesně o dva pixely a současně byly uspořádány zleva doprava v pořadí M3+M2+M1+M0:

        lda #146                ; horizontální pozice první střely
        sta HPOSM0              ; uložit do řídicího registru HPOSP0 na čipu GTIA

        lda #144                ; horizontální pozice druhé střely
        sta HPOSM1              ; uložit do řídicího registru HPOSP1 na čipu GTIA

        lda #142                ; horizontální pozice třetí střely
        sta HPOSM2              ; uložit do řídicího registru HPOSP2 na čipu GTIA

        lda #140                ; horizontální pozice čtvrté střely
        sta HPOSM3              ; uložit do řídicího registru HPOSP3 na čipu GTIA

Výsledkem je „něco“, co se podobá duhovému pátému hráči:

Čtyři střely umístěné přesně tak, aby zdánlivě tvořily pátého hráče.

Obrázek 8: Čtyři střely umístěné tak, aby simulovaly pátého hráče. 

Autor: tisnik, podle licence: Rights Managed

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

Opět si pro úplnost ukažme úplný zdrojový kód dnešního pátého demonstračního příkladu, jenž vypadá následovně:

; ---------------------------------------------------------------------
; Ovládání PMG joystickem.
; ---------------------------------------------------------------------
 
.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
MISSILES_OFFSET = 384
 
 
.proc main
        lda #80                 ; horizontální pozice prvního hráče
        sta HPOSP0              ; uložit do řídicího registru HPOSP0 na čipu GTIA
 
        lda #95                 ; horizontální pozice druhého hráče
        sta HPOSP1              ; uložit do řídicího registru HPOSP1 na čipu GTIA
 
        lda #110                ; horizontální pozice třetího hráče
        sta HPOSP2              ; uložit do řídicího registru HPOSP2 na čipu GTIA
 
        lda #125                ; horizontální pozice čtvrtého hráče
        sta HPOSP3              ; uložit do řídicího registru HPOSP3 na čipu GTIA
 
        lda #146                ; horizontální pozice první střely
        sta HPOSM0              ; uložit do řídicího registru HPOSP0 na čipu GTIA
 
        lda #144                ; horizontální pozice druhé střely
        sta HPOSM1              ; uložit do řídicího registru HPOSP1 na čipu GTIA
 
        lda #142                ; horizontální pozice třetí střely
        sta HPOSM2              ; uložit do řídicího registru HPOSP2 na čipu GTIA
 
        lda #140                ; horizontální pozice čtvrté střely
        sta HPOSM3              ; 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áč
        sta addr+MISSILES_OFFSET+50, x  ; uložit byte - střely
        dex                     ; snížit offset + nastavit příznaky
        bne next_line           ; další byte spritu
 
        lda #46                 ; povolení PMG DMA
        sta SDMCTL
 
        ldx #80                 ; výchozí pozice prvního hráče
loop:
        txa                     ; uložení obsahu X do akumulátoru
        jsr _wait_vsync
        jsr _wait_vsync
        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
        jmp loop
 
.endproc
 
 
.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
 
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

Povolení pátého hráče

V tomto seriálu jsme se již několikrát setkali s řídicím registrem GPRIOR. Podle názvu se jedná o registr řídicí prioritu spritů a herního pole, ovšem k tomuto účelu slouží jen spodní čtyři bity. Šestý bit již známe – zapíná operaci OR barev spritů, pokud se překrývají. Ovšem zajímavý je i pátý bit, který zapíná „pátého hráče“:

        lda #16                 ; priorita hráčů a pozadí -> povolení pátého hráče
        sta GPRIOR              ; uložit do řídicího registru GPRIOR na čipu GTIA

Pátý hráč se sice skládá ze čtyř střel, ovšem bude mít jednotnou barvu zapisovanou do registru COLOR3 (POZOR: to je změna, toto je registr s více významy):

        lda #HUE_YELLOWRED<<4 + 8   ; barva pátého hráče (odstín+intenzita)
        sta COLOR3              ; uložit do řídicího registru COLPF3 na čipu GTIA

Výsledek bude vypadat takto:

Čtyři střely mají stejnou barvu a tvoří tak (do jisté míry) pátého hráče.

Obrázek 9: Čtyři střely se shodnou barvou jsou považovány za pátého hráče.  

Autor: tisnik, podle licence: Rights Managed

Poznámka: ovšem stále platí, že horizontálním posunem střel můžeme pátého hráče „rozsekat“ na čtyři kousky, což se ostatně v některých hrách hodí pro různé efekty.

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

Dnešní předposlední demonstrační příklad vypadá takto:

; ---------------------------------------------------------------------
; Ovládání PMG joystickem.
; ---------------------------------------------------------------------
 
.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
MISSILES_OFFSET = 384
 
 
.proc main
        lda #80                 ; horizontální pozice prvního hráče
        sta HPOSP0              ; uložit do řídicího registru HPOSP0 na čipu GTIA
 
        lda #95                 ; horizontální pozice druhého hráče
        sta HPOSP1              ; uložit do řídicího registru HPOSP1 na čipu GTIA
 
        lda #110                ; horizontální pozice třetího hráče
        sta HPOSP2              ; uložit do řídicího registru HPOSP2 na čipu GTIA
 
        lda #125                ; horizontální pozice čtvrtého hráče
        sta HPOSP3              ; uložit do řídicího registru HPOSP3 na čipu GTIA
 
        lda #146                ; horizontální pozice první střely
        sta HPOSM0              ; uložit do řídicího registru HPOSP0 na čipu GTIA
 
        lda #144                ; horizontální pozice druhé střely
        sta HPOSM1              ; uložit do řídicího registru HPOSP1 na čipu GTIA
 
        lda #142                ; horizontální pozice třetí střely
        sta HPOSM2              ; uložit do řídicího registru HPOSP2 na čipu GTIA
 
        lda #140                ; horizontální pozice čtvrté střely
        sta HPOSM3              ; 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 #HUE_YELLOWRED<<4 + 8   ; barva pátého hráče (odstín+intenzita)
        sta COLOR3              ; uložit do řídicího registru COLPF3 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 #16                 ; priorita hráčů a pozadí -> povolení pátého hráče
        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áč
        sta addr+MISSILES_OFFSET+50, x  ; uložit byte - střely
        dex                     ; snížit offset + nastavit příznaky
        bne next_line           ; další byte spritu
 
        lda #46                 ; povolení PMG DMA
        sta SDMCTL
 
        ldx #80                 ; výchozí pozice prvního hráče
loop:
        txa                     ; uložení obsahu X do akumulátoru
        jsr _wait_vsync
        jsr _wait_vsync
        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
        jmp loop
 
.endproc
 
 
.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
 
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

Detekce stisku tlačítka joysticku, reakce na stisk tlačítka

V předchozím textu jsme si ukázali, jak lze zjistit náklon joysticku. Ještě nám zbývá detekce stisku tlačítka joysticku. To je snadné, protože stačí přečíst obsah registru STRIG0. Obsah tohoto registru je ovšem poněkud matoucí: jednička znamená, že tlačítko není stisknutu a nula naopak znamená detekci stisku. Snadno tedy můžeme realizovat například změnu barvy hráče stiskem tlačítka:

        lda STRIG0              ; 0=stisknuto (Z je nastaven)
        bne not_pressed         ; NE==NZ
 
        tya
        clc
        adc #16                 ; změna odstínu barvy, ne intenzity
        tay
        sty PCOLR0              ; modifikovat barvový registr
not_pressed:
Poznámka: povšimněte si, jak jsme se opět vyhnuli použití zásobníku – celý kód si stále vystačí s pouhými třemi pracovními registry!
Změna barvy prvního hráče s využitím tlačítka joysticku.

Obrázek 10: Změna barvy prvního hráče s využitím tlačítka joysticku.

Autor: tisnik, podle licence: Rights Managed

Změna barvy prvního hráče s využitím tlačítka joysticku.

Obrázek 11: Změna barvy prvního hráče s využitím tlačítka joysticku.

Autor: tisnik, podle licence: Rights Managed

Již naposledy si ukažme zdrojový kód:

; ---------------------------------------------------------------------
; Ovládání PMG joystickem.
; ---------------------------------------------------------------------
 
.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
MISSILES_OFFSET = 384
 
 
.proc main
        lda #80                 ; horizontální pozice prvního hráče
        sta HPOSP0              ; uložit do řídicího registru HPOSP0 na čipu GTIA
 
        lda #95                 ; horizontální pozice druhého hráče
        sta HPOSP1              ; uložit do řídicího registru HPOSP1 na čipu GTIA
 
        lda #110                ; horizontální pozice třetího hráče
        sta HPOSP2              ; uložit do řídicího registru HPOSP2 na čipu GTIA
 
        lda #125                ; horizontální pozice čtvrtého hráče
        sta HPOSP3              ; uložit do řídicího registru HPOSP3 na čipu GTIA
 
        lda #146                ; horizontální pozice první střely
        sta HPOSM0              ; uložit do řídicího registru HPOSP0 na čipu GTIA
 
        lda #144                ; horizontální pozice druhé střely
        sta HPOSM1              ; uložit do řídicího registru HPOSP1 na čipu GTIA
 
        lda #142                ; horizontální pozice třetí střely
        sta HPOSM2              ; uložit do řídicího registru HPOSP2 na čipu GTIA
 
        lda #140                ; horizontální pozice čtvrté střely
        sta HPOSM3              ; 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 #HUE_YELLOWRED<<4 + 8   ; barva pátého hráče (odstín+intenzita)
        sta COLOR3              ; uložit do řídicího registru COLPF3 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 #16                 ; priorita hráčů a pozadí -> povolení pátého hráče
        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áč
        sta addr+MISSILES_OFFSET+50, x  ; uložit byte - střely
        dex                     ; snížit offset + nastavit příznaky
        bne next_line           ; další byte spritu
 
        lda #46                 ; povolení PMG DMA
        sta SDMCTL
 
        ldy #14                 ; barva prvního hráče
        ldx #80                 ; výchozí pozice prvního hráče
loop:
        txa                     ; uložení obsahu X do akumulátoru
        jsr _wait_vsync
        jsr _wait_vsync
        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
 
        lda STRIG0              ; 0=stisknuto (Z je nastaven)
        bne not_pressed         ; NE==NZ
 
        tya
        clc
        adc #16                 ; změna odstínu barvy, ne intenzity
        tay
        sty PCOLR0              ; modifikovat barvový registr
not_pressed:
 
       jmp loop
 
.endproc
 
 
.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
 
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

Příloha A: Seznam všech doposud popsaných instrukcí mikroprocesoru MOS 6502

Všechny doposud popsané instrukce mikroprocesoru MOS 6502 jsou vypsány v následující tabulce (oproti minulému článku se seznam instrukcí rozšířil):

# Instrukce Plné jméno Popis
1 ADC add with carry součet hodnoty s akumulátorem (včetně přetečení)
2 SBC subtract with carry odečtení hodnoty od akumulátoru (včetně výpůjčky)
       
3 AND and with accumulator logické AND s akumulátorem
4 ORA or with accumulator logické OR s akumulátorem
5 EOR exclusive or with accumulator logické XOR s akumulátorem
       
6 INC increment zvýšení hodnoty o 1 (kupodivu nelze s akumulátorem, ovšem s pamětí ano)
7 INX increment X zvýšení hodnoty index registru X o 1
8 INY increment Y zvýšení hodnoty index registru Y o 1
9 DEC decrement snížení hodnoty o 1 (opět nelze s akumulátorem)
10 DEX decrement X snížení hodnoty index registru X o 1
11 DEY decrement Y snížení hodnoty index registru Y o 1
       
12 CMP compare with accumulator odečtení hodnoty od akumulátoru bez zápisu výsledku
13 CPX compare with X odečtení hodnoty od index registru X bez zápisu výsledku
14 CPY compare with Y odečtení hodnoty od index registru Y bez zápisu výsledku
15 BIT bit test logické AND bez uložení výsledků (změní se jen příznakové bity)
       
16 ASL arithmetic shift left aritmetický posun doleva o jeden bit
17 LSR logical shift right logický posun doprava o jeden bit
18 ROL rotate left rotace doleva o jeden bit
19 ROR rotate right rotace doprava o jeden bit
       
20 JMP jump skok (existuje několik adresovacích režimů)
21 JSR jump to subroutine skok do podprogramu s uložením návratové adresy na zásobník
22 RTS return from subroutine návrat z podprogramu
23 RTI return from interrupt návrat z prerušovací rutiny
       
24 BCC branch on carry clear rozvětvení za podmínky C==0
25 BCS branch on carry set rozvětvení za podmínky C==1
26 BEQ branch on equal (zero set) rozvětvení za podmínky Z==1
27 BMI branch on minus (negative set) rozvětvení za podmínky N==1
28 BNE branch on not equal (zero clear) rozvětvení za podmínky Z==0
29 BPL branch on plus (negative clear) rozvětvení za podmínky N==0
30 BVC branch on overflow clear rozvětvení za podmínky O==0
31 BVS branch on overflow set rozvětvení za podmínky O==1
       
32 PHA push accumulator on stack uložení obsahu akumulátoru na zásobník
33 PLA pull accumulator from stack obnovení obsahu akumulátoru ze zásobníku
       
34 LDA load accumulator načtení hodnoty do akumulátoru
35 LDX load X register načtení hodnoty do index registru X
36 LDY load Y register načtení hodnoty do index registru Y
37 STA store accumulator uložení akumulátoru
38 STX store X register uložení index registru X
39 STY store Y register uložení index registru Y
       
40 TAX transfer accumulator to X přesun hodnoty z akumulátoru do index registru X
41 TAY transfer accumulator to Y přesun hodnoty z akumulátoru do index registru Y
42 TXA transfer X to accumulator přesun hodnoty z index registru X do akumulátoru
43 TYA transfer Y to accumulator přesun hodnoty z index registru Y do akumulátoru
44 TSX transfer stack pointer to X přesun ukazatele vrcholu zásobníku do index registru X
45 TXS transfer X to stack pointer přesun hodnoty z index registru X do ukazatele vrcholu zásobníku

Příloha B: 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í Zabbix

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_stick_1.xex         pmg_stick_2.xex \
         pmg_stick_3.xex         pmg_stick_4.xex \
         pmg_stick_5.xex
 
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
 

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 chars.bas tisk všech znaků na obrazovku (varianta naprogramovaná v BASICu) https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/chars.bas

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



Nejnovější články