Limity čipu GTIA
Co se dozvíte v článku
- Limity čipu GTIA
- Čip ANTIC se představuje
- Textové režimy čipu ANTIC
- Grafické režimy čipu ANTIC
- Ukázky her využívajících textové režimy
- Ukázky her využívajících grafické režimy
- Řídicí registry čipu ANTIC
- Od teorie k praxi
- Soubor atari_antic.inc
- Úprava konfiguračního souboru pro linker
- Nastavení display listu s textovým režimem (4 barvy, dvojitá velikost znaků)
- Úplný zdrojový kód prvního demonstračního příkladu
- I assembler může být čitelný: využití konstant definovaných v souboru atari_antic.inc
- Úplný zdrojový kód druhého demonstračního příkladu
- Kombinace různých textových a grafických režimů
- Složitější varianta display listu
- Úplný zdrojový kód třetího demonstračního příkladu
- Příloha: Makefile pro překlad všech demonstračních příkladů
- Repositář s demonstračními příklady
- Odkazy na Internetu
V předchozích třech článcích o tvorbě software pro osmibitové domácí mikropočítače Atari jsme se zaměřili na popis grafického čipu GTIA. Ten je určen (především) k zobrazení pohyblivých objektů – spritů, ovšem omezeni jsme jen na sprity šířky dvou či osmi pixelů a výšky 128 nebo 256 pixelů (další rozšíření již vyžaduje ANTIC). Možnosti jsou tedy relativně omezené, i když jen s využitím spritů (a ničeho dalšího) lze implementovat například plnohodnotnou hru Pong. Celou implementaci sice ještě hotovou nemáme, ale první „nástřel“ (využívající skutečně pouze sprity) vypadá takto:
Obrázek 1: Scéna ze hry Pong, ve které jsem použil jen čtyři hráče a čtyři střely.
Ostatně podívejme se na zdrojový kód programu, který tuto scénu vykreslí. Skutečně zde pracujeme jen se čtyřmi hráči (zobrazení skóre) a čtyřmi střelami (dvě pálky, síťka a míček):
; ---------------------------------------------------------------------
; Zobrazení obrazovky ze hry Pong.
; ---------------------------------------------------------------------
.include "atari.inc"
.CODE
SCORE_OFFSET = 10
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 #0 ; barva pozadí textu
sta COLOR1 ; nastavit
sta COLOR2 ; nastavit
lda #70 ; horizontální pozice prvního hráče (číslice skóre)
sta HPOSP0 ; uložit do řídicího registru HPOSP0 na čipu GTIA
lda #80 ; horizontální pozice druhého hráče (číslice skóre)
sta HPOSP1 ; uložit do řídicího registru HPOSP1 na čipu GTIA
lda #160 ; horizontální pozice třetího hráče (číslice skóre)
sta HPOSP2 ; uložit do řídicího registru HPOSP2 na čipu GTIA
lda #170 ; horizontální pozice čtvrtého hráče (číslice skóre)
sta HPOSP3 ; uložit do řídicího registru HPOSP3 na čipu GTIA
lda #50 ; horizontální pozice první střely (pálka)
sta HPOSM0 ; uložit do řídicího registru HPOSM0 na čipu GTIA
lda #200 ; horizontální pozice druhé střely (pálka)
sta HPOSM1 ; uložit do řídicího registru HPOSM1 na čipu GTIA
lda #160 ; horizontální pozice třetí střely (míček)
sta HPOSM2 ; uložit do řídicího registru HPOSM2 na čipu GTIA
lda #128 ; horizontální pozice čtvrté střely (síťka)
sta HPOSM3 ; uložit do řídicího registru HPOSM3 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 #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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Skóre
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
addr = 152*256
ldx #8 ; začneme na hodnotě o 1 vyšší
next_line:
lda number_0-1, x ; načíst
sta addr+PLAYER_0_OFFSET+SCORE_OFFSET, x ; uložit byte - první hráč
sta addr+PLAYER_1_OFFSET+SCORE_OFFSET, x ; uložit byte - druhý hráč
sta addr+PLAYER_2_OFFSET+SCORE_OFFSET, x ; uložit byte - třetí hráč
sta addr+PLAYER_3_OFFSET+SCORE_OFFSET, x ; uložit byte - čtvrtý hráč
dex ; snížit offset + nastavit příznaky
bne next_line ; další byte spritu
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pálky
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ldx #20
missile_line:
lda #%0000001 ; jen první střela (pálka)
sta addr+MISSILES_OFFSET+50, x
lda #%0000100 ; jen druhá střela (pálka)
sta addr+MISSILES_OFFSET+72, x
dex
bne missile_line ; další byte spritu
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Míček
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
lda #%00110000 ; jen třetí střela (míček)
sta addr+MISSILES_OFFSET+70, x
sta addr+MISSILES_OFFSET+71, x
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Síťka
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ldx #126
net:
lda addr+MISSILES_OFFSET, x
ora #%1000000 ; jen čtvrtá střela (síťka)
sta addr+MISSILES_OFFSET, x
dex
dex
bne net ; další byte spritu
lda #46 ; povolení PMG DMA
sta SDMCTL
loop: jmp loop
.endproc
; data
number_0: .byte %00111100, %011000011, %011000011, %011000011, %011000011, %011000011, %00111100, 0
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
Čip ANTIC se představuje
Na osmibitových počítačích Atari se grafika skládala, jak již dobře víme, ze dvou částí: pozadí (hrací pole, playfield) a pohyblivých rastrových obrázků (spritů). Pro nastavení grafického režimu pozadí (playfield) byl určen obvod ANTIC (Alpha-Numeric Television Interface Circuit), který umožnil pro každý vykreslovaný řádek programově nastavit jeden ze čtrnácti textových nebo grafických režimů, které se lišily svým rozlišením, počtem současně zobrazitelných barev a velikostí alokované paměti.
Některé z podporovaných režimů zobrazovaly pouze znaky, jiné byly čistě bitmapové. U každého zobrazovaného řádku bylo možné povolit přerušení DLI (Display-List Interrupt), které nastalo při horizontálním zpětném běhu elektronového paprsku na televizní obrazovce. Pro každý zobrazovaný řádek bylo také možné povolit jemný posuv o maximálně osm pixelů, čímž bylo možné realizovat jednoduchý scrolling obrazovky nebo její části (tj. pouze několika vybraných řádků).
Vzhledem k tomu, že se čip ANTIC řídil vlastní sadou příkazů nazývanou Display List a při vykreslování přebíral od hlavního procesoru řízení sběrnice, se v podstatě jednalo o jeden z prvních široce používaných grafických procesorů (Graphics Processing Unit – GPU). Operační paměť byla mezi hlavním procesorem počítače MOS 6502 a čipem ANTIC sdílená, což vedlo k nutnosti postupného přebírání řízení jedním z procesorů za pomoci operací přerušení.
Díky frekvenci hlavního procesoru a potřebě synchronizace elektronového paprsku bylo maximální podporované rozlišení rovno 352×240 pixelům. Toto rozlišení, které se v literatuře nazývá celkem trefně overscan se kvůli kompatibilitě s kompozitními monitory a televizními obrazovkami snižovalo na standardních 320×200 pixelů resp. spíše 320×192 pixelů. V režimu overscan totiž paprsek okrajové části obrazu kreslil „za roh“ obrazovky, což bylo krásně viditelné například na elektronkových televizorech Salermo, které měly přední část obrazovky o cca 2cm vysunutou z šasi přístroje (o tuto vymoženost jsme postupnou modernizací přišli).
Textové režimy čipu ANTIC
Popišme si nejdříve textové režimy podporované čipem ANTIC. V následující tabulce jsou vypsány vlastnosti všech šesti textových režimů. Druhý sloupec obsahuje číslo režimu v BASICu, kde je použito v příkazu GRAPHICS (dále budeme používat zkratku GR.x znamenající GRAPHICS x, například GRAPHICS 8). Počet řádků a vyžadovaná kapacita RAM je spočtena pro standardní případy – všechny řádky používají stejný režim a omezeni jsme na 192 obrazových řádků:
| ANTIC | BASIC | Znaků/řádek | Počet řádků | Počet barev | Spotřeba RAM |
|---|---|---|---|---|---|
| 2 | 0 | 40 | 24 | 2 | 960 |
| 3 | – | 40 | -- | 2 | -- |
| 4 | 12 | 40 | 24 | 4/5 | 960 |
| 5 | 13 | 40 | 12 | 4/5 | 480 |
| 6 | 1 | 20 | 24 | 5 | 480 |
| 7 | 2 | 20 | 12 | 5 | 240 |
Tuto šestici režimů je možné dále rozdělit do tří podskupin:
- V první podskupině je standardní textový režim GR.0 (ANTIC 2) a režim ANTIC 3. V těchto režimech se zobrazují monochromatické znaky o výše osmi resp. deseti obrazových řádků. Barva pozadí a popředí znaků má vždy stejný odstín, liší se jen intenzita.
- Ve druhé podskupině jsou režimy GR.1 a GR.2 (ANTIC 6 a 7). Horizontální počet znaků je snížen na polovinu (stejně jako rozlišení) a zobrazit je možné jen 64 znaků (nikoli 128). Nejvyšší dva bity znaků určují jejich barvu, pátá je barva pozadí (implicitně černá).
- Režimy GR.12 a GR.13 (ANTIC 4 a 5) leží na pomezí mezi čistě textovými režimy a režimy grafickými. Znaky mají poloviční horizontální rozlišení a vždy dva bity v bitmapě znaku určují barvu pixelu. Tím lze rozlišit čtyři barvy; pátá barva je vybrána sedmým bitem kódu znaku. Výsledkem jsou „divné“ (špatně čitelné) znaky, ovšem modifikací znakové sady lze docílit mnoha zajímavých efektů.
Grafické režimy čipu ANTIC
Grafických režimů podporovaných čipem ANTIC je celkem osm. Tyto režimy vznikají kombinací různého horizontálního rozlišení (40, 80, 160, 320 pixelů), vertikálního rozlišení (24, 48, 96, 192 řádků) a počtu barev (2 nebo 4). Základní informace o těchto režimech jsou uvedeny v následující tabulce:
| ANTIC | BASIC | Pixelů/řádek | Počet řádků | Počet barev | Spotřeba RAM |
|---|---|---|---|---|---|
| 8 | 3 | 40 | 24 | 4 | 240 |
| 9 | 4 | 80 | 48 | 2 | 480 |
| A | 5 | 80 | 48 | 4 | 960 |
| B | 6 | 160 | 96 | 2 | 1920 |
| D | 7 | 160 | 96 | 4 | 3840 |
| C | 14 | 160 | 192 | 2 | 3840 |
| E | 15 | 160 | 192 | 4 | 7680 |
| F | 8 | 320 | 192 | 2 | 7680 |
Grafické režimy lze rozdělit do tří podskupin:
- V první podskupině se nachází režimy se čtyřmi barvami. Jedná se o režimy s rozlišeními 40×24, 80×48, 160×96 a 160×192 pixelů (ANTIC 8, A, D a E) neboli GR.3, GR.5, GR.7 a GR.15. Každý pixel je uložen ve dvou bitech a kromě posledního režimu jsou pixely čtvercové (v posledním režimu mají poloviční výšku).
- Režimy s rozlišením 80×48, 160×96 a 160×192 pixelů mají i svoje dvojbarevné varianty, v nichž je každý pixel uložen v jediném bitu. Jedná se o režimy ANTIC 9, B a C neboli GR.4, GR.6 a GR.14 (kupodivu neexistuje režim 40×24 pixelů se dvěma barvami, to je hodně primitivní grafika).
- Režim s rozlišením 320×192 pixelů (ANTIC F neboli GR.8) je monochromatický, což znamená, že barva pozadí i popředí má stejný odstín a pouze jinou intenzitu. Jedná se tedy o obdobu standardního textového režimu GR.0, který má (z pohledu barev) stejné vlastnosti. Tento režim nabízí nejvyšší možné (standardní) rozlišení, ovšem taktéž vyžaduje skoro 8 kB RAM (jinak se ovšem jedná o běžný režim s jedním bitem na pixel).
Ukázky her využívajících textové režimy
Ukažme si, jak byly jednotlivé režimy čipu ANTIC využity v praxi. V této kapitole budou představeny screenshoty několika her, které využívají některý z textových režimů. Snažil jsem se o výběr takových her, v nichž není zkombinováno větší množství režimů (takovými hrami se budeme zabývat příště).
Začneme standardním textovým režimem GR.0, který má v instrukční sadě ANTICu kód 2. První hra používá tento režim beze změny, druhá má vlastní font:
Obrázek 2: Hra Diktátor ve verzi pro osmibitová Atari.
Obrázek 3: Jedna z mnoha textovek využívajících standardní textový režim, ovšem vlastní font.
Režim GR.1 s 20 znaky na řádku a 24 textovými řádky není ve hrách příliš často používán, takže zde je výběr poněkud omezený. V dalším screeshotu je použita vlastní znaková sada:
Obrázek 4: Hra Dungeons of Xotha naprogramovaná v BASICu.
Režim GR.2 s 20 znaky na řádku a pouze 12 textovými řádky taktéž není (jako celek) používán příliš často. Ukažme si tedy alespoň úvodní obrazovku ke stejné hře, z jaké byl pořízen předchozí screenshot:
Obrázek 5: Úvodní obrazovka hry Dungeons of Xotha naprogramované v BASICu.
Naproti tomu režim GR.12 (ANTIC 4) se 40 znaky na řádku a 24 textovými řádky se používá velmi často. Horizontální rozlišení je zde sice sníženo na polovinu (160 pixelů), ovšem v oblasti každého znaku lze využít čtyři barvy (pátá barva se volí horním bitem znaku). Tento režim je velmi často využíván v mnoha hrách (i když to nemusí být na první pohled patrné) a ještě se k němu několikrát vrátíme:
Obrázek 6: Slavný Boulder Dash (zde konkrétně Boulder Dash II) běží celý v textovém režimu.
Obrázek 7: Neméně známá hra (Preliminary) Monty.
Ukázky her využívajících grafické režimy
Podívejme se ještě na několik ukázek her a dem, v nichž jsou použity režimy grafické. Opět jsem se (prozatím) snažil o výběr takových obrázků, v nichž nedochází ke změně režimů na jednotlivých řádcích, takže možná není příliš velkým překvapením, že se v několika případech jedná o „pouhé“ úvodní statické obrázky.
První screenshot pochází z dema, nikoli ze skutečné hry. Je v něm použit režim GR.6 (ANTIC B) s rozlišením 160×96 pixelů, který má pouhé dvě barvy. Předností tohoto režimu je malá kapacita obrazové paměti (1920 bajtů) a tím pádem i možnost relativně rychlého přepočítávání a překreslování:
Obrázek 8: Toto není hra, ale screenshot z dema Tron.
Další screenshot již pochází ze hry. Je zde použit grafický režim GR.7 (ANTIC D), jenž má taktéž rozlišení 160×96 pixelů, ovšem již je zde možné využít čtyři barvy (mimochodem: na této hře je nejlepší úvodní melodie a úvodní obrázek, samotná hra je dosti jednotvárná):
Obrázek 9: Úvodní obrazovka hry Space Lobsters.
Následuje dvojice obrázků používajících grafický režim GR.15 (ANTIC E) s rozlišením 160×192 pixelů a se čtyřmi barvami. Pixely v tomto případě nejsou čtvercové, ovšem vertikální rozlišení se zdvojnásobilo, stejně jako požadavky na Video RAM (celých 7680 bajtů):
Obrázek 10: Známá hra Zorro firmy Datasoft.
Obrázek 11: Opět Boulder Dash II, tentokrát jeho úvodní obrazovka.
Poslední dva screenshoty využívají režim GR.8 (ANTIC F) s nejvyšším rozlišení 320×192 pixelů, ovšem pouze s jedinou barvou (ve dvou odstínech). První screenshot je statický úvodní snímek, druhý screenshot ovšem pochází z živé hry:
Obrázek 12: Úvodní obrazovka známé hry Starquake.
Obrázek 13: Isometrická hra Amaurote (je až neuvěřitelné, že tato hra s pohyblivými objekty je počítána a vykreslována MOSem 6502).
Řídicí registry čipu ANTIC
Čip ANTIC se konfiguruje přes patnáct řídicích registrů. Těchto registrů je tedy mnohem méně, než v případě čipu GTIA, ovšem na druhou stranu ANTIC využívá několik datových struktur uložených v ROM nebo v operační paměti. Mezi tyto struktury patří především takzvaný display list, o němž se zmíníme dále a taktéž znaková sada (1024 bajtů neboli čtyři stránky paměti). Vraťme se však k řídicím registrům čipu ANTIC. Ty jsou vypsány v následující tabulce:
| Jméno | Význam | Čtení/zápis | Stínový registr |
|---|---|---|---|
| DMACTL | Direct Memory Access Control | W | SDMCTL |
| CHACTL | Character Control | W | CHART |
| DLISTL | Display List Pointer (low byte) | W | SDLSTL |
| DLISTH | Display List Pointer (high byte) | W | SDLSTH |
| HSCROL | Horizontal Fine Scroll | W | |
| VSCROL | Vertical Fine Scroll | W | |
| PMBASE | Player/Missile Base Address | W | |
| CHBASE | Character Set Base Address | W | CHBAS |
| WSYNC | Wait for Horizontal Sync | W | |
| VCOUNT | Vertical Line Counter | R | |
| PENH | Light Pen Horizontal Position | R | LPENH |
| PENV | Light Pen Vertical Position | R | LPENV |
| NMIEN | Non-Maskable Interrupt (NMI) Enable | W | |
| NMIRES | Non-Maskable Interrupt (NMI) Reset | W | |
| NMIST | Non-Maskable Interrupt (NMI) Status | R |
Registr PMBASE a DMACTL (resp. stínový registr SDMCTL) jsme již dříve používali, ovšem skutečně se jedná o registry čipu ANTIC. Z toho ovšem plyne zajímavé poučení: o přístup do paměti se stará i v případě spritů ANTIC a nikoli GTIA.
Od teorie k praxi
V tomto seriálu jsem schválně nejdříve začal s popisem čipu GTIA a nikoli ANTIC. Je tomu tak z toho důvodu, že s využitím GTIA je možné vykreslit nějaký sprite (hráče nebo střelu) s pouhými několika instrukcemi. V případě čipu ANTIC je situace komplikovanější, protože pokud budeme chtít použít jiný režim, než standardní GR.0 (ANTIC 2), bude nutné, abychom explicitně nastavili display list a navíc je nutné v některém místě RAM rezervovat blok použitý pro uložení kódů znaků (textové režimy) nebo barev pixelů (grafické režimy). To vyžaduje další znalosti assembleru (segment BSS atd.). Nicméně již dnes budeme schopni nastavit nový textový/grafický režim a provést výpis textu nebo vykreslení pixelů. V navazujících článcích si podrobněji vysvětlíme, jak celý proces funguje.
Soubor atari_antic.inc
Řídicí registry čipu ANTIC, ale například i kódy pro jednotlivé textové či grafické režimy, jsou uloženy v souboru atari_antic.inc, který je nainstalován současně s assemblerem CA65. Tento soubor je relativně krátký a současně postupně využijeme všechny zde definované symboly, takže je možná dobrý nápad si uvést celý jeho obsah:
;------------------------------------------------------------------------- ; ANTIC Address Equates ;------------------------------------------------------------------------- ; Read Addresses VCOUNT = ANTIC + $0B ;vertical line counter PENH = ANTIC + $0C ;light pen horizontal position PENV = ANTIC + $0D ;light pen vertical position NMIST = ANTIC + $0F ;NMI interrupt status ; Write Addresses DMACTL = ANTIC + $00 ;DMA control CHACTL = ANTIC + $01 ;character control DLISTL = ANTIC + $02 ;low display list address DLISTH = ANTIC + $03 ;high display list address HSCROL = ANTIC + $04 ;horizontal scroll VSCROL = ANTIC + $05 ;vertical scroll PMBASE = ANTIC + $07 ;player-missile base address CHBASE = ANTIC + $09 ;character base address WSYNC = ANTIC + $0A ;wait for HBLANK synchronization NMIEN = ANTIC + $0E ;NMI enable NMIRES = ANTIC + $0F ;NMI interrupt reset ;------------------------------------------------------------------------- ; Antic opcodes ;------------------------------------------------------------------------- ; usage example: ; ; ScreenDL: ; .byte DL_BLK8 ; .byte DL_BLK8 ; .byte DL_CHR40x8x1 | DL_LMS | DL_DLI ; .word ScreenAlignment ; .byte DL_BLK1 | DL_DLI ; .byte DL_MAP320x1x1 | DL_LMS ; .word Screen ; ; .repeat 99 ; .byte DL_MAP320x1x1 ; .endrepeat ; .byte DL_MAP320x1x1 | DL_LMS ; .word Screen + 40 * 100 ; 100 lines a 40 byte, 'Screen' has to be aligned correctly! ; .repeat 92 ; .byte DL_MAP320x1x1 ; .endrepeat ; ; .byte DL_JVB ; absolute instructions (non mode lines) DL_JMP = 1 DL_JVB = 65 ; DL_BLKn display n empty lines (just background) DL_BLK1 = 0 DL_BLK2 = 16 DL_BLK3 = 32 DL_BLK4 = 48 DL_BLK5 = 64 DL_BLK6 = 80 DL_BLK7 = 96 DL_BLK8 = 112 ; absolute instructions (mode lines) DL_CHR40x8x1 = 2 ; monochrome, 40 character & 8 scanlines per mode line (GR. 0) DL_CHR40x10x1 = 3 ; monochrome, 40 character & 10 scanlines per mode line DL_CHR40x8x4 = 4 ; colour, 40 character & 8 scanlines per mode line (GR. 12) DL_CHR40x16x4 = 5 ; colour, 40 character & 16 scanlines per mode line (GR. 13) DL_CHR20x8x2 = 6 ; colour (duochrome per character), 20 character & 8 scanlines per mode line (GR. 1) DL_CHR20x16x2 = 7 ; colour (duochrome per character), 20 character & 16 scanlines per mode line (GR. 2) DL_MAP40x8x4 = 8 ; colour, 40 pixel & 8 scanlines per mode line (GR. 3) DL_MAP80x4x2 = 9 ; 'duochrome', 80 pixel & 4 scanlines per mode line (GR.4) DL_MAP80x4x4 = 10 ; colour, 80 pixel & 4 scanlines per mode line (GR.5) DL_MAP160x2x2 = 11 ; 'duochrome', 160 pixel & 2 scanlines per mode line (GR.6) DL_MAP160x1x2 = 12 ; 'duochrome', 160 pixel & 1 scanline per mode line (GR.14) DL_MAP160x2x4 = 13 ; 4 colours, 160 pixel & 2 scanlines per mode line (GR.7) DL_MAP160x1x4 = 14 ; 4 colours, 160 pixel & 1 scanline per mode line (GR.15) DL_MAP320x1x1 = 15 ; monochrome, 320 pixel & 1 scanline per mode line (GR.8) ; modifiers on mode lines... DL_HSCROL = 16 DL_VSCROL = 32 DL_LMS = 64 ; general modifier... DL_DLI = 128
Úprava konfiguračního souboru pro linker
Demonstrační příklady popsané v navazujících kapitolách taktéž vyžadují modifikaci konfiguračního souboru linkeru. Jedná se o soubor nazvaný linker.cfg, do kterého je přidán řádek se specifikací segmentu BSS. Ostatní řádky zůstanou nezměněny:
FEATURES
{
STARTADDRESS: default = $2000;
}
SYMBOLS
{
}
MEMORY
{
ZP: start = $0082, size = $007E, type = rw, define = yes;
HEADER: start = $0000, size = $0006, file = %O;
RAM: start = %S, size = $8000, file = %O;
TRAILER: start = $0000, size = $0006, file = %O;
}
SEGMENTS
{
EXEHDR: load = HEADER, type = ro;
STARTUP: load = RAM, type = ro, define = yes, optional = yes;
ZEROPAGE: load = ZP, type = zp;
CODE: load = RAM, type = ro, define = yes;
AUTOSTRT: load = TRAILER, type = ro;
BSS: load = RAM, type = bss, define = yes;
}
FEATURES
{
CONDES: segment = INIT,
type = constructor,
label = __CONSTRUCTOR_TABLE__,
count = __CONSTRUCTOR_COUNT__;
CONDES: segment = RODATA,
type = destructor,
label = __DESTRUCTOR_TABLE__,
count = __DESTRUCTOR_COUNT__;
CONDES: type = interruptor,
segment = RODATA,
label = __INTERRUPTOR_TABLE__,
count = __INTERRUPTOR_COUNT__;
}
Nastavení display listu s textovým režimem (4 barvy, dvojitá velikost znaků)
Vykreslování herního pole čipem ANTIC probíhá (zjednodušeně řečeno) následujícím způsobem:
- Přečte se instrukce display listu, což je jedna hodnota typu bajt nebo hodnota+dvoubajtová adresa
- Instrukce se provede, což znamená buď vykreslení řádku (text či grafika) nebo skok na jinou instrukci display listu
Existuje několik typů instrukcí, které lze do display listu zapsat:
- Vykreslení osmi prázdných řádků
- Vykreslení textového řádku (písma) nebo grafického řádku (40, 80, 160 či 320 pixelů)
- Skok na jinou instrukci display listu
- Nastavení začátku obrazové paměti + vykreslení textového nebo grafického řádku (kupodivu se jedná o jedinou instrukci)
Pokud budeme chtít na obrazovce zobrazit dvanáct textových řádků režimu GR.2 (ANTIC 7), bude display list vypadat takto:
vykreslení osmi prázdných řádků (sync televize) vykreslení osmi prázdných řádků (sync televize) vykreslení osmi prázdných řádků (sync televize) vykreslení textového řádku ANTIC 7 + nastavení adresy začátku video RAM (jedna instrukce) vykreslení textového řádku ANTIC 7 vykreslení textového řádku ANTIC 7 vykreslení textového řádku ANTIC 7 vykreslení textového řádku ANTIC 7 vykreslení textového řádku ANTIC 7 vykreslení textového řádku ANTIC 7 vykreslení textového řádku ANTIC 7 vykreslení textového řádku ANTIC 7 vykreslení textového řádku ANTIC 7 vykreslení textového řádku ANTIC 7 vykreslení textového řádku ANTIC 7 skok na začátek display listu
Číselně může celý display list vypadat následovně:
.byte 112, 112, 112 .byte 64+7, <screen, >screen .byte 7, 7, 7, 7 .byte 7, 7, 7, 7 .byte 7, 7, 7 .byte 65, <dlist, >dlist
Na druhém řádku je uvedena instrukce 64+7, <screen, >screen. Tato instrukce nastaví počáteční adresu video RAM na blok začínající návěštím screen. A současně se vykreslí jeden textový řádek v režimu GR.2 (ANTIC 7). Samotná video RAM má kapacitu 20×24=480 bajtů a je umístěna v segmentu BSS (ten není uložen ve výsledném .xex souboru – zbytečně by ho „nafukoval“):
.BSS screen: .res 20*24
Výsledek:
Obrázek 14: Dvanáct textových řádků v režimu GR.2 (ANTIC 7).
Úplný zdrojový kód prvního demonstračního příkladu
Podívejme se na úplný zdrojový kód dnešního prvního demonstračního příkladu, který vypadá následovně:
.include "atari.inc"
.CODE
.proc main
lda #<dlist ; nižší byte adresy display listu
sta SDLSTL
lda #>dlist ; vyšší byte adresy display listu
sta SDLSTH
ldy #0 ; počitadlo zápisů
lda #0 ; kód vypisovaného znaku
_fill:
sta screen, y ; tisk znaku na zvolené místo na obrazovce
clc
adc #1
iny ; zvětšit hodnotu počitadla a offsetu
cpy #20*12 ; test na koncovou hodnotu počitadla
bne _fill ; skok, pokud Y>20x12
loop: jmp loop
.endproc
dlist:
.byte 112, 112, 112
.byte 64+7, <screen, >screen
.byte 7, 7, 7, 7
.byte 7, 7, 7, 7
.byte 7, 7, 7
.byte 65, <dlist, >dlist
end:
.BSS
screen: .res 20*24
.segment "EXEHDR"
.word $ffff ; uvodni sekvence bajtu v souboru XEX
.word main ; zacatek kodoveho segmentu
.word end - 1 ; konec kodoveho segmentu
.segment "AUTOSTRT" ; segment s pocatecni adresou
.word RUNAD ; naplni se pouze adresy RUNAD a RUNAD+1
.word RUNAD+1
.word main ; adresa vstupniho bodu do programu
; finito
I assembler může být čitelný: využití konstant definovaných v souboru atari_antic.inc
Pokud se podíváme na řadu čísel z předchozího zdrojového kódu, mohlo by se zdát, že práce v assembleru je při práci s ANTICem plná magie, ve které dosahujeme kýženého výsledku opakováním tajných číselných sekvencí předávaných programátory z generace na generaci:
dlist: .byte 112, 112, 112 .byte 64+7, <screen, >screen .byte 7, 7, 7, 7 .byte 7, 7, 7, 7 .byte 7, 7, 7 .byte 65, <dlist, >dlist
Ovšem ve skutečnosti tak tomu být nemusí, protože si musíme uvědomit, že číselné konstanty jsou vlastně instrukcemi ANTICu a díky hlavičkovému souboru s potřebnými konstantami můžeme tyto instrukce přepsat do rozumnějšího tvaru:
dlist: .byte DL_BLK8, DL_BLK8, DL_BLK8 ; 3x8=24 prázdných obrazových řádků .byte DL_LMS+DL_CHR20x16x2 ; určení počáteční adresy obrazové paměti + jeden řádek režimu 7 .byte <screen, >screen ; počáteční adresa obrazové paměti .byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2) .byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2) .byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2) .byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2) .byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2) .byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2) .byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2) .byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2) .byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2) .byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2) .byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2) .byte DL_JVB, <dlist, >dlist ; skok na začátek display listu
Stále se zde vyskytují symboly < a >. Jedná se o klauzule assembleru, který namísto těchto symbolů dosadí horní nebo dolní bajt adresy, tj. v našem případě konkrétně adresy s obsahem obrazovky screen a adresy začátku display listu dlist.
Výsledek bude po zobrazení na obrazovce totožný s předchozím příkladem:
Obrázek 15: Dvanáct textových řádků v režimu GR.2 (ANTIC 7).
Úplný zdrojový kód druhého demonstračního příkladu
Celý zdrojový kód dnešního druhého demonstračního příkladu se do značné míry podobá příkladu prvnímu, pochopitelně s tím rozdílem, že je nyní výsledek mnohem čitelnější (byla odstraněna většina magických konstant):
.include "atari.inc"
.CODE
.proc main
lda #<dlist ; nižší byte adresy display listu
sta SDLSTL
lda #>dlist ; vyšší byte adresy display listu
sta SDLSTH
ldy #0 ; počitadlo zápisů
lda #0 ; kód vypisovaného znaku
_fill:
sta screen, y ; tisk znaku na zvolené místo na obrazovce
clc
adc #1
iny ; zvětšit hodnotu počitadla a offsetu
cpy #20*12 ; test na koncovou hodnotu počitadla
bne _fill ; skok, pokud Y>20x12
loop: jmp loop
.endproc
dlist:
.byte DL_BLK8, DL_BLK8, DL_BLK8 ; 3x8=24 prázdných obrazových řádků
.byte DL_LMS+DL_CHR20x16x2 ; určení počáteční adresy obrazové paměti + jeden řádek režimu 7
.byte <screen, >screen ; počáteční adresa obrazové paměti
.byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2)
.byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2)
.byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2)
.byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2)
.byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2)
.byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2)
.byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2)
.byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2)
.byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2)
.byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2)
.byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2)
.byte DL_JVB, <dlist, >dlist ; skok na začátek display listu
end:
.BSS
screen: .res 20*24
.segment "EXEHDR"
.word $ffff ; uvodni sekvence bajtu v souboru XEX
.word main ; zacatek kodoveho segmentu
.word end - 1 ; konec kodoveho segmentu
.segment "AUTOSTRT" ; segment s pocatecni adresou
.word RUNAD ; naplni se pouze adresy RUNAD a RUNAD+1
.word RUNAD+1
.word main ; adresa vstupniho bodu do programu
; finito
Kombinace různých textových a grafických režimů
Jednou z nejtypičtějších a vlastně i nejunikátnějších vlastností osmibitových domácích mikropočítačů Atari je schopnost ANTICu na jediné obrazovce střídat různé textové a grafické režimy. Musíme vlastně dodržet jen dvě pravidla: nepřekročit bloky o velikosti čtyř kilobajtů (povíme si příště) a taktéž celkový počet obrazových řádků (včetně prázdných řádků na okrajích) nesmí překročit limit televizoru. Teoreticky je možné zobrazit okolo 228 obrazových řádků, typicky se však používá 192 obrazových řádků (ovšem rozšíření na 200 řádků se zdá být zcela bezpečné). To, jakým způsobem se textové a grafické režimy kombinují v praxi, si povíme příště, kdy si ukážeme display listy některých her (zde mi velmi pomohl kolega MilanV, kterému mockrát děkuji!). Ovšem již dnes si můžeme ukázat, jak bude vypadat výsledná obrazovka, pokud zkombinujeme několik grafických a textových režimů.
Složitější varianta display listu
V dalším demonstračním příkladu bude display list obsahovat textové režimy GR.0, GR.1 i GR.2. Kromě toho pro zajímavost zařadím dva řádky grafického režimu GR.3, který umožňuje zobrazit 40 pixelů na řádku (pixelem je myšlena logická jednotka, fyziky se takový pixel vlastně skládá z celé řady pixelů obrazovky). Celková délka display listu je navržena tak, aby se nepřekročil celkový povolený počet obrazových řádků:
.byte DL_BLK8, DL_BLK8, DL_BLK8 ; 3x8=24 prázdných obrazových řádků .byte DL_LMS+DL_CHR20x16x2 ; určení počáteční adresy obrazové paměti + jeden řádek režimu 7 .byte <screen, >screen ; počáteční adresa obrazové paměti .byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2) .byte DL_CHR40x8x1 ; jeden řádek textového režimu 2 (GR.0) .byte DL_CHR20x8x2 ; jeden řádek textového režimu 6 (GR.1) .byte DL_CHR40x8x1 ; jeden řádek textového režimu 2 (GR.0) .byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2) .byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2) .byte DL_MAP40x8x4 ; jeden řádek grafického režimu 8 (GR.3) .byte DL_MAP40x8x4 ; jeden řádek grafického režimu 8 (GR.3) .byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2) .byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2) .byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2) .byte DL_CHR40x8x1 ; jeden řádek textového režimu 2 (GR.0) .byte DL_JVB, <dlist, >dlist ; skok na začátek display listu
Počet obrazových řádků si můžeme snadno vypočítat:
DL_BLK8, DL_BLK8, DL_BLK8 24
DL_LMS+DL_CHR20x16x2 16
DL_CHR20x16x2 16
DL_CHR40x8x1 8
DL_CHR20x8x2 8
DL_CHR40x8x1 8
DL_CHR20x16x2 16
DL_CHR20x16x2 16
DL_MAP40x8x4 8
DL_MAP40x8x4 8
DL_CHR20x16x2 16
DL_CHR20x16x2 16
DL_CHR20x16x2 16
DL_CHR40x8x1 8
-----
184
Výsledkem je pěkný guláš:
Obrázek 16: Mix různých textových a grafických režimů.
Úplný zdrojový kód třetího demonstračního příkladu
Zdrojový kód třetího a současně i dnes posledního demonstračního příkladu vypadá následovně:
.include "atari.inc"
.CODE
.proc main
lda #<dlist ; nižší byte adresy display listu
sta SDLSTL
lda #>dlist ; vyšší byte adresy display listu
sta SDLSTH
ldy #0 ; počitadlo zápisů
lda #0 ; kód vypisovaného znaku
_fill:
sta screen, y ; tisk znaku na zvolené místo na obrazovce
clc
adc #1
iny ; zvětšit hodnotu počitadla a offsetu
cpy #40*6 ; test na koncovou hodnotu počitadla
bne _fill ; skok, pokud Y>40*6
loop: jmp loop
.endproc
dlist:
.byte DL_BLK8, DL_BLK8, DL_BLK8 ; 3x8=24 prázdných obrazových řádků
.byte DL_LMS+DL_CHR20x16x2 ; určení počáteční adresy obrazové paměti + jeden řádek režimu 7
.byte <screen, >screen ; počáteční adresa obrazové paměti
.byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2)
.byte DL_CHR40x8x1 ; jeden řádek textového režimu 2 (GR.0)
.byte DL_CHR20x8x2 ; jeden řádek textového režimu 6 (GR.1)
.byte DL_CHR40x8x1 ; jeden řádek textového režimu 2 (GR.0)
.byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2)
.byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2)
.byte DL_MAP40x8x4 ; jeden řádek grafického režimu 8 (GR.3)
.byte DL_MAP40x8x4 ; jeden řádek grafického režimu 8 (GR.3)
.byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2)
.byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2)
.byte DL_CHR20x16x2 ; jeden řádek textového režimu 7 (GR.2)
.byte DL_CHR40x8x1 ; jeden řádek textového režimu 2 (GR.0)
.byte DL_JVB, <dlist, >dlist ; skok na začátek display listu
end:
.BSS
screen: .res 20*24
.segment "EXEHDR"
.word $ffff ; uvodni sekvence bajtu v souboru XEX
.word main ; zacatek kodoveho segmentu
.word end - 1 ; konec kodoveho segmentu
.segment "AUTOSTRT" ; segment s pocatecni adresou
.word RUNAD ; naplni se pouze adresy RUNAD a RUNAD+1
.word RUNAD+1
.word main ; adresa vstupniho bodu do programu
; finito
Příloha: Makefile pro překlad všech demonstračních příkladů
Všechny minule i dnes popsané demonstrační příklady, pro jejichž překlad je zapotřebí použít assembler ca65 a linker ld65, je možné přeložit s využitím souboru Makefile, jehož obsah je vypsán pod tímto odstavcem:
execs := dummy.xex print_a.xex \
background_color_1.xex background_color_2.xex \
color_computation_1.xex color_computation_2.xex \
subroutine_1.xex subroutine_2.xex \
hex_number_1.xex hex_number_2.xex \
hex_number_3.xex hex_number_4.xex \
hex_number_5.xex hex_number_6.xex \
hex_number_7.xex hex_number_8.xex \
hex_number_9.xex \
fill_block_1.xex fill_block_2.xex \
fill_block_3.xex fill_block_4.xex \
fill_block_5.xex \
pmg_01.xex pmg_02.xex \
pmg_03.xex pmg_04.xex \
pmg_05.xex pmg_06.xex \
pmg_07.xex pmg_08.xex \
pmg_09.xex pmg_10.xex \
pmg_11.xex pmg_12.xex \
pmg_13.xex pmg_14.xex \
pmg_15.xex pong.xex \
pmg_stick_1.xex pmg_stick_2.xex \
pmg_stick_3.xex pmg_stick_4.xex \
pmg_stick_5.xex pmg_stick_6.xex \
pmg_collisions_1.xex pmg_collisions_2.xex \
pmg_collisions_3.xex pmg_collisions_4.xex \
antic_1.xex antic_2.xex \
antic_3.xex
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)
