Integrovaný obvod POKEY z herních automatů i počítačů Atari je víceúčelovým čipem. Realizuje tvorbu zvuků a hudby, čtení stavů ovladačů paddle, čtení kláves, obsahuje generátor pseudonáhodných čísel a taktéž sériový I/O.
Poznámka: samotná zkratka POKEY znamená Pot Keyboard Integrated Circuit, z čehož plyne, že se větší důraz kladl na práci s klávesnicí a čtení natočení potenciometrů (použity jsou v ovladačích typu paddle). Tedy na rozdíl od SIDu (Sound Interface Device) není v názvu POKEY zmíněn ani zvukový subsystém, ani systém pro sériové vstup-výstup (I/O).
Ovládání či naopak čtení stavu čipu POKEY se provádí s využitím řídicích a stavových registrů. Adresový rozsah vyhrazený pro POKEY je roven šestnácti adresám, ovšem využívá se jich jen 14 pro čtení a 15 pro zápis. Jak je na osmibitových Atari zvykem, je při zápisu na určitou adresu použit (zcela) odlišný registr, než pro čtení. Konkrétně tedy při čtení z adresy $d200 získáme stav natočení prvního paddle, kdežto při zápisu na stejnou adresu nastavujeme děličku frekvence prvního zvukového kanálu. I z tohoto důvodu existují pro vybrané registry takzvané stínové registry, což jsou místa v operační paměti, kam operační systém zapisuje stejné informace, jaké zapisuje do řídicích registrů (odsud totiž není možné čtení provést):
| Jméno | Stínový registr | Čtení/zápis | Adresa | Stručný popis |
|---|---|---|---|---|
| POT0 | PADDL0 | čtení | $d200 | měření natočení prvního paddle |
| POT1 | PADDL1 | čtení | $d201 | měření natočení druhého paddle |
| POT2 | PADDL2 | čtení | $d202 | měření natočení třetího paddle |
| POT3 | PADDL3 | čtení | $d203 | měření natočení čtvrtého paddle |
| POT4 | PADDL4 | čtení | $d204 | měření natočení pátého paddle |
| POT5 | PADDL5 | čtení | $d205 | měření natočení šestého paddle |
| POT6 | PADDL6 | čtení | $d206 | měření natočení sedmého paddle |
| POT7 | PADDL7 | čtení | $d207 | měření natočení osmého paddle |
| ALLPOT | čtení | $d208 | stav měření všech osmi paddle (0 znamená validní informaci, 1 prováděné měření) | |
| KBCODE | CH | čtení | $d209 | kód stisknuté klávesy (což není zcela přesné, viz další text) |
| RANDOM | čtení | $d20a | hodnota generátoru pseudonáhodných hodnot | |
| SERIN | čtení | $d20d | buffer pro data posílaná po sériovém portu (čtení-příjem) | |
| IRQST | čtení | $d20e | stav jednotlivých přerušení (IRQ) | |
| SKSTAT | čtení | $d20f | stavový registr sériového portu | |
| AUDF1 | zápis | $d200 | nastavení děličky frekvence prvního zvukového kanálu | |
| AUDC1 | zápis | $d201 | hlasitost + zkreslení (poly čítače) prvního zvukového kanálu | |
| AUDF2 | zápis | $d202 | nastavení děličky frekvence druhého zvukového kanálu | |
| AUDC2 | zápis | $d203 | hlasitost + zkreslení (poly čítače) druhého zvukového kanálu | |
| AUDF3 | zápis | $d204 | nastavení děličky frekvence třetího zvukového kanálu | |
| AUDC3 | zápis | $d205 | hlasitost + zkreslení (poly čítače) třetího zvukového kanálu | |
| AUDF4 | zápis | $d206 | nastavení děličky frekvence čtvrtého zvukového kanálu | |
| AUDC4 | zápis | $d207 | hlasitost + zkreslení (poly čítače) čtvrtého zvukového kanálu | |
| AUDCTL | zápis | $d208 | globální nastavení celého zvukového subsystému (frekvence+spojení zvukových kanálů) | |
| STIMER | zápis | $d209 | zapnutí časovače | |
| SKRES | zápis | $d20a | zápis jakékoli hodnoty provede vynulování bitů 5 až 7 registru SKSTAT | |
| POTGO | zápis | $d20b | inicializace měření natočení paddle (vybití kondenzátorů) | |
| SEROUT | zápis | $d20d | buffer pro data posílaná po sériovém portu (zápis-vysílání) | |
| IRQEN | POKMSK | zápis | $d20e | povolení či zákaz jednotlivých přerušení |
| SKCTL | SSKCLT | zápis | $d20f | řízení sériového portu, režimu čtení klávesnice a rychlého čtení paddle |
Alternativně je možné registry rozdělit podle subsystému, který ovládají nebo o němž zjišťují stav.
Zvukový subsystém:
| Jméno | Stínový registr | Čtení/zápis | Adresa | Stručný popis |
|---|---|---|---|---|
| AUDF1 | zápis | $d200 | nastavení děličky frekvence prvního zvukového kanálu | |
| AUDC1 | zápis | $d201 | hlasitost + zkreslení (poly čítače) prvního zvukového kanálu | |
| AUDF2 | zápis | $d202 | nastavení děličky frekvence druhého zvukového kanálu | |
| AUDC2 | zápis | $d203 | hlasitost + zkreslení (poly čítače) druhého zvukového kanálu | |
| AUDF3 | zápis | $d204 | nastavení děličky frekvence třetího zvukového kanálu | |
| AUDC3 | zápis | $d205 | hlasitost + zkreslení (poly čítače) třetího zvukového kanálu | |
| AUDF4 | zápis | $d206 | nastavení děličky frekvence čtvrtého zvukového kanálu | |
| AUDC4 | zápis | $d207 | hlasitost + zkreslení (poly čítače) čtvrtého zvukového kanálu | |
| AUDCTL | zápis | $d208 | globální nastavení celého zvukového subsystému (frekvence+spojení zvukových kanálů) |
Práce s ovladači typu paddle:
| Jméno | Stínový registr | Čtení/zápis | Adresa | Stručný popis |
|---|---|---|---|---|
| POT0 | PADDL0 | čtení | $d200 | měření natočení prvního paddle |
| POT1 | PADDL1 | čtení | $d201 | měření natočení druhého paddle |
| POT2 | PADDL2 | čtení | $d202 | měření natočení třetího paddle |
| POT3 | PADDL3 | čtení | $d203 | měření natočení čtvrtého paddle |
| POT4 | PADDL4 | čtení | $d204 | měření natočení pátého paddle |
| POT5 | PADDL5 | čtení | $d205 | měření natočení šestého paddle |
| POT6 | PADDL6 | čtení | $d206 | měření natočení sedmého paddle |
| POT7 | PADDL7 | čtení | $d207 | měření natočení osmého paddle |
| ALLPOT | čtení | $d208 | stav měření všech osmi paddle (0 znamená validní informaci, 1 prováděné měření) | |
| POTGO | zápis | $d20b | inicializace měření natočení paddle (vybití kondenzátorů) |
Sériový I/O port:
| Jméno | Stínový registr | Čtení/zápis | Adresa | Stručný popis |
|---|---|---|---|---|
| SERIN | čtení | $d20d | buffer pro data posílaná po sériovém portu (čtení-příjem) | |
| SKSTAT | čtení | $d20f | stavový registr sériového portu | |
| SEROUT | zápis | $d20d | buffer pro data posílaná po sériovém portu (zápis-vysílání) | |
| SKCTL | SSKCLT | zápis | $d20f | řízení sériového portu, režimu čtení klávesnice a rychlého čtení paddle |
| SKRES | zápis | $d20a | zápis jakékoli hodnoty provede vynulování bitů 5 až 7 registru SKSTAT |
Klávesnice:
| Jméno | Stínový registr | Čtení/zápis | Adresa | Stručný popis |
|---|---|---|---|---|
| KBCODE | CH | čtení | $d209 | kód stisknuté klávesy (což není zcela přesné, viz další text) |
IRQ:
| Jméno | Stínový registr | Čtení/zápis | Adresa | Stručný popis |
|---|---|---|---|---|
| IRQST | čtení | $d20e | stav jednotlivých přerušení (IRQ) | |
| IRQEN | POKMSK | zápis | $d20e | povolení či zákaz jednotlivých přerušení |
Generátor pseudonáhodných hodnot a časovač:
| Jméno | Stínový registr | Čtení/zápis | Adresa | Stručný popis |
|---|---|---|---|---|
| RANDOM | čtení | $d20a | hodnota generátoru pseudonáhodných hodnot | |
| STIMER | zápis | $d209 | zapnutí časovače |
Při programování v assembleru samozřejmě nemusíme pracovat přímo s číselnými adresami registrů POKEY, protože v souboru atari.inc máme k dispozici příslušné konstanty. Zejména počáteční adresu adresové prostoru čipu POKEY:
POKEY = $D200 ;POKEY area
Adresy jednotlivých registrů jsou pak od POKEY odvozeny:
; Read Addresses POT0 = POKEY + $00 ;potentiometer 0 POT1 = POKEY + $01 ;potentiometer 1 POT2 = POKEY + $02 ;potentiometer 2 POT3 = POKEY + $03 ;potentiometer 3 POT4 = POKEY + $04 ;potentiometer 4 POT5 = POKEY + $05 ;potentiometer 5 POT6 = POKEY + $06 ;potentiometer 6 POT7 = POKEY + $07 ;potentiometer 7 ALLPOT = POKEY + $08 ;potentiometer port status KBCODE = POKEY + $09 ;keyboard code RANDOM = POKEY + $0A ;random number generator SERIN = POKEY + $0D ;serial port input IRQST = POKEY + $0E ;IRQ interrupt status SKSTAT = POKEY + $0F ;serial port and keyboard status ; Write Addresses AUDF1 = POKEY + $00 ;channel 1 audio frequency AUDC1 = POKEY + $01 ;channel 1 audio control AUDF2 = POKEY + $02 ;channel 2 audio frequency AUDC2 = POKEY + $03 ;channel 2 audio control AUDF3 = POKEY + $04 ;channel 3 audio frequency AUDC3 = POKEY + $05 ;channel 3 audio control AUDF4 = POKEY + $06 ;channel 4 audio frequency AUDC4 = POKEY + $07 ;channel 4 audio control AUDCTL = POKEY + $08 ;audio control STIMER = POKEY + $09 ;start timers SKRES = POKEY + $0A ;reset SKSTAT status POTGO = POKEY + $0B ;start potentiometer scan sequence SEROUT = POKEY + $0D ;serial port output IRQEN = POKEY + $0E ;IRQ interrupt enable SKCTL = POKEY + $0F ;serial port and keyboard control
Praktickou část dnešního článku začneme tou nejjednodušší vlastností čipu POKEY. Přes stavový registr RANDOM (určen je jen pro čtení) je totiž možné v libovolný okamžik přečíst osm bitů s pseudonáhodnými hodnotami. Interně je pro generování pseudonáhodných hodnot využit sedmnáctibitový posuvný registr se zpětnou vazbou (poly čítač, LFSR – Linear-feedback shift register), s nímž jsme se již setkali při popisu zvukového subsystému. Tento poly čítač tedy slouží jak ke generování šumu, tak i pseudonáhodných hodnot (ostatně proč nevyužít již tak drahé tranzistory pro více účelů?). Tento čítač mění svůj stav s frekvencí CPU (tedy cca 1,7 MHz) a registr RANDOM lze díky tomu, že v počítači vznikají a jsou zpracovávána různá přerušení, dochází k přerušení od ANTICu atd., považovat za dostatečně kvalitní generátor (pseudo)náhodných hodnot – pro hry je vhodný zcela jistě a pro kryptografické aplikace nejsou osmibitová Atari určena :-)
V dnešním prvním demonstračním příkladu se na prvních šest textových řádků standardního grafického režimu GR.0 vypíšou náhodné ATASCII znaky, jejichž kódy byly získány právě čtením registru RANDOM:
Obrázek 1: Pseudonáhodné znaky generované s využitím čipu POKEY.
Autor: tisnik, podle licence: Rights Managed
Po každém stisku klávesy se provede překreslení obrazovky novou sadou pseudonáhodných znaků:
Obrázek 2: Odlišné pseudonáhodné znaky generované s využitím čipu POKEY.
Autor: tisnik, podle licence: Rights Managed
Poznámka: pouhých šest textových řádků a nikoli celou obrazovku používám z toho důvodu, že 6×40<255 a tedy samotná realizace programové smyčky si vystačí s jediným osmibitovým počitadlem realizovaným index registrem Y. Proč zrovna Y a ne X? Odpověď dá použitý adresovací režim):
ldy #0 ; počitadlo zápisů
fills:
lda RANDOM
sta (88), y ; tisk znaku na zvolené místo na obrazovce
; (adresa Video RAM je na adresách 88 a 89)
iny ; zvětšit hodnotu počitadla a offsetu
cpy #40*6 ; test na koncovou hodnotu počitadla
bne fills ; skok, pokud Y>40*6
Následuje výpis úplného zdrojového kódu tohoto demonstračního příkladu:
; ---------------------------------------------------------------------
; Vyplnění bloku náhodnými hodnotami.
; ---------------------------------------------------------------------
.include "atari.inc"
.CODE
.proc main
loop:
ldy #0 ; počitadlo zápisů
fills:
lda RANDOM
sta (88), y ; tisk znaku na zvolené místo na obrazovce
; (adresa Video RAM je na adresách 88 a 89)
iny ; zvětšit hodnotu počitadla a offsetu
cpy #40*6 ; test na koncovou hodnotu počitadla
bne fills ; skok, pokud Y>40*6
jsr get_key
jmp loop
.endproc
; ---------------------------------------------------------------------
; čekání na stisk klávesy
; ---------------------------------------------------------------------
.proc get_key
KBHANDLER = $e424 ; rutina pro cteni klavesy
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
U generátorů pseudonáhodných hodnot vždy stojíme před otázkou: do jaké míry jsou čtené hodnoty „náhodné“ a zda mají dostatečně dlouhou periodu (ostatně samotná existence konečné periody znamená, že hodnoty nejsou skutečně náhodné). Pochopitelně bychom pro analýzu mohli použít různé předpřipravené nástroje, ovšem pro jednoduchost si vystačíme s lidským mozkem a jeho systémem rozpoznávání vzorů (v chaosu). Nejprve nastavíme monochromatický grafický režim a následně do obrazové paměti uložíme pseudonáhodné hodnoty získané čtením z registru RANDOM. Pokud vznikne ve čtených datech krátká perioda popř. se nějaké vzorky budou opakovat, lidský mozek by tuto skutečnost měl zaznamenat.
Monochromatický režim bude mít rozlišení 80×48 pixelů (není nutné řešit stránkování) a jeho display list vypadá takto:
dlist: .byte DL_BLK8, DL_BLK8, DL_BLK8 ; 3x8=24 prázdných obrazových řádků .byte DL_LMS+DL_MAP80x4x2 ; určení počáteční adresy obrazové paměti + jeden řádek režimu 9 (GR.4) .byte <screen, >screen ; počáteční adresa obrazové paměti .res 47, DL_MAP80x4x2 ; opakovat řádky grafického režimu 9 (GR.4) .byte DL_JVB, dlist ; skok na začátek display listu
V dnešním druhém demonstračním příkladu se nejdříve nastaví monochromatický grafický režim s rozlišením 80×48 pixelů, přičemž obrazovka bude inicializována statickými daty:
Obrázek 3: Na začátku má obrazová paměť tento obsah.
Autor: tisnik, podle licence: Rights Managed
Po stisku libovolné klávesy se prvních 240 bajtů, tedy prvních 24 obrazových řádků přepíše pseudonáhodnými daty přečtenými z registru RANDOM:
Obrázek 4: Vyplnění prvních 240 bajtů obrazové paměti pseudonáhodnými daty.
Autor: tisnik, podle licence: Rights Managed
Každý další stisk klávesy tuto první část obrazové paměti přepíše novými pseudonáhodnými hodnotami:
Obrázek 5: Vyplnění prvních 240 bajtů obrazové paměti odlišnými pseudonáhodnými daty.
Autor: tisnik, podle licence: Rights Managed
Úplný zdrojový kód takto upraveného demonstračního příkladu vypadá následovně:
; ---------------------------------------------------------------------
; Vyplnění bloku náhodnými hodnotami.
; ---------------------------------------------------------------------
.include "atari.inc"
.CODE
.proc main
lda #0 ; kod barvy
sta COLOR0 ; ulozit do registru COLOR2
lda #10 ; kod barvy
sta COLOR4 ; ulozit do registru COLOR4
lda #<dlist ; nižší byte adresy display listu
sta SDLSTL
lda #>dlist ; vyšší byte adresy display listu
sta SDLSTH
jsr get_key
loop:
ldy #0 ; počitadlo zápisů
fills:
lda RANDOM
sta screen, y ; tisk znaku na zvolené místo na obrazovce
iny ; zvětšit hodnotu počitadla a offsetu
cpy #40*6 ; test na koncovou hodnotu počitadla
bne fills ; skok, pokud Y>40*6
jsr get_key
jmp loop
.endproc
; ---------------------------------------------------------------------
; čekání na stisk klávesy
; ---------------------------------------------------------------------
.proc get_key
KBHANDLER = $e424 ; rutina pro cteni klavesy
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
dlist:
.byte DL_BLK8, DL_BLK8, DL_BLK8 ; 3x8=24 prázdných obrazových řádků
.byte DL_LMS+DL_MAP80x4x2 ; určení počáteční adresy obrazové paměti + jeden řádek režimu 9 (GR.4)
.byte <screen, >screen ; počáteční adresa obrazové paměti
.res 47, DL_MAP80x4x2 ; opakovat řádky grafického režimu 9 (GR.4)
.byte DL_JVB, dlist ; skok na začátek display listu
screen: ; video paměť
.include "image_80x48.asm"
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
Další, v pořadí již třetí demonstrační příklad, vykresluje pseudonáhodné pixely na celou obrazovku. Díky použitému grafickému režimu je nutné vyplnit pouze 480 bajtů, což znamená dvojici programových smyček (každá pro vyplnění resp. nastavení 240 bajtů). Poněkud naivní, ale na druhou stranu plně funkční, způsob implementace může vypadat takto:
fills1:
lda RANDOM
sta screen, y ; tisk osmice pixelu na zvolené místo na obrazovce
iny ; zvětšit hodnotu počitadla a offsetu
cpy #40*6 ; test na koncovou hodnotu počitadla
bne fills1 ; skok, pokud Y>40*6
ldy #0 ; počitadlo zápisů
fills2:
lda RANDOM
sta screen+40*6, y ; tisk osmice pixelu na zvolené místo na obrazovce
iny ; zvětšit hodnotu počitadla a offsetu
cpy #40*6 ; test na koncovou hodnotu počitadla
bne fills2 ; skok, pokud Y>40*6
Obrázek 6: Vyplnění celé obrazové paměti (480 bajtů) pseudonáhodnými daty.
Autor: tisnik, podle licence: Rights Managed
Obrázek 7: Odlišné pseudonáhodné hodnoty vyplňující celou obrazovou paměť.
Autor: tisnik, podle licence: Rights Managed
Úplný zdrojový kód takto rozšířeného demonstračního příkladu vypadá následovně:
; ---------------------------------------------------------------------
; Vyplnění bloku náhodnými hodnotami.
; ---------------------------------------------------------------------
.include "atari.inc"
.CODE
.proc main
lda #0 ; kod barvy
sta COLOR0 ; ulozit do registru COLOR2
lda #10 ; kod barvy
sta COLOR4 ; ulozit do registru COLOR4
lda #<dlist ; nižší byte adresy display listu
sta SDLSTL
lda #>dlist ; vyšší byte adresy display listu
sta SDLSTH
jsr get_key
loop:
ldy #0 ; počitadlo zápisů
fills1:
lda RANDOM
sta screen, y ; tisk osmice pixelu na zvolené místo na obrazovce
iny ; zvětšit hodnotu počitadla a offsetu
cpy #40*6 ; test na koncovou hodnotu počitadla
bne fills1 ; skok, pokud Y>40*6
ldy #0 ; počitadlo zápisů
fills2:
lda RANDOM
sta screen+40*6, y ; tisk osmice pixelu na zvolené místo na obrazovce
iny ; zvětšit hodnotu počitadla a offsetu
cpy #40*6 ; test na koncovou hodnotu počitadla
bne fills2 ; skok, pokud Y>40*6
jsr get_key
jmp loop
.endproc
; ---------------------------------------------------------------------
; čekání na stisk klávesy
; ---------------------------------------------------------------------
.proc get_key
KBHANDLER = $e424 ; rutina pro cteni klavesy
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
dlist:
.byte DL_BLK8, DL_BLK8, DL_BLK8 ; 3x8=24 prázdných obrazových řádků
.byte DL_LMS+DL_MAP80x4x2 ; určení počáteční adresy obrazové paměti + jeden řádek režimu 9 (GR.4)
.byte <screen, >screen ; počáteční adresa obrazové paměti
.res 47, DL_MAP80x4x2 ; opakovat řádky grafického režimu 9 (GR.4)
.byte DL_JVB, <dlist, >dlist ; skok na začátek display listu
screen: ; video paměť
.include "image_80x48.asm"
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
Výhodnější však může být uložení „vyplňovací smyčky“ do makra, kterému se předá počáteční adresa vyplňovaného bloku a celkový počet bajtů (do 255):
.macro fill_random_pixels address, size
.local fills
ldy #0 ; počitadlo zápisů
fills:
lda RANDOM
sta address, y ; tisk znaku osmice pixelu na zvolené místo na obrazovce
iny ; zvětšit hodnotu počitadla a offsetu
cpy size ; test na koncovou hodnotu počitadla
bne fills ; skok, pokud Y>size
ldy #0 ; počitadlo zápisů
.endmacro
Toto makro bude v programu expandováno celkem dvakrát:
fill_random_pixels screen, 40*6
fill_random_pixels screen+40*6, 40*6
Výsledný programový kód bude po těchto úpravách vypadat takto:
; ---------------------------------------------------------------------
; Vyplnění bloku náhodnými hodnotami.
; ---------------------------------------------------------------------
.include "atari.inc"
.CODE
.macro fill_random_pixels address, size
.local fills
ldy #0 ; počitadlo zápisů
fills:
lda RANDOM
sta address, y ; tisk znaku osmice pixelu na zvolené místo na obrazovce
iny ; zvětšit hodnotu počitadla a offsetu
cpy size ; test na koncovou hodnotu počitadla
bne fills ; skok, pokud Y>size
ldy #0 ; počitadlo zápisů
.endmacro
.proc main
lda #0 ; kod barvy
sta COLOR0 ; ulozit do registru COLOR2
lda #10 ; kod barvy
sta COLOR4 ; ulozit do registru COLOR4
lda #<dlist ; nižší byte adresy display listu
sta SDLSTL
lda #>dlist ; vyšší byte adresy display listu
sta SDLSTH
jsr get_key
loop:
fill_random_pixels screen, 40*6
fill_random_pixels screen+40*6, 40*6
jsr get_key
jmp loop
.endproc
; ---------------------------------------------------------------------
; čekání na stisk klávesy
; ---------------------------------------------------------------------
.proc get_key
KBHANDLER = $e424 ; rutina pro cteni klavesy
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
dlist:
.byte DL_BLK8, DL_BLK8, DL_BLK8 ; 3x8=24 prázdných obrazových řádků
.byte DL_LMS+DL_MAP80x4x2 ; určení počáteční adresy obrazové paměti + jeden řádek režimu 9 (GR.4)
.byte <screen, >screen ; počáteční adresa obrazové paměti
.res 47, DL_MAP80x4x2 ; opakovat řádky grafického režimu 9 (GR.4)
.byte DL_JVB, <dlist, >dlist ; skok na začátek display listu
screen: ; video paměť
.include "image_80x48.asm"
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
Vraťme se na chvíli do dávné IT minulosti, konkrétně do roku 1966. Právě tehdy Nolan Bushnell najal mladého inženýra Allana Alcorna, aby pro něj navrhl a zkonstruoval závodní hru (vývoj probíhal paralelně s vývojem Computer Space). Pokud by Alan skutečně toto zadání zdárně dokončil, jednalo by se s velkou pravděpodobností o první závodní hru tohoto typu na světě, po několika týdnech vývoje se však ukázalo, že se při tehdejší úrovni integrace elektronických obvodů jedná o příliš ambiciózní projekt, protože výsledný produkt by byl velký a především drahý. Allan Alcorn tedy místo implementačně komplikované závodní hry vytvořil vlastní kopii hry Pong, která se stala velmi úspěšným titulem a velkou měrou přispěla k dalšímu vývoji herních automatů a posléze i domácích herních konzolí (nejdůležitější byl fakt, že se i další firmy začaly o toto zcela nové průmyslové odvětví zajímat, což pozitivně přispělo k vývoji dalších technologií, na jejichž konci stojí moderní osobní počítače)

Obrázek 8: Al Alcorn byl v pořadí třetím zaměstnancem firmy Atari.
Automat s touto hrou sice pro vykreslování herní scény používal rastrový displej (obyčejnou černobílou televizní obrazovku), ovšem dnes zcela běžný framebuffer, tj. obrazová paměť, ve které je uložena předloha vykreslovaného rastrového obrázku, zde nebyl implementován – namísto toho se obraz generoval v sadě integrovaných obvodů řízených přesným hodinovým signálem, podobně jako ve výše zmíněné hře Computer Space. V souvislosti s videohrou Pong se setkáváme s další důležitou firmou. Jedná se o společnost Magnavox, která vytvořila herní konzoli Odyssey právě se hrou Pong. Vzhledem k tomu, že konzole Odyssey byla vytvořena dříve než automat Pong, byl Nolan Bushnell a jeho právě založená firma Atari zažalována (korunu tomu dodal fakt, že Bushnell byl zapsán v seznamu hostů pozvaných na představení konzole Odyssey ještě před jejím vydáním a samozřejmě též před vydáním videohry Pong). Výsledkem tohoto soudního sporu bylo, že firma Atari v roce 1976 zakoupila „licenci“ za 700 000 dolarů na hru Pong, a tuto licenci samozřejmě zaplatila z výnosů, které jí tento herní automat přinášel.

Obrázek 9: Hra Pong ve variantě z roku 1972.
Proč jsme se však o hře Pong vůbec zmiňovali? Není to proto, že by se jednalo o výrobek společnosti Atari, ale z toho důvodu, že se hra Pong ovládala dvojicí otočných ovladačů. Natočením se měnil odpor, který byl periodicky měřen a hra reagovala na vypočtenou hodnotu. Později byl podobný způsob ovládání použit i v domácí (přenosné) variantě hry Pong. A protože se ve stolním tenisu (ping pong) rakety označují slovem paddle, vžilo se toto označení i pro otočné herní ovladače, které interně využívaly buď rotační enkodér nebo (častěji) běžný potenciometr. A právě druhý typ ovladačů založených na potenciometru je podporován i osmibitovými domácími mikropočítači Atari. Ovladače typu paddle se připojovaly do stejných konektorů, jako joysticky. A vzhledem k tomu, že do jednoho joystickového konektoru mohly být připojeny dva ovladače typu paddle (piny paddle A a paddle B), bylo možné podle typu počítače pracovat buď se čtyřmi (série XL a XE) nebo dokonce osmi (původní Atari 400 a Atari 800) otočnými ovladači.

Obrázek 10: Kabinet se hrou Pong. Z panelu pod obrazovkou je patrné minimalistické pojetí ovládání této hry s využitím dvojice paddle.
Každý ovladač paddle je většinou představovaný běžným potenciometrem, který je zapojen mezi pin s pěti volty a vstupní pin číslo 5 nebo 9 na joystickovém konektoru. Interně je každý z pinů (5, 9) interně zapojen ke kondenzátoru, který má svou druhou elektrodu uzemněnou. A navíc je paralelně ke kondenzátoru zapojen tranzistor ovládaný softwarově. Počítač při zjišťování, jak je paddle (a tedy vlastně potenciometr) natočen, provádí tyto operace:
Konkrétní způsob měření je prováděn operačním systémem a je odvozen – jako ostatně i mnoho dalších činností – od časování grafického subsystému. Konkrétně se čas měří v délce trvání obrazových řádků, ať již viditelných či neviditelných. Hodnoty, které jsou naměřeny, jsou tak v rozsahu 0 až 228, což je (jaká náhoda) rozsah horizontálních pozic spritů. Některé hry tedy mohly načtené údaje o natočení přímo použít pro horizontální pozicování hráče.
Pro čtení hodnoty ovladačů paddle (je jich teoreticky celkem osm, prakticky ovšem spíše maximálně čtyři) se používá deset registrů čipu POKEY. Devět z těchto registrů je použito pro čtení, desátý registr naopak slouží pro zápis:
| Jméno | Stínový registr | Čtení/zápis | Adresa | Stručný popis |
|---|---|---|---|---|
| POT0 | PADDL0 | čtení | $d200 | měření natočení prvního paddle |
| POT1 | PADDL1 | čtení | $d201 | měření natočení druhého paddle |
| POT2 | PADDL2 | čtení | $d202 | měření natočení třetího paddle |
| POT3 | PADDL3 | čtení | $d203 | měření natočení čtvrtého paddle |
| POT4 | PADDL4 | čtení | $d204 | měření natočení pátého paddle |
| POT5 | PADDL5 | čtení | $d205 | měření natočení šestého paddle |
| POT6 | PADDL6 | čtení | $d206 | měření natočení sedmého paddle |
| POT7 | PADDL7 | čtení | $d207 | měření natočení osmého paddle |
| ALLPOT | čtení | $d208 | stav měření všech osmi paddle (0 znamená validní informaci, 1 prováděné měření) | |
| POTGO | zápis | $d20b | inicializace měření natočení paddle (vybití kondenzátorů) |
Jak čtení probíhá? Typicky se na konci VBI rutiny provede zápis libovolné hodnoty do registru POTGO, čímž se zapne měření odporu (resp. času nabíjení kondenzátoru připojeného do série s potenciometrem):
LDA #cokoli STA POTGO
Teoreticky je poté možné čekat na nastavení nulových bitů v registru ALLPOT. Jakmile je příslušný bit nulový, je hodnota uložená v odpovídajícím registru POTx korektní (kondenzátor se nabil). Ovšem prakticky víme, že hodnoty POTx budou korektní až v následujícím snímku, takže je opět můžeme vyčíst v subrutině VBI:
LDA POT0 ... ... ...
Poznámka: většinou nám postačuje čtení nové hodnoty v každém snímku. Rychlejší čtení je možné, ale nebude přesné (ukážeme si příště).
Ve skutečnosti je veškerá obsluha paddle řešena již na úrovni operačního systému, který automaticky nastavuje stínové registry PADDLx. Původní ROM počítačů Atari obsahuje mj. i následující sekvenci instrukcí, která je součástí subrutiny VBI:
; Source: original Atari ROMs 1508 E883 A2 03 LDX #3 1509 EBBS BD 10 D0 STRL: LDA TRIGO,X ;MOVE JOYSTICK TRIGGERS 1510 EBBS 90 84 02 STA STRIGO,X 1511 E8BB BD 00 D2 LDA POTO,X ;MOVE POT VALUES 1512 EBBE 9D 70 02 STA PADDLO,X 1513 E8C1 BD 04 D2 LDA POT4,X 1514 EBC4 9D 74 02 STA PADDL4,X 1515 E8C7 CA DEX 1516 E8C8 10 EB BPL STRL 1517 E8CA 8D OB D2 STA POTGO ;START POTS FOR NEXT TIME 1518 ; 1519 E8CD A2 06 LDX #6 1520 E8CF A0 03 LDY #3 1521 EBD1 89 78 02 PTRLP: LDA STICKO,Y ;TRANSFER BITS FROM JOYSTICKS 1522 E8D4 4A LSR A ;TO PADDLE TRIGGERS 1523 E8D5 4A LSR A 1524 E8D6 4A LSR A 1525 EBD7 90 7D 02 STA PTRIG1,X 1526 E8DA A9 00 LDA #0 1527 E8DC 2A ROL A 1528 E8DD 9D 7C 02 STA PTRIGO,X 1529 E8E0 CA DEX 1530 E8E1 CA DEX 1531 E8E2 88 DEY 1532 E8E3 10 EC BPL PTRLP
Čitelnější kód nalezneme například ve známé Altiře:
; Zdroj:
; https://github.com/ilmenit/AltirraSDL/blob/main/src/Kernel/source/Shared/vbi.s
pot_loop:
lda pot0,x
sta paddl0,x
lda #0
sta ptrig0,x
dex
bpl pot_loop
ldx #3
trig_loop:
lda trig0,x
sta strig0,x
dex
bpl trig_loop
lda porta
ldx #0
ldy #0
jsr do_stick_ptrigs
lda portb
ldx #4
ldy #2
jsr do_stick_ptrigs
.endif
;restart pots (required for SysInfo)
sta potgo
Ovladače typu paddle byly poprvé vydány pro herní konzoli Atari 2600 (VCS) a byly využity v několika známých hrách. Mezi ně patří Breakout (tedy předchůdce Arkanoidu), Warlords, Canyon Bomber či Kaboom! Na osmibitových domácích mikropočítačích Atari (400, 800, řada XL, řada XE atd.) se sice používal naprosto stejný ovladač, ovšem podpora pro paddle ve hrách byla relativně slabší. Pravděpodobně nejznámější hrou jsou Warlords (stejný princip jako na Atari 2600 či na herním automatu) a paddle podporuje (vedle joysticku) například i Arkanoid či Planetary Defense.
Obrázek 11: Hra Warlords je ovládaná pomocí paddle.
Autor: tisnik, podle licence: Rights Managed
Obrázek 12: Úvodní obrazovka Arkanoidu nabízí ovládání pomocí paddle.
Autor: tisnik, podle licence: Rights Managed
Obrázek 13: První úroveň hry Arkanoid.
Autor: tisnik, podle licence: Rights Managed
Obrázek 14: Planetary Defense se dá ovládat i dvojicí paddle, což může být v tomto případě lepší, než s využitím joysticku (což je taktéž možné).
Autor: tisnik, podle licence: Rights Managed
Zajímavý je tablet (v původním smyslu tohoto slova) nazvaný Koala Pad, který se připojoval k analogovému vstupu, konkrétně byl připojen jako dvojice ovladačů typu paddle. Koala Pad byl podporován kreslicím programem Koala Painter, jehož uživatelské rozhraní vypadá následovně (je použit grafický režim 160×192 pixelů pro obrázek, uživatelské rozhraní je však založeno na textovém režimu s pěti barvami):
Obrázek 15: Menu kreslicího programu Koala Painter využívá textový režim s pěti barvami.
Autor: tisnik, podle licence: Rights Managed
Vraťme se nyní na chvíli k článkům o PMG, tedy o spritech, které se u osmibitových mikropočítačů Atari nazývají souslovím Player-Missile Graphics. V těchto článcích jsme si kromě dalších věcí ukázali, jak snadné je měnit horizontální pozici hráče zápisem osmibitové hodnoty do jednoho z řídicích registrů HPOSx integrovaného obvodu GTIA. Takto jsme například implementovali posun hráče s využitím joysticku:
; ---------------------------------------------------------------------
; subrutina pro obsluhu VBI
; ---------------------------------------------------------------------
.proc horizontal_movement
ldx x_pos ; původní pozice prvního hráče
lda STICK0 ; čtení joysticku
cmp #11 ; je nakloněn doleva?
bne not_left
dex ; posun hráče doleva
not_left:
cmp #7 ; je nakloněn doprava?
bne not_right
inx ; posun hráče doprava
not_right:
stx HPOSP0 ; změna pozice prvního hráče
stx x_pos ; zapamatovat si pozici prvního hráče
jmp XITVBV ; zpracovat zbytek odloženého VBLANKu
rts
.endproc
Tato subrutina je volána 50× nebo 60× za sekundu a navíc využívá paměťovou buňku s předchozí pozicí hráče:
; horizontální pozice hráče x_pos: .byte 80
Výsledek na obrazovce Atari může vypadat následovně:
Obrázek 16: Posun hráče s využitím joysticku.
Autor: tisnik, podle licence: Rights Managed
Následuje úplný zdrojový kód, který bude v rámci navazující kapitoly modifikován tak, aby bylo možné hráče posunovat nikoli joystickem, ale pomocí ovladače paddle:
.include "atari.inc"
.CODE
PLAYER_0_OFFSET = 512
; ---------------------------------------------------------------------
; vstupní bod do programu
; ---------------------------------------------------------------------
.proc main
lda #80 ; horizontální pozice prvního hráče
sta HPOSP0 ; uložit do řídicího registru HPOSP0 na čipu GTIA
lda #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 #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áč
dex ; snížit offset + nastavit příznaky
bne next_line ; další byte spritu
lda #46 ; povolení PMG DMA
sta SDMCTL
; nastavit vektor pro odloženou VBI
lda #>horizontal_movement
sta VVBLKD+1
lda #<horizontal_movement
sta VVBLKD
loop:
jmp loop ; program vlastně nice nedělá - jen cyklí!
.endproc
; ---------------------------------------------------------------------
; subrutina pro obsluhu VBI
; ---------------------------------------------------------------------
.proc horizontal_movement
ldx x_pos ; původní pozice prvního hráče
lda STICK0 ; čtení joysticku
cmp #11 ; je nakloněn doleva?
bne not_left
dex ; posun hráče doleva
not_left:
cmp #7 ; je nakloněn doprava?
bne not_right
inx ; posun hráče doprava
not_right:
stx HPOSP0 ; změna pozice prvního hráče
stx x_pos ; zapamatovat si pozici prvního hráče
jmp XITVBV ; zpracovat zbytek odloženého VBLANKu
rts
.endproc
; data
sprite: .byte 24, 60, 126, 219, 255, 36, 90, 165
; horizontální pozice hráče
x_pos: .byte 80
end:
.segment "EXEHDR"
.word $ffff ; uvodni sekvence bajtu v souboru XEX
.word main ; zacatek kodoveho segmentu
.word end - 1 ; konec kodoveho segmentu
.segment "AUTOSTRT" ; segment s pocatecni adresou
.word RUNAD ; naplni se pouze adresy RUNAD a RUNAD+1
.word RUNAD+1
.word main ; adresa vstupniho bodu do programu
; finito
Přímé ovládání hráče, resp. přesněji řečeno horizontální polohy hráče s využitím ovladače paddle, je realizováno v dnešním šestém a současně i posledním demonstračním příkladu. Změna pozice hráče je realizována ve VBI a je až triviálně jednoduchá, protože většinu práce za nás udělá operační systém:
; ---------------------------------------------------------------------
; subrutina pro obsluhu VBI
; ---------------------------------------------------------------------
.proc horizontal_movement
lda PADDL0 ; čtení hodnoty paddle
sta HPOSP0 ; změna pozice prvního hráče
jmp XITVBV ; zpracovat zbytek odloženého VBLANKu
rts
.endproc
Poznámka: to tedy znamená, že načtená hodnota 0 až 227 je přímo použita pro nastavení horizontální pozice spritu. Samozřejmě by bylo možné provádět další výpočty, aby se například začínalo na hodnotě 48 atd.
Výsledek:
Obrázek 17: Posun hráče s využitím paddle.
Autor: tisnik, podle licence: Rights Managed
Úplný zdrojový kód dnešního šestého demonstračního příkladu vypadá následovně:
.include "atari.inc"
.CODE
PLAYER_0_OFFSET = 512
; ---------------------------------------------------------------------
; vstupní bod do programu
; ---------------------------------------------------------------------
.proc main
lda #80 ; horizontální pozice prvního hráče
sta HPOSP0 ; uložit do řídicího registru HPOSP0 na čipu GTIA
lda #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 #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áč
dex ; snížit offset + nastavit příznaky
bne next_line ; další byte spritu
lda #46 ; povolení PMG DMA
sta SDMCTL
; nastavit vektor pro odloženou VBI
lda #>horizontal_movement
sta VVBLKD+1
lda #<horizontal_movement
sta VVBLKD
loop:
jmp loop ; program vlastně nice nedělá - jen cyklí!
.endproc
; ---------------------------------------------------------------------
; subrutina pro obsluhu VBI
; ---------------------------------------------------------------------
.proc horizontal_movement
lda PADDL0 ; čtení hodnoty paddle
sta HPOSP0 ; změna pozice prvního hráče
jmp XITVBV ; zpracovat zbytek odloženého VBLANKu
rts
.endproc
; data
sprite: .byte 24, 60, 126, 219, 255, 36, 90, 165
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
V navazujícím článku budeme pokračovat v popisu možností nabízených čipem POKEY. Nejdříve si ukážeme způsob čtení kódu stlačených kláves, s čímž nepřímo souvisí i problematika hardwarových přerušení (IRQ), které POKEY taktéž dokáže ovládat (maskovat atd.). A poté si řekneme, jakým způsobem byl integrovaný čip POKEY využit pro řízení sériového portu. Ten byl velmi důležitý, protože sloužil k připojování dalších periferií k osmibitovým mikropočítačům Atari. Ostatně sériový port Atari nazývaný SIO se stal předchůdcem USB, tedy sériové sběrnice používané dodnes.
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 antic_4.xex \
antic_5.xex antic_6.xex \
antic_7.xex antic_8.xex \
antic_9.xex antic_A.xex \
antic_B.xex \
antic_bitmap_1.xex antic_bitmap_2.xex \
antic_bitmap_3.xex antic_bitmap_4.xex \
antic_bitmap_5.xex antic_bitmap_6.xex \
antic_bitmap_7.xex antic_bitmap_8.xex \
antic_dli_1.asm antic_dli_2.asm \
antic_dli_3.asm antic_dli_4.asm \
antic_dli_5.asm antic_dli_pmg.asm \
sound_1.xex sound_2.xex \
sound_3.xex sound_4.xex \
sound_5.xex sound_6.xex \
sound_7.xex sound_8.xex \
sound_9.xex sound_A.xex \
sound_B.xex sound_C.xex \
sound_D.xex sound_E.xex \
sound_F.xex \
rnd_1.xex rnd_2.xex \
rnd_3.xex rnd_4.xex \
paddle_1.xex paddle_2.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
antic_bitmap_6.xex: antic_bitmap_6.o
ld65 -C linker_image.cfg $< -o $@ -m $(basename $<).map
antic_bitmap_7.xex: antic_bitmap_7.o
ld65 -C linker_image_2.cfg $< -o $@ -m $(basename $<).map
antic: \
antic_1.xex \
antic_2.xex \
antic_3.xex \
antic_4.xex \
antic_5.xex \
antic_6.xex \
antic_7.xex \
antic_8.xex \
antic_9.xex \
antic_A.xex \
antic_B.xex
antic_bitmap: \
antic_bitmap_1.xex \
antic_bitmap_2.xex \
antic_bitmap_3.xex \
antic_bitmap_4.xex \
antic_bitmap_5.xex \
antic_bitmap_6.xex \
antic_bitmap_7.xex \
antic_bitmap_8.xex
antic_dli: \
antic_dli_1.xex \
antic_dli_2.xex \
antic_dli_3.xex \
antic_dli_4.xex \
antic_dli_5.xex \
antic_dli_pmg.xex
antic_vbi: \
antic_vbi_1.xex \
antic_vbi_2.xex \
antic_vbi_3.xex \
antic_vbi_dli_1.xex \
antic_vbi_dli_2.xex \
antic_vbi_dli_3.xex \
antic_vbi_dli_4.xex
antic_scrolling: \
antic_scrolling_1.xex \
antic_scrolling_2.xex \
antic_scrolling_3.xex \
antic_scrolling_4.xex
gtia: \
gtia_mode_1.xex \
gtia_mode_2.xex \
gtia_mode_3.xex \
gtia_mode_4.xex \
gtia_mode_5.xex \
gtia_mode_6.xex \
gtia_mode_7.xex \
gtia_mode_8.xex \
gtia_mode_9.xex \
gtia_mode_A.xex \
gtia_mode_B.xex
sound: \
sound_1.xex \
sound_2.xex \
sound_3.xex \
sound_4.xex \
sound_5.xex \
sound_6.xex \
sound_7.xex \
sound_8.xex \
sound_9.xex \
sound_A.xex \
sound_B.xex \
sound_C.xex \
sound_D.xex \
sound_E.xex \
sound_F.xex
rnd: \
rnd_1.xex \
rnd_2.xex \
rnd_3.xex \
rnd_4.xex
paddle: \
paddle_1.xex \
paddle_2.xex
Výsledkem překladu jsou soubory s koncovkou .xex, které je možné přímo spustit v emulátoru osmibitových počítačů Atari.
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:
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | Klávesnice osmibitových počítačů Atari: až překvapivě komplikovaná problematika | 0 | 5 | 06-07-2026 |
| 2 | Postřehy z bezpečnosti: AI modely a funkce, kam se oko podívá | 0 | 7 | 05-07-2026 |
| 3 | Obnova po resetu GPU v GNOME, nahrávání 4k/60p videa přes USB | 0 | 7 | 04-07-2026 |
| 4 | В Швейцарии создали Фурье-пиксель: он одновременно видит и показывает | 5 | 7 | 06-07-2026 |
| 5 | Пользователи "Тройки" смогут разместить на карте свою фотографию | 0 | 0 | 04-12-2018 |
| 6 | Названы скрытые функции кнопок смартфона | 0 | 5 | 06-07-2026 |
| 7 | Студенты в российских вузах смогут получать цифровую профессию одновременно с основной | 0 | 0 | 10-07-2019 |
| 8 | Инновационные технологии | 5 | 7 | 29-06-2026 |
| 9 | Інсайдер: Apple працює над iRing – своїм першим розумним кільцем | 0 | 5 | 26-06-2026 |