Práce se sprity: čip GTIA
Co se dozvíte v článku
- Práce se sprity: čip GTIA
- Řídicí a stavové registry čipu GTIA
- Praktické příklady využití čipu GTIA při práci se sprity
- Inicializace PMG, povolení PMG, nastavení pozice a globálního tvaru prvního hráče
- Úplný zdrojový kód prvního demonstračního příkladu
- Nastavení barvy prvního hráče
- Zákaz DMA, pokud se mají zobrazit jen globální tvary hráčů
- Modifikace šířky hráčů
- Změna globálního tvaru hráče
- Priority PMG vůči hracímu poli a pozadí
- Zobrazení dvou překrývajících se hráčů současně, režim „multicolor“
- Nastavení bitmapy spritů (hráčů i střel)
- Demonstrační příklad: naivní nastavení bitmapy prvního hráče
- Přečtení bitmapy (tvaru) hráče z pole s daty
- Zobrazení čtyř hráčů současně se změnou priorit
- Nastavení bitmap všech čtyř hráčů
- Příloha A: Seznam všech doposud popsaných instrukcí mikroprocesoru MOS 6502
- Příloha B: Makefile pro překlad všech demonstračních příkladů
- Repositář s demonstračními příklady
- Odkazy na Internetu
Dnes navážeme na předchozí článek, ve kterém jsme se začali zabývat popisem grafického subsystému osmibitových Atari. Dnes si popíšeme způsob práce se sprity (pohyblivými objekty na obrazovce). Tento typ grafiky se u Atari nazývá PMG neboli Player-Missile Graphics. O zobrazení PMG se stará čip GTIA, jenž ideově vychází ze staršího čipu TIA.
Pro porovnání shodných vlastností a rozdílů mezi čipy TIA a GTIA se podívejme na následující dvojici tabulek. V první tabulce jsou vypsány grafické objekty, s nimiž dokázal pracovat původní čip TIA použitý v herní konzoli Atari 2600:
| # | Typ objektu | Orig.název | Objem paměti | Šířka reprezentovaná jedním bitem |
|---|---|---|---|---|
| 1 | Pozadí | Background | 0 bitů | × |
| 2 | Hrací plocha | Playground | 20 bitů | 4× základní šířka pixelu |
| 3 | Míč | Ball | 1 bit | 1×, 2×, 4×, 8× šířka pixelu |
| 4 | Hráč 0 | Player 0 | 8 bitů | 1×, 2×, 4× šířka pixelu |
| 5 | Střela 0 | Missile 0 | 1 bit | 1×, 2×, 4×, 8× šířka pixelu |
| 6 | Hráč 1 | Player 1 | 8 bitů | 1×, 2×, 4× šířka pixelu |
| 7 | Střela 1 | Missile 1 | 1 bit | 1×, 2×, 4×, 8× šířka pixelu |
Ve druhé tabulce jsou vypsány grafické objekty, s nimiž dokázal pracovat čip GTIA použitý v herní konzoli Atari 5200 i v prakticky všech osmibitových domácích počítačích Atari (pokud tedy nepočítáme prvních zhruba 100 000 počítačů Atari 400 a Atari 800 s čipy CTIA:
| # | Typ objektu | Orig.název | Objem paměti | Šířka reprezentovaná jedním bitem |
|---|---|---|---|---|
| 1 | Pozadí | Background | 0 bitů | barva v COLBK, přes celou šířku řádku |
| 2 | Hrací plocha | Playground | x bitů | generováno v ANTIC |
| 3 | Hráč 0 | Player 0 | 8 bitů×128/256 | 1×, 2×, 4× šířka pixelu |
| 4 | Střela 0 | Missile 0 | 2 bity×128/256 | 1×, 2×, 4×, 8× šířka pixelu |
| 5 | Hráč 1 | Player 1 | 8 bitů×128/256 | 1×, 2×, 4× šířka pixelu |
| 6 | Střela 1 | Missile 1 | 2 bity×128/256 | 1×, 2×, 4×, 8× šířka pixelu |
| 7 | Hráč 2 | Player 2 | 8 bitů×128/256 | 1×, 2×, 4× šířka pixelu |
| 8 | Střela 2 | Missile 2 | 2 bity×128/256 | 1×, 2×, 4×, 8× šířka pixelu |
| 9 | Hráč 3 | Player 3 | 8 bitů×128/256 | 1×, 2×, 4× šířka pixelu |
| 10 | Střela 3 | Missile 3 | 2 bity×128/256 | 1×, 2×, 4×, 8× šířka pixelu |
Řídicí a stavové registry čipu GTIA
Nejprve si uvedeme tabulku se všemi řídicími registry čipu GTIA. Ten byl řízen s využitím registrů, z nichž všechny byly určeny pro zápis a některé taktéž pro čtení, tj. například pro zjišťování kolizí atd. (při čtení mají jiné jméno, než při zápisu). Většina z těchto registrů (konkrétně všechny registry související s grafikou) je vypsána v následující tabulce. Tabulka obsahuje více než 32 položek, protože stejná adresa registru při čtení má jiný význam, než při zápisu:
| Registr | Režim | Význam |
|---|---|---|
| COLPM0 | W | barva hráče číslo 0 a střely číslo 0 |
| COLPM1 | W | barva hráče číslo 1 a střely číslo 1 |
| COLPM2 | W | barva hráče číslo 2 a střely číslo 2 |
| COLPM3 | W | barva hráče číslo 3 a střely číslo 3 |
| COLPF0 | W | barva pro herní pole číslo 0 |
| COLPF1 | W | barva pro herní pole číslo 1 |
| COLPF2 | W | barva pro herní pole číslo 2 |
| COLPF3 | W | barva pro herní pole číslo 3 |
| COLBK | W | barva pozadí |
| 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 |
| SIZEP0 | W | horizontální zvětšení hráče číslo 0 (1×, 2×, 4×) |
| SIZEP1 | W | horizontální zvětšení hráče číslo 1 (1×, 2×, 4×) |
| SIZEP2 | W | horizontální zvětšení hráče číslo 2 (1×, 2×, 4×) |
| SIZEP3 | W | horizontální zvětšení hráče číslo 3 (1×, 2×, 4×) |
| SIZEM | W | horizontální zvětšení všech střel (1×, 2×, 4×) |
| GRAFP0 | W | bitová data pro hráče číslo 0 |
| GRAFP1 | W | bitová data pro hráče číslo 1 |
| GRAFP2 | W | bitová data pro hráče číslo 2 |
| GRAFP3 | W | bitová data pro hráče číslo 3 |
| GRAFM | W | bitová data pro všechny střely |
| PRIOR | W | řízení priority objektů a taktéž výběr grafického režimu |
| GRACTL | W | povolení PMG |
| M0PF | R | kolizní registr mezi střelou číslo 0 a herním polem |
| M1PF | R | kolizní registr mezi střelou číslo 1 a herním polem |
| M2PF | R | kolizní registr mezi střelou číslo 2 a herním polem |
| M3PF | R | kolizní registr mezi střelou číslo 3 a herním polem |
| P0PF | R | kolizní registr mezi hráčem číslo 0 a herním polem |
| P1PF | R | kolizní registr mezi hráčem číslo 1 a herním polem |
| P2PF | R | kolizní registr mezi hráčem číslo 2 a herním polem |
| P3PF | R | kolizní registr mezi hráčem číslo 3 a herním polem |
| M0PL | R | kolizní registr mezi střelou číslo 0 a hráčem |
| M1PL | R | kolizní registr mezi střelou číslo 1 a hráčem |
| M2PL | R | kolizní registr mezi střelou číslo 2 a hráčem |
| M3PL | R | kolizní registr mezi střelou číslo 3 a hráčem |
| P0PL | R | kolizní registr mezi hráčem číslo 0 a dalším hráčem |
| P1PL | R | kolizní registr mezi hráčem číslo 1 a dalším hráčem |
| P2PL | R | kolizní registr mezi hráčem číslo 2 a dalším hráčem |
| P3PL | R | kolizní registr mezi hráčem číslo 3 a dalším hráčem |
Praktické příklady využití čipu GTIA při práci se sprity
Práci se sprity si ukážeme na deseti demonstračních příkladech, přičemž další příklady budou ukázány v navazujícím článku. V dnešních příkladech bude ukázán způsob povolení zobrazení PMG, nastavení horizontálních souřadnic hráčů, nastavení jejich barvy, velikosti a tvaru (tj. způsobu zobrazení na obrazovce) a popíšeme si taktéž změnu priorit při zobrazování, tj. způsob řešení překryvu hráčů a střel s pozadím nebo mezi sebou navzájem.
Ovšem to ve skutečnosti není vše, co systém PMG na osmibitových Atari nabízí. Přímo na hardwarové úrovni je řešena i detekce kolizí, což může do značné míry urychlit algoritmy používané ve hrách (v podstatě se mohou zcela odstranit výpočty kolizí). Navíc je hardwarová detekce kolizí provedena s přesností na jednotlivé pixely, takže není nutné provádět optimalizace s využitím takzvaných bounding boxů atd. Ve výsledku může být práce s PMG velmi efektivní z hlediska celkové rychlosti her, a to i přesto, že je nutné softwarově řešit vertikální posuny (naopak například na počítačích Commodore C64 je i tento problém řešitelný přímo na úrovni hardware).
Inicializace PMG, povolení PMG, nastavení pozice a globálního tvaru prvního hráče
Na moderních počítačích a moderních operačních systémech může být inicializace grafiky (například ve hrách) relativně složitá, a to i přesto, že se používají různé vysokoúrovňové knihovny. Na osmibitových Atari tomu tak ovšem není, protože pro zobrazení hráče (řekněme prvního hráče s číslem 0) postačuje provést pouhé dvě operace, konkrétně dva zápisy do HW registrů čipu GTIA:
- Je nutné přenastavit horizontální pozici hráče, což je osmibitová hodnota, která se v případě prvního hráče zapisuje do registruHPOS0 (určeno jen pro zápis). Jaký je přesný vztah mezi pozicí hráče a pixelem herního pole, se dozvíme příště.
- Taktéž je nutné nastavit bitmapu hráče (má rozlišení 8×128 pixelů), a to buď přímo změnou bitmapy (ukážeme si v dalších kapitolách) nebo zápisem osmi bitů do registru GRAFP0. Tím se nastaví všechny řádky bitmapy na stejnou hodnotu. Bit s hodnotou 1 znamená „kreslí se barva hráče“, nulový bit znamená „pixel je průhledný, tj. kreslí se barva pod hráčem“.
Úplný zdrojový kód prvního demonstračního příkladu
V dnešním prvním demonstračním příkladu nastavíme horizontální pozici hráče na hodnotu 128 (blízko středu obrazovky) a jeho tvar na samé jedničky, takže všechny pixely hráče budou zobrazeny jeho barvou.
Úplný zdrojový kód dnešního prvního demonstračního příkladu, od něhož budou odvozeny i všechny další příklady, vypadá následovně:
; ---------------------------------------------------------------------
; Initializace PMG, povolení PMG, nastavení pozice a tvaru prvního hráče.
; ---------------------------------------------------------------------
.include "atari.inc"
.CODE
.proc main
lda #128 ; horizontální pozice hráče
sta HPOSP0 ; uložit do řídicího registru HPOSP0 na čipu GTIA
lda #$ff ; bitová maska hráče
sta GRAFP0 ; uložit do řídicího registru GRAFP0 na čipu GTIA
loop: jmp loop
end:
.endproc
.segment "EXEHDR"
.word $ffff ; uvodni sekvence bajtu v souboru XEX
.word main ; zacatek kodoveho segmentu
.word main::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
Po spuštění se na obrazovce ukáže vertikální černý pruh:
Obrázek 1: Černý pruh představující prvního hráče.
Nastavení barvy prvního hráče
Při pohledu do tabulky uvedené ve druhé kapitole snadno zjistíme, že barva prvního hráče je nastavována řídicím registrem COLPM0. Jenže tento registr nelze přečíst (jeho význam je při čtení odlišný). A proto existuje v paměti Atari několik takzvaných stínových registrů, které jsou automaticky (v každém snímku) zapisovány do registrů GTIA (a jejich čtení je tedy možné a je triviální). Pro COLM0 existuje stínový registr nazvaný PCOLR3, kterým (v dalším snímku) změníme barvu prvního hráče:
lda #HUE_MAGENTA<<4 + 8 ; barva hráče (odstín+intenzita)
sta PCOLR0 ; uložit do řídicího registru PCOLR0 na čipu GTIA
Nyní bude obrazovka vypadat odlišně:
Obrázek 2: Barevný pruh představující prvního hráče, který je zobrazený zhruba uprostřed obrazovky.
Výsledný zdrojový kód příkladu:
; ---------------------------------------------------------------------
; Initializace PMG, povolení PMG, nastavení pozice, tvaru a barvy prvního hráče.
; ---------------------------------------------------------------------
.include "atari.inc"
.CODE
.proc main
lda #128 ; horizontální pozice hráče
sta HPOSP0 ; uložit do řídicího registru HPOSP0 na čipu GTIA
lda #HUE_MAGENTA<<4 + 8 ; barva hráče (odstín+intenzita)
sta PCOLR0 ; uložit do řídicího registru PCOLR0 na čipu GTIA
lda #$ff ; bitová maska hráče
sta GRAFP0 ; uložit do řídicího registru GRAFP0 na čipu GTIA
loop: jmp loop
end:
.endproc
.segment "EXEHDR"
.word $ffff ; uvodni sekvence bajtu v souboru XEX
.word main ; zacatek kodoveho segmentu
.word main::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
Zákaz DMA, pokud se mají zobrazit jen globální tvary hráčů
Prozatím nepracujeme s bitmapami spritů a proto můžeme vypnout DMA. Jedná se o technologii, kterou GTIA využívá pro získání tvarů spritů při vykreslování snímků. My ale prozatím pracujeme s hráčem, jehož všechny řádky jsou stejné a proto můžeme DMA vypnout a počítač tak urychlit (více cyklů pro CPU). To se provede následovně:
lda #0 ; bitové pole: vše nulové
sta GRACTL ; uložit do řídicího registru GRACTL na čipu GTIA
Výsledek by měl být stejný, jako v příkladu předchozím, ovšem CPU má nyní k dispozici více strojových cyklů:
Obrázek 3: Barevný pruh představující prvního hráče, který je zobrazený zhruba uprostřed obrazovky. Vypnutí DMA nemá na zobrazení vliv.
Úplný zdrojový kód třetího demonstračního příkladu:
; ---------------------------------------------------------------------
; Initializace PMG, povolení PMG, nastavení pozice, tvaru a barvy prvního hráče.
; Zákaz DMA.
; ---------------------------------------------------------------------
.include "atari.inc"
.CODE
.proc main
lda #128 ; horizontální pozice hráče
sta HPOSP0 ; uložit do řídicího registru HPOSP0 na čipu GTIA
lda #HUE_MAGENTA<<4 + 8 ; barva hráče (odstín+intenzita)
sta PCOLR0 ; uložit do řídicího registru PCOLR0 na čipu GTIA
lda #$ff ; bitová maska hráče
sta GRAFP0 ; uložit do řídicího registru GRAFP0 na čipu GTIA
lda #0 ; bitové pole: vše nulové
sta GRACTL ; uložit do řídicího registru GRACTL na čipu GTIA
loop: jmp loop
end:
.endproc
.segment "EXEHDR"
.word $ffff ; uvodni sekvence bajtu v souboru XEX
.word main ; zacatek kodoveho segmentu
.word main::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
Modifikace šířky hráčů
Zajímavé možnosti nabízí registry SIZEPx a SIZEM. Nejnižšími dvěma bity je možné nastavit šířku pixelů hráčů a/nebo střel. Hodnota 00 znamená normální šířku odpovídající dvěma pixelům hracího pole v nejvyšším rozlišení (tato šířka odpovídá jednomu taktu hodin pro generování barvy na TV, více informací bude uvedeno v popisu čipu ANTIC). Hodnota 01 znamená dvojnásobnou šířku a hodnota 11 pak šířku čtyřnásobnou.
V dalším demonstračním příkladu se postupně mění šířka prvního hráče, a to modifikací obsahu HW registru SIZEP0. Mezi jednotlivými změnami velikostí se čeká na stisk klávesy (mimochodem: malou úpravou dosáhnete toho, že se po změně na čtyřnásobnou velikost řízení vrátí zpět na začátek programu – tuto úpravu ponechávám na laskavém čtenáři):
Obrázek 4: První hráč s výchozí velikostí.
Obrázek 5: První hráč s dvojnásobnou velikostí.
Obrázek 6: První hráč se čtyřnásobnou velikostí.
Následuje výpis úplného zdrojového kódu tohoto demonstračního příkladu:
; ---------------------------------------------------------------------
; Initializace PMG, povolení PMG, nastavení pozice, tvaru a barvy prvního hráče.
; Zákaz DMA. Postupná změna horizontální velikosti hráče.
; ---------------------------------------------------------------------
.include "atari.inc"
.CODE
KBHANDLER = $e424 ; rutina pro cteni klavesy
.proc main
lda #128 ; horizontální pozice hráče
sta HPOSP0 ; uložit do řídicího registru HPOSP0 na čipu GTIA
lda #HUE_MAGENTA<<4 + 8 ; barva hráče (odstín+intenzita)
sta PCOLR0 ; uložit do řídicího registru PCOLR0 na čipu GTIA
lda #$ff ; bitová maska hráče
sta GRAFP0 ; uložit do řídicího registru GRAFP0 na čipu GTIA
lda #0 ; bitové pole: vše nulové
sta GRACTL ; uložit do řídicího registru GRACTL na čipu GTIA
jsr get_key ; čekání na stisk klávesy
lda #1 ; horizontální velikost hráče
sta SIZEP0 ; uložit do řídicího registru SIZEP0 na čipu GTIA
jsr get_key ; čekání na stisk klávesy
lda #3 ; horizontální velikost hráče
sta SIZEP0 ; uložit do řídicího registru SIZEP0 na čipu GTIA
loop: jmp loop
.endproc
.proc get_key
lda KBHANDLER+1 ; cteni horni casti adresy ulozene v ROM
pha ; ulozeni na zasobnik
lda KBHANDLER ; cteni dolni casti adresy ulozene v ROM
pha ; ulozeni na zasobnik
rts ; vyber adresy ze zasobniku + skok
; zde neni nutne mit RTS
.endproc
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
Změna globálního tvaru hráče
Prozatím jsme do HW registru GRAFP0 zapisovali hodnotu 0×ff, tj. všechny bity byly nastaveny na jedničku. První hráč byl zobrazen formou vertikálního pruhu o šířce 16, 32 nebo 64 pixelů (počítáme v pixelech hracího pole). Ovšem pokud zapíšeme hodnotu odlišnou, budou některé pruhy hráče průhledné. Můžeme například vynechat každý lichý bit a tudíž i každý lichý sloupec bude průhledný:
lda #128+32+8+2 ; bitová maska hráče
sta GRAFP0 ; uložit do řídicího registru GRAFP0 na čipu GTIA
Výsledek pro různě nastavené šířky hráčů:
Obrázek 7: První hráč má nyní odlišný tvar (všechny jeho řádky jsou však stále totožné).
Obrázek 8: První hráč má nyní odlišný tvar (všechny jeho řádky jsou však stále totožné), dvojnásobná šířka.
Obrázek 9: První hráč má nyní odlišný tvar (všechny jeho řádky jsou však stále totožné), čtyřnásobná šířka.
Úplný zdrojový kód takto upraveného příkladu:
; ---------------------------------------------------------------------
; Initializace PMG, povolení PMG, nastavení pozice, tvaru a barvy prvního hráče.
; Zákaz DMA. Postupná změna horizontální velikosti hráče.
; ---------------------------------------------------------------------
.include "atari.inc"
.CODE
KBHANDLER = $e424 ; rutina pro cteni klavesy
.proc main
lda #128 ; horizontální pozice hráče
sta HPOSP0 ; uložit do řídicího registru HPOSP0 na čipu GTIA
lda #HUE_MAGENTA<<4 + 8 ; barva hráče (odstín+intenzita)
sta PCOLR0 ; uložit do řídicího registru PCOLR0 na čipu GTIA
lda #128+32+8+2 ; bitová maska hráče
sta GRAFP0 ; uložit do řídicího registru GRAFP0 na čipu GTIA
lda #0 ; bitové pole: vše nulové
sta GRACTL ; uložit do řídicího registru GRACTL na čipu GTIA
jsr get_key ; čekání na stisk klávesy
lda #1 ; horizontální velikost hráče
sta SIZEP0 ; uložit do řídicího registru SIZEP0 na čipu GTIA
jsr get_key ; čekání na stisk klávesy
lda #3 ; horizontální velikost hráče
sta SIZEP0 ; uložit do řídicího registru SIZEP0 na čipu GTIA
loop: jmp loop
.endproc
.proc get_key
lda KBHANDLER+1 ; cteni horni casti adresy ulozene v ROM
pha ; ulozeni na zasobnik
lda KBHANDLER ; cteni dolni casti adresy ulozene v ROM
pha ; ulozeni na zasobnik
rts ; vyber adresy ze zasobniku + skok
; zde neni nutne mit RTS
.endproc
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
Priority PMG vůči hracímu poli a pozadí
Priority zobrazení hráčů a střel vůči sobě nebo vůči hracímu poli se nastavují modifikací nejnižších čtyř bitů řídicího registru GPRIOR. Existuje celkem devět úrovní priorit, ovšem vybírat si můžeme jen z pěti možností tak, jak je to naznačeno v další tabulce:
| Priorita | 0001 | 0010 | 0100 | 1000 | 0000 |
|---|---|---|---|---|---|
| Nejvyšší | PM0 | PM0 | P5/PF0 | P5/PF0 | PM0 |
| PM1 | PM1 | PF1 | PF1 | PM1 | |
| PM2 | P5/PF0 | PF2 | PM0 | P5/PF0 | |
| PM3 | PF1 | PF3 | PM1 | PF1 | |
| P5/PF0 | PF2 | PM0 | PM2 | PM2 | |
| PF1 | PF3 | PM1 | PM3 | PM3 | |
| PF2 | PM2 | PM2 | PF2 | PF2 | |
| PF3 | PM3 | PM3 | PF3 | PF3 | |
| Nejnižší | COLBK | COLBK | COLBK | COLBK | COLBK |
Význam zkratek z předchozí tabulky:
| Zkratka | Význam |
|---|---|
| PMx | hráč a střela x (0–3) |
| P5 | pátý hráč složený ze všech střel (viz navazující článek) |
| PFx | barva hracího pole x (0–3) |
| COLBK | barva pozadí |
Zobrazení dvou překrývajících se hráčů současně, režim „multicolor“
Šestým bitem registru GPRIOR se povoluje takzvaný režim „multicolor“ (pozor, na Commodore C64 má toto slovo naprosto odlišný význam). Pokud je tento bit nastaven a dva sprity (například hráči) se překrývají, bude barva překryté oblasti vypočtena operací OR. Připomeňme, že na Atari se barva skládá z kódu odstínu a intenzity. Operace OR tedy může vést k zobrazení zcela odlišné barvy – nejedná se o smíchání barev ve smyslu jejich odstínu! Režim „multicolor“ se zapne po spuštění dalšího příkladu a stisku klávesy. Další stisky klávesy mění navíc i prioritu (což si ještě ukážeme v dalších příkladech):
Obrázek 10: Dva překrývající se hráči, GPRIOR=0.
Obrázek 11: Dva překrývající se hráči, GPRIOR=32 (multicolor).
Obrázek 12: Dva překrývající se hráči, GPRIOR=37 (změna priorit).
Obrázek 13: Dva překrývající se hráči, GPRIOR=37 (multicolor+změna priorit).
Úplný zdrojový kód takto upraveného příkladu:
; ---------------------------------------------------------------------
; Initializace PMG, povolení PMG, nastavení pozice, tvaru a barvy dvou
; hráčů.
; ---------------------------------------------------------------------
.include "atari.inc"
.CODE
KBHANDLER = $e424 ; rutina pro cteni klavesy
.proc main
lda #128 ; horizontální pozice prvního hráče
sta HPOSP0 ; uložit do řídicího registru HPOSP0 na čipu GTIA
lda #132 ; horizontální pozice druého hráče
sta HPOSP1 ; uložit do řídicího registru HPOSP1 na čipu GTIA
lda #HUE_GREEN<<4 + 6 ; 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 #$ff ; bitová maska prvního i druhého hráče
sta GRAFP0 ; uložit do řídicího registru GRAFP0 na čipu GTIA
sta GRAFP1 ; uložit do řídicího registru GRAFP1 na čipu GTIA
lda #0 ; bitové pole: vše nulové
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
jsr get_key ; čekání na stisk klávesy
lda #32 ; priorita hráčů a pozadí - OR barev
sta GPRIOR ; uložit do řídicího registru GPRIOR na čipu GTIA
jsr get_key ; čekání na stisk klávesy
lda #31 ; priorita hráčů a pozadí
sta GPRIOR ; uložit do řídicího registru GPRIOR na čipu GTIA
jsr get_key ; čekání na stisk klávesy
lda #37 ; priorita hráčů a pozadí
sta GPRIOR ; uložit do řídicího registru GPRIOR na čipu GTIA
loop: jmp loop
.endproc
.proc get_key
lda KBHANDLER+1 ; cteni horni casti adresy ulozene v ROM
pha ; ulozeni na zasobnik
lda KBHANDLER ; cteni dolni casti adresy ulozene v ROM
pha ; ulozeni na zasobnik
rts ; vyber adresy ze zasobniku + skok
; zde neni nutne mit RTS
.endproc
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
Nastavení bitmapy spritů (hráčů i střel)
Prozatím naše sprity vypadaly jako obdélníky, ovšem systém PMG pochopitelně podporuje i definici hráčů (a střel) pomocí bitmapy. U hráčů je každá bitmapa široká osm pixelů a vysoká 128 pixelů. Pro každého hráče je tedy nutné alokovat paměť 128×8 bitů=128 bajtů. Pro všechny střely současně se jedná o stejnou velikost, tedy 128 bajtů. Celkově tedy potřebujeme:
1 hráč = 128 bajtů
2 hráč = 128 bajtů
3 hráč = 128 bajtů
4 hráč = 128 bajtů
střely = 128 bajtů
------------------
640 bajtů
K těmto 640 bajtům je přidáno 384 bajtů „výplně“ (můžete je použít pro jiné účely) a celkem tedy potřebujeme 640+384=1024 bajtů, tj. čtyři stránky paměti. Tyto stránky mohou být umístěny kdekoli v paměti, ovšem musí začínat na hodnotě dělitelné čtyřmi.
Offsety bitmap pro hráče se pak vypočtou takto (ve skutečnosti 1024 bajtů začíná bufferem a poté 128 bajty pro střely):
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
V našich demonstračních příkladech použijeme paměťové stránky 152–156. Index první stránky předáme čipu ANTIC (ne GTIA) přes řídicí registr:
lda #152 ; paměťová stránka číslo 152
sta PMBASE
Demonstrační příklad: naivní nastavení bitmapy prvního hráče
V tomto demonstračním příkladu nejprve povolíme definici bitmapy hráčů, povolíme DMA a nastavíme stránky, ve kterých jsou bitmapy uloženy:
lda #3 ; bitové pole: povolení hráčů i střel
sta GRACTL ; uložit do řídicího registru GRACTL na čipu GTIA
lda #152 ; paměťová stránka číslo 152
sta PMBASE
lda #46 ; povolení PMG DMA
sta SDMCTL
Dále je nutné vyplnit část bitmapy prvního hráče. Nastavíme pouze osm řádků zhruba v polovině výšce hráče (offset 64):
addr = 152*256
lda #24 ; bitová maska jednoho řádku spritu
sta addr+512+64 ; zapsat do paměti
lda #60
sta addr+512+64+1
lda #126
sta addr+512+64+2
lda #126
sta addr+512+64+3
lda #219
sta addr+512+64+4
lda #255
sta addr+512+64+5
lda #36
sta addr+512+64+6
lda #90
sta addr+512+64+7
lda #165
sta addr+512+64+8
Výsledek by měl vypadat takto:
Obrázek 14: První hráč s definovanou bitmapou.
; ---------------------------------------------------------------------
; Initializace PMG, nastavení barvy, pozice a bitmapy prvního hráče.
; ---------------------------------------------------------------------
.include "atari.inc"
.CODE
.proc main
lda #128 ; horizontální pozice prvního hráče
sta HPOSP0 ; uložit do řídicího registru HPOSP0 na čipu GTIA
lda #HUE_YELLOW<<4 + 12 ; barva prvního hráče (odstín+intenzita)
sta PCOLR0 ; uložit do řídicího registru PCOLR0 na čipu GTIA
lda #$ff ; bitová maska prvního i druhého hráče
sta GRAFP0 ; uložit do řídicího registru GRAFP0 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 #152 ; paměťová stránka číslo 152
sta PMBASE
addr = 152*256
lda #24 ; bitová maska jednoho řádku spritu
sta addr+512+64 ; zapsat do paměti
lda #60
sta addr+512+64+1
lda #126
sta addr+512+64+2
lda #126
sta addr+512+64+3
lda #219
sta addr+512+64+4
lda #255
sta addr+512+64+5
lda #36
sta addr+512+64+6
lda #90
sta addr+512+64+7
lda #165
sta addr+512+64+8
lda #46 ; povolení PMG DMA
sta SDMCTL
loop: jmp loop
.endproc
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řečtení bitmapy (tvaru) hráče z pole s daty
Předchozí způsob nastavení bitmapy hráče byl pochopitelně poměrně naivní, už jen z toho důvodu, že vyžadoval pro každý řádek pět bajtů strojového kódu. Existuje pochopitelně elegantnější způsob. Nejdříve uložíme data hráče (tedy bitmapu či její část) přímo do zdrojového kódu v assembleru. V našem konkrétním případě je postavička vysoká osm řádků a proto potřebujeme osm bajtů:
; data sprite: .byte 24, 60, 126, 219, 255, 36, 90, 165
Dále je nutné implementovat počítanou programovou smyčku, která přenese oněch osm bajtů na vypočtenou adresu, tedy v našem případě do paměťového bloku začínajícího na stránce číslo 152. Adresa této stránky je rovna:
addr = 152*256
Samotná počítaná programová smyčka může vypadat takto:
ldx #8 ; začneme na hodnotě o 1 vyšší
next_line:
lda sprite-1, x ; načíst
sta addr+512+64, x ; uložit byte
dex ; snížit offset + nastavit příznaky
bne next_line ; další byte spritu
lda #46 ; povolení PMG DMA
sta SDMCTL
Výsledek by měl být stejný, jako je tomu v předchozím příkladu:
Obrázek 15: Hráč s definovanou bitmapou.
Opět následuje výpis zdrojového kódu:
; ---------------------------------------------------------------------
; Initializace PMG, nastavení barvy, pozice a bitmapy prvního hráče.
; ---------------------------------------------------------------------
.include "atari.inc"
.CODE
.proc main
lda #128 ; horizontální pozice prvního hráče
sta HPOSP0 ; uložit do řídicího registru HPOSP0 na čipu GTIA
lda #HUE_YELLOW<<4 + 12 ; barva prvního hráče (odstín+intenzita)
sta PCOLR0 ; uložit do řídicího registru PCOLR0 na čipu GTIA
lda #$ff ; bitová maska prvního i druhého hráče
sta GRAFP0 ; uložit do řídicího registru GRAFP0 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 #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+512+64, x ; uložit byte
dex ; snížit offset + nastavit příznaky
bne next_line ; další byte spritu
lda #46 ; povolení PMG DMA
sta SDMCTL
loop: jmp loop
.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í čtyř hráčů současně se změnou priorit
V dnešním předposledním demonstračním příkladu, který si ukážeme, se vrátíme k registru GPRIOR, kterým je možné nastavit priority PMG vůči sobě (první hráč vs. třetí hráč atd.) či vůči hernímu poli (playground). V příkladu zobrazíme všechny čtyři hráče tak, aby se nepřekrývaly, a posléze bude provedeno přepnutí priorit na hodnoty 0000, 0001, 0010 a 0100 (binárně). Přepínání se opět provádí stiskem klávesy. Vizuální výsledky při postupné změně priorit by měly vypadat takto:
Obrázek 16: Registr GPRIOR=0.
Obrázek 17: Registr GPRIOR=1.
Obrázek 18: Registr GPRIOR=2.
Obrázek 19: Registr GPRIOR=4.
Opět následuje výpis celého zdrojového kódu tohoto demonstračního příkladu:
; ---------------------------------------------------------------------
; Initializace PMG, povolení PMG, nastavení pozice, tvaru a barvy všech
; hráčů.
; ---------------------------------------------------------------------
.include "atari.inc"
.CODE
KBHANDLER = $e424 ; rutina pro cteni klavesy
.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 + 6 ; 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 #0 ; bitové pole: vše nulové
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
jsr get_key ; čekání na stisk klávesy
lda #1 ; priorita hráčů a pozadí
sta GPRIOR ; uložit do řídicího registru GPRIOR na čipu GTIA
jsr get_key ; čekání na stisk klávesy
lda #2 ; priorita hráčů a pozadí
sta GPRIOR ; uložit do řídicího registru GPRIOR na čipu GTIA
jsr get_key ; čekání na stisk klávesy
lda #4 ; priorita hráčů a pozadí
sta GPRIOR ; uložit do řídicího registru GPRIOR na čipu GTIA
loop: jmp loop
.endproc
.proc get_key
lda KBHANDLER+1 ; cteni horni casti adresy ulozene v ROM
pha ; ulozeni na zasobnik
lda KBHANDLER ; cteni dolni casti adresy ulozene v ROM
pha ; ulozeni na zasobnik
rts ; vyber adresy ze zasobniku + skok
; zde neni nutne mit RTS
.endproc
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
Nastavení bitmap všech čtyř hráčů
V dnešním posledním demonstračním příkladu opět zobrazíme všechny čtyři hráče, tentokrát však budou hráči definovaní svou bitmapou (polem 128×8 bitů). Pro jednoduchost nastavíme všechny bitmapy podobným způsobem, pouze s odlišným offsetem (což odpovídá vertikální pozici hráče na obrazovce). Výsledek by měl vypadat následovně:
Obrázek 20: Všichni čtyři hráči s definovanou bitmapou.
Úplný zdrojový kód tohoto příkladu, na který navážeme v příštím článku, 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+30, x ; uložit byte - první hráč
sta addr+PLAYER_1_OFFSET+50, x ; uložit byte - druhý hráč
sta addr+PLAYER_2_OFFSET+70, x ; uložit byte - třetí hráč
sta addr+PLAYER_3_OFFSET+90, 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: jmp loop
.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:
| # | 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 |
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:
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
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:
Odkazy na Internetu
- MOS 6502 instruction set
http://www.6502.org/users/obelisk/6502/instructions.html - EXE File Format Description
https://gury.atari8.info/refs/file_formats_exe.php - XEX Filter – A toolkit to analyze and manipulate Atari binary files
https://www.vitoco.cl/atari/xex-filter/index.html - chkxex.py
https://raw.githubusercontent.com/seban-slt/tcx_tools/refs/heads/master/chkxex.py - ca65 Users Guide
https://cc65.github.io/doc/ca65.html - cc65 Users Guide
https://cc65.github.io/doc/cc65.html - ld65 Users Guide
https://cc65.github.io/doc/ld65.html - da65 Users Guide
https://cc65.github.io/doc/da65.html - Překladače jazyka C pro historické osmibitové mikroprocesory
https://www.root.cz/clanky/prekladace-jazyka-c-pro-historicke-osmibitove-mikroprocesory/ - 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/ - Getting Started Programming in C: Coding a Retro Game with C Part 2
https://retrogamecoders.com/getting-started-with-c-cc65/ - NES game development in 6502 assembly – Part 1
https://kibrit.tech/en/blog/nes-game-development-part-1 - 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/ - Minimal NES example using ca65
https://github.com/bbbradsmith/NES-ca65-example - List of 6502-based Computers and Consoles
https://www.retrocompute.co.uk/list-of-6502-based-computers-and-consoles/ - 6502 – the first RISC µP
http://ericclever.com/6500/ - 3 Generations of Game Machine Architecture
http://www.atariarchives.org/dev/CGEXPO99.html - “Hello, world” from scratch on a 6502 — Part 1
https://www.youtube.com/watch?v=LnzuMJLZRdU - A Tour of 6502 Cross-Assemblers
https://bumbershootsoft.wordpress.com/2016/01/31/a-tour-of-6502-cross-assemblers/ - Adventures with ca65
https://atariage.com/forums/topic/312451-adventures-with-ca65/ - example ca65 startup code
https://atariage.com/forums/topic/209776-example-ca65-startup-code/ - 6502 PRIMER: Building your own 6502 computer
http://wilsonminesco.com/6502primer/ - 6502 Instruction Set
https://www.masswerk.at/6502/6502_instruction_set.html - Chip Hall of Fame: MOS Technology 6502 Microprocessor
https://spectrum.ieee.org/tech-history/silicon-revolution/chip-hall-of-fame-mos-technology-6502-microprocessor - Single-board computer
https://en.wikipedia.org/wiki/Single-board_computer - www.6502.org
http://www.6502.org/ - 6502 PRIMER: Building your own 6502 computer – clock generator
http://wilsonminesco.com/6502primer/ClkGen.html - Great Microprocessors of the Past and Present (V 13.4.0)
http://www.cpushack.com/CPU/cpu.html - Jak se zrodil procesor?
https://www.root.cz/clanky/jak-se-zrodil-procesor/ - Osmibitové mikroprocesory a mikrořadiče firmy Motorola (1)
https://www.root.cz/clanky/osmibitove-mikroprocesory-a-mikroradice-firmy-motorola-1/ - 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/ - 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/ - 25 Microchips That Shook the World
https://spectrum.ieee.org/tech-history/silicon-revolution/25-microchips-that-shook-the-world - Comparison of instruction set architectures
https://en.wikipedia.org/wiki/Comparison_of_instruction_set_architectures - How To Start Learning Atari 8 Bit Assembly For Free
https://forums.atariage.com/topic/300732-how-to-start-learning-atari-8-bit-assembly-for-free/ - WUDSN (Demo Group)
https://www.wudsn.com/ - Machine Language For Beginners
https://www.atariarchives.org/mlb/ - Assembly language: all about I/O
https://www.atarimagazines.com/v3n8/AllAbout_IO.html - Sedmdesátiny assemblerů: lidsky čitelný strojový kód
https://www.root.cz/clanky/sedmdesatiny-assembleru-lidsky-citelny-strojovy-kod/ - Color names
https://atariwiki.org/wiki/Wiki.jsp?page=Color%20names - ATASCII
https://en.wikipedia.org/wiki/ATASCII - Put characters in display ram isn't ATASCII?
https://forums.atariage.com/topic/359973-put-characters-in-display-ram-isnt-atascii/ - ATASCII And Internal Character Code Values
https://www.atariarchives.org/mapping/appendix10.php - Reading ATASCII from the keyboard in assembly
https://forums.atariage.com/topic/361733-reading-atascii-from-the-keyboard-in-assembly/ - Why does the 6502 JSR instruction only increment the return address by 2 bytes?
https://retrocomputing.stackexchange.com/questions/19543/why-does-the-6502-jsr-instruction-only-increment-the-return-address-by-2-bytes - Pushing return address to stack off by 1 byte
https://forums.atariage.com/topic/378206-pushing-return-address-to-stack-off-by-1-byte/ - Intel x86 documentation has more pages than the 6502 has transistors
https://www.righto.com/2013/09/intel-x86-documentation-has-more-pages.html - Clearing a Section of Memory
http://www.6502.org/source/general/clearmem.htm - Practical Memory Move Routines by Bruce Clark
http://www.6502.org/source/general/memory_move.html - 6502 Assembly Programming Guide
https://neumont-gamedev.github.io/posts/retrogamedev-6502-guide/ - Off-by-one error
https://en.wikipedia.org/wiki/Off-by-one_error - 6502 cycle times
https://www.nesdev.org/wiki/6502_cycle_times - Atari TIA
http://www.atarihq.com/danb/tia.shtml - TIA Playfield
http://www.atarihq.com/danb/TIA/Playfield.shtml - Atari Inc.:
ANTIC C012296 (NTSC) Revision D
Atari Incorporated, Sunnyvale CA, 1982 - Atari Inc.:
GTIA C014805 (NTSC) Revision A
Atari Incorporated, Sunnyvale CA, 1982 - Atari 5200
http://www.atariage.com/software_search.html?SystemID=5200 - Atari 5200 Hardware and Accessories
http://www.atariage.com/5200/archives/hardware.html - Atari 5200 Screenshots
http://www.atariage.com/system_items.html?SystemID=5200&ItemTypeID=SCREENSHOT - History of video game consoles (second generation): Wikipedia
http://en.wikipedia.org/wiki/History_of_video_game_consoles_(second_generation) - Atari 5200: Wikipedia
http://en.wikipedia.org/wiki/Atari_5200 - Player-Missile Graphics
https://www.atariarchives.org/agagd/chapter5.php - Sprite (computer graphics)
https://en.wikipedia.org/wiki/Sprite_(computer_graphics)
