Na úvodní článek o CIO (Central Input/Output), jenž tvoří nedílnou a možná i nejdůležitější součást operačního systému osmibitových domácích mikropočítačů Atari, dnes navážeme. Nejdříve si ukážeme, jak se volají operace OPEN a CLOSE z assembleru (prozatím jsme si je ukazovali v Atari BASICu), dále se budeme zabývat zpočátku možná poněkud záhadným příkazem XIO (lze jím realizovat všechny speciální operace, které zařízení podporuje) a ve třetí části dnešního článku si, prozatím alespoň ve stručnosti, popíšeme tabulku nazvanou HATABS (Handler Address Table).
Co se dozvíte v článku
- Otevření kanálu pro zápis, zápis jednoho bajtu a uzavření kanálu
- Realizace operace uzavření kanálu v assembleru
- Realizace operace otevření kanálu v assembleru
- Realizace operace pro zápis jednoho znaku do zvoleného kanálu
- Úplný zdrojový kód dnešního prvního demonstračního příkladu
- Zápis více řádků do souboru přes CIO
- Realizace čtení bloku ze zvoleného kanálu v assembleru
- Demonstrační příklady: přečtení dat ze souboru přes CIO (jeden řádek, celý soubor)
- Kontrola chyb po provedení CIO operace
- Demonstrační příklad: zápis na zařízení E: s následnou kontrolou chyb
- Jak dopadne pokus o zápis do uzavřeného kanálu?
- Operace XIO
- Syntaxe a sémantika příkazu XIO
- Vykreslovací příkazy volané přes XIO
- Tabulka zařízení: HATABS (Handler Address Table)
- Realizace výpisu obsahu tabulky HATABS v Atari BASICu
- Příloha: Makefile pro překlad všech demonstračních příkladů
- Repositář s demonstračními příklady
- Odkazy na Internetu
Je to velmi jednoduchá, ovšem o to užitečnější tabulka, díky které je možné do operačního systému zaregistrovat nová zařízení se zvoleným jménem i s libovolnými operacemi. Jakmile je tabulka naplněna (resp. doplněna) o nové zařízení a do paměti jsou nahrány jeho ovladače (ony handlery), může prakticky jakýkoli program začít toto zařízení používat.
Právě díky konceptu kanálů, k nim přiřazených IOCB (Input-Output Control Block) a HATABS je operační systém osmibitových Atari rozšiřitelný a vlastně i poměrně modulární.
Otevření kanálu pro zápis, zápis jednoho bajtu a uzavření kanálu
Připomeňme si, jakým způsobem jsme se zařízeními a kanály pracovali v Atari BASICu. V následujícím programu je nejdříve pro jistotu uzavřen kanál #4 (pokud by byl předtím nechán otevřený, což se může stát – stisk klávesy BREAK atd.). Následně je tento kanál (znovu) otevřen, a to v režimu zápisu (konstanta 8 v příkazu OPEN). Jméno zařízení je nastaveno na H:test.txt, což znamená zařízení H: (zápis na souborový systém v emulátoru) se jménem souboru. Další operace je jednoduchá – provádíme zde zápis jediného bajtu s kódem 42 a následně je čtvrtý kanál (znovu) uzavřen:
10 REM Zapis nekolika hodnot 11 REM na disk namapovany emulatorem. 20 REM 21 REM Pro jistotu zavreme kanal 22 REM pred jeho pouzitim 22 CLOSE #4 30 REM Otevreme kanal pro zapis 31 OPEN #4, 8, 0, "H:test.txt" 40 REM Provedeni zapisu jednoho znaku 41 PUT #4, 42 50 REM Zavreme kanal 51 CLOSE #4
Tento program si postupně přepíšeme do assembleru, což vlastně znamená, že musíme implementovat či alespoň napodobit příkazy OPEN, CLOSE a PUT. Na začátku použiji pouze kostru programu, která sice bude bez problémů přeložitelná, ale nebude provádět žádné vstupně-výstupní operace, protože příslušné podprogramy (subrutiny) obsahují pouze instrukci pro návrat z podprogramu (rts):
.include "atari.inc"
.CODE
; ---------------------------------------------------------------------
; hlavní program
; ---------------------------------------------------------------------
.proc main
jsr CLOSE_CHANNEL_4
jsr OPEN_CHANNEL_4_AS_H
jsr WRITE_BYTE_CHANNEL_4
jsr CLOSE_CHANNEL_4
loop:
jmp loop ; program vlastně nice nedělá - jen cyklí!
.endproc
; ---------------------------------------------------------------------
; uzavření kanálu číslo 4
; ---------------------------------------------------------------------
.proc CLOSE_CHANNEL_4
rts ; návrat ze subrutiny
.endproc
; ---------------------------------------------------------------------
; otevření kanálu číslo 4 v režimu zápisu na zařízení H:test.txt
; ---------------------------------------------------------------------
.proc OPEN_CHANNEL_4_AS_H
rts ; návrat ze subrutiny
.endproc
; ---------------------------------------------------------------------
; zápis jednoho znaku do kanálu číslo 4
; ---------------------------------------------------------------------
.proc WRITE_BYTE_CHANNEL_4
rts ; návrat ze subrutiny
.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
Realizace operace uzavření kanálu v assembleru
Nejjednodušší je realizace subrutiny CLOSE_CHANNEL_4. V této subrutině budeme přes CIO volat příkaz CLOSE, který nevyžaduje žádné další parametry. Nejdříve ovšem nadefinujeme offset pro kanál číslo #4, který budeme používat:
IOCB4 = $40 ; offset odvozený od čísla IOCB kanálu (nutno násobit šestnácti)
Samotná realizace subrutiny CLOSE_CHANNEL_4 je dosti přímočará. Adresování je realizováno přes index registr X, což je dobře, protože v systémové subrutině CIO je hodnota tohoto registru použita pro volbu kanálu, kterého se příkaz týká:
; ---------------------------------------------------------------------
; uzavření kanálu číslo 4
; ---------------------------------------------------------------------
.proc CLOSE_CHANNEL_4
ldx #IOCB4 ; offset odvozený od čísla IOCB kanálu
lda #CLOSE ; prováděná operace
sta ICCOM, x ; zápis prováděné operace do bloku IOCB
jsr CIOV ; zavolání rutiny pro CIO
rts ; návrat ze subrutiny
.endproc
Realizace operace otevření kanálu v assembleru
Operace pro otevření kanálu je nepatrně komplikovanější, protože vyžaduje zadání několika parametrů (zapisovaných pochopitelně do IOCB). Je nutné specifikovat jméno zařízení a popř. i cestu k souboru. Jedná se o řetězec ukončený nulou, který v assembleru nadefinujeme následujícím způsobem:
; jméno zařízení (+ jméno souboru) ukončené nulou device_name: .byte "H:TEST.TXT", 0
Adresa tohoto řetězce se zapíše do ICBAH+ICBAL:
; specifikace jména zařízení + jména souboru (16bitový ukazatel) lda #<device_name sta ICBAL, x lda #>device_name sta ICBAH, x
Požadovaný režim otevření (čtení, zápis, čtení+zápis, připojení) se zapisuje do ICAX1. V hlavičkovém souboru atari.inc je definována vhodná konstanta OPNOT (zápis):
lda #OPNOT ; režim otevření: zápis (odpovídá druhému parametru příkazu OPEN v BASICu) sta ICAX1, x
Celá subrutina pro otevření kanálu tedy může vypadat následovně:
; ---------------------------------------------------------------------
; otevření kanálu číslo 4 v režimu zápisu na zařízení H:test.txt
; ---------------------------------------------------------------------
.proc OPEN_CHANNEL_4_AS_H
ldx #IOCB4 ; offset odvozený od čísla IOCB kanálu
lda #OPEN ; prováděná operace
sta ICCOM, x ; zápis prováděné operace do bloku IOCB
; specifikace jména zařízení + jména souboru (16bitový ukazatel)
lda #<device_name
sta ICBAL, x
lda #>device_name
sta ICBAH, x
lda #OPNOT ; režim otevření: zápis (odpovídá druhému parametru příkazu OPEN v BASICu)
sta ICAX1, x
lda #0 ; odpovídá třetímu parametru příkazu OPEN v BASICu
sta ICAX2, x
jsr CIOV ; zavolání rutiny pro CIO
rts ; návrat ze subrutiny
.endproc
Realizace operace pro zápis jednoho znaku do zvoleného kanálu
Zbývá nám realizace poslední operace WRITE_BYTE_CHANNEL_4. Zde se nejedná o žádnou novinku, protože zápis na zařízení jsme si již popsali v předchozím článku. V tomto případě musíme nastavit adresu zapisovaného bufferu (ICBAH+ICBAL) a do ICBLH+ICBLL uložíme hodnotu 1, protože do zařízení pošleme jediný znak:
; ---------------------------------------------------------------------
; zápis jednoho znaku do kanálu číslo 4
; ---------------------------------------------------------------------
.proc WRITE_BYTE_CHANNEL_4
ldx #IOCB4 ; offset odvozený od čísla IOCB kanálu
lda #PUTCHR ; prováděná operace
sta ICCOM, x ; zápis prováděné operace do bloku IOCB
; adresa zapisovaného bloku
lda #<char_to_put
sta ICBAL, x
lda #>char_to_put
sta ICBAH, x
; nastavení počtu zapisovaných bajtů
lda #1
sta ICBLL, x
lda #0
sta ICBLH, x
jsr CIOV ; zavolání rutiny pro CIO
rts ; návrat ze subrutiny
.endproc
Úplný zdrojový kód dnešního prvního demonstračního příkladu
Pro úplnost si ukažme úplný zdrojový kód dnešního prvního demonstračního příkladu, který po svém překladu a spuštění vytvoří na zařízení se jménem H: nový soubor nazvaný TEST.TXT a zapíše do něj jeden bajt. Samotný zdrojový kód je sice relativně dlouhý, ale program má po překladu velikost jen 112 bajtů, tedy necelou polovinu jedné stránky paměti (a mohl být ještě kratší):
.include "atari.inc"
.CODE
IOCB4 = $40 ; offset odvozený od čísla IOCB kanálu (nutno násobit šestnácti)
; ---------------------------------------------------------------------
; hlavní program
; ---------------------------------------------------------------------
.proc main
jsr CLOSE_CHANNEL_4
jsr OPEN_CHANNEL_4_AS_H
jsr WRITE_BYTE_CHANNEL_4
jsr CLOSE_CHANNEL_4
loop:
jmp loop ; program vlastně nice nedělá - jen cyklí!
.endproc
; ---------------------------------------------------------------------
; uzavření kanálu číslo 4
; ---------------------------------------------------------------------
.proc CLOSE_CHANNEL_4
ldx #IOCB4 ; offset odvozený od čísla IOCB kanálu
lda #CLOSE ; prováděná operace
sta ICCOM, x ; zápis prováděné operace do bloku IOCB
jsr CIOV ; zavolání rutiny pro CIO
rts ; návrat ze subrutiny
.endproc
; ---------------------------------------------------------------------
; otevření kanálu číslo 4 v režimu zápisu na zařízení H:test.txt
; ---------------------------------------------------------------------
.proc OPEN_CHANNEL_4_AS_H
ldx #IOCB4 ; offset odvozený od čísla IOCB kanálu
lda #OPEN ; prováděná operace
sta ICCOM, x ; zápis prováděné operace do bloku IOCB
; specifikace jména zařízení + jména souboru (16bitový ukazatel)
lda #<device_name
sta ICBAL, x
lda #>device_name
sta ICBAH, x
lda #OPNOT ; režim otevření: zápis (odpovídá druhému parametru příkazu OPEN v BASICu)
sta ICAX1, x
lda #0 ; odpovídá třetímu parametru příkazu OPEN v BASICu
sta ICAX2, x
jsr CIOV ; zavolání rutiny pro CIO
rts ; návrat ze subrutiny
.endproc
; ---------------------------------------------------------------------
; zápis jednoho znaku do kanálu číslo 4
; ---------------------------------------------------------------------
.proc WRITE_BYTE_CHANNEL_4
ldx #IOCB4 ; offset odvozený od čísla IOCB kanálu
lda #PUTCHR ; prováděná operace
sta ICCOM, x ; zápis prováděné operace do bloku IOCB
; adresa zapisovaného bloku
lda #<char_to_put
sta ICBAL, x
lda #>char_to_put
sta ICBAH, x
; nastavení počtu zapisovaných bajtů
lda #1
sta ICBLL, x
lda #0
sta ICBLH, x
jsr CIOV ; zavolání rutiny pro CIO
rts ; návrat ze subrutiny
.endproc
; jméno zařízení (+ jméno souboru) ukončené nulou
device_name: .byte "H:TEST.TXT", 0
; zapisovaný bajt
char_to_put: .byte $41
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
Zápis více řádků do souboru přes CIO
Připomeňme si, jakým způsobem jsme zapsali data (zprávu) do textového souboru v Atari BASICu. Soubor byl vytvořen na zařízení H:, které může být v emulátoru namapováno na souborový systém (většinou je nutné explicitně povolit přístup read/write a nikoli read-only):
10 REM Zapis textovych dat 11 REM na disk namapovany emulatorem. 20 REM 21 REM Pro jistotu zavreme kanal 22 REM pred jeho pouzitim 22 CLOSE #4 30 REM Otevreme kanal pro zapis 31 OPEN #4, 8, 0, "H:hello.txt" 40 REM Provedeni zapisu 41 PRINT #4; "Hello Atari!" 50 REM Zavreme kanal 51 CLOSE #4
Obsah výsledného souboru bude obsahovat jak vlastní zprávu „Hello Atari!“ (dvanáct bajtů), tak i znak s kódem $9b, kterým je v ATASCII zakódován konec řádku:
$ xxd -g1 hello.txt 00000000: 48 65 6c 6c 6f 20 41 74 61 72 69 21 9b Hello Atari!.
Pokusme se ještě o zápis více řádků, aby bylo zřejmé, jak se přesně používají znaky s kódem $9b:
10 REM Zapis textovych dat 11 REM na disk namapovany emulatorem. 20 REM 21 REM Pro jistotu zavreme kanal 22 REM pred jeho pouzitim 22 CLOSE #4 30 REM Otevreme kanal pro zapis 31 OPEN #4, 8, 0, "H:hello.txt" 40 REM Provedeni zapisu 41 PRINT #4; "Hello Atari!" 42 PRINT #4; "this is second line" 43 PRINT #4; "this is third line" 50 REM Zavreme kanal 51 CLOSE #4
Analýza obsahu výsledného souboru:
$ xxd -g1 hello.txt 00000000: 48 65 6c 6c 6f 20 41 74 61 72 69 21 9b 74 68 69 Hello Atari!.thi 00000010: 73 20 69 73 20 73 65 63 6f 6e 64 20 6c 69 6e 65 s is second line 00000020: 9b 74 68 69 73 20 69 73 20 74 68 69 72 64 20 6c .this is third l 00000030: 69 6e 65 9b ine.
Realizace čtení bloku ze zvoleného kanálu v assembleru
Pokusme se nejdříve realizovat přečtení jednoho řádku z textového souboru. Pro tento účel bude alokován buffer o délce třinácti bajtů, což plně dostačuje pro načtení řetězce „Hello, Atari!“ i znaku pro konec řádku:
; buffer buffer: .res 13 end_of_buffer:
Soubor na zařízení H: běžným způsobem otevřeme subrutinou OPEN_CHANNEL_4_AS_H. Pro čtení dat, resp. přesněji řečeno bufferu o délce třinácti bajtů, bude využita následující subrutina, která před provedením CIO operace nastaví v IOCB jak adresu bufferu (ICBAH+ICBAL), tak i jeho délku (ICBLH+ICBLL):
; ---------------------------------------------------------------------
; čtení zprávy z kanálu číslo 4
; ---------------------------------------------------------------------
.proc READ_MESSAGE_FROM_CHANNEL_4
ldx #IOCB4 ; offset odvozený od čísla IOCB kanálu
lda #GETCHR ; prováděná operace
sta ICCOM, x ; zápis prováděné operace do bloku IOCB
; adresa bloku
lda #<buffer
sta ICBAL, x
lda #>buffer
sta ICBAH, x
; nastavení počtu čtených bajtů
lda #(end_of_buffer-buffer)
sta ICBLL, x
lda #0
sta ICBLH, x
jsr CIOV ; zavolání rutiny pro CIO
rts ; návrat ze subrutiny
.endproc
Malou úpravou pak dosáhneme toho, že se jedinou operací přečte celý soubor (všechny tři textové řádky). Postačuje pouze zvětšit velikost bufferu:
; buffer buffer: .res 52 end_of_buffer:
Demonstrační příklady: přečtení dat ze souboru přes CIO (jeden řádek, celý soubor)
Výše uvedenou subrutinu READ_MESSAGE_FROM_CHANNEL_4 použijeme ve dvou demonstračních příkladech. V příkladu prvním se přečte (a na obrazovku vypíše) prvních třináct bajtů načtených ze souboru. Výsledek může vypadat následovně (zajímavé: kurzor se korektně posunul na další řádek):
Obrázek 1: Načtený řetězec se korektně zobrazil.
V příkladu druhém se buffer rozšiřuje na 52 bajtů a to znamená, že dokážeme načíst celý obsah souboru. Výsledek bude podle očekávání odlišný:
Obrázek 2: Načtení celého souboru se třemi řádky s jejich následným zobrazením.
Úplný zdrojový kód prvního příkladu vypadá následovně:
.include "atari.inc"
.CODE
IOCB0 = $00 ; offset odvozený od čísla IOCB kanálu (nutno násobit šestnácti)
IOCB4 = $40 ; offset odvozený od čísla IOCB kanálu (nutno násobit šestnácti)
; ---------------------------------------------------------------------
; hlavní program
; ---------------------------------------------------------------------
.proc main
jsr CLOSE_CHANNEL_4
jsr OPEN_CHANNEL_4_AS_H
jsr READ_MESSAGE_FROM_CHANNEL_4
jsr WRITE_MESSAGE_INTO_CHANNEL_0
jsr CLOSE_CHANNEL_4
loop:
jmp loop ; program vlastně nice nedělá - jen cyklí!
.endproc
; ---------------------------------------------------------------------
; uzavření kanálu číslo 4
; ---------------------------------------------------------------------
.proc CLOSE_CHANNEL_4
ldx #IOCB4 ; offset odvozený od čísla IOCB kanálu
lda #CLOSE ; prováděná operace
sta ICCOM, x ; zápis prováděné operace do bloku IOCB
jsr CIOV ; zavolání rutiny pro CIO
rts ; návrat ze subrutiny
.endproc
; ---------------------------------------------------------------------
; otevření kanálu číslo 4 v režimu zápisu na zařízení H:test.txt
; ---------------------------------------------------------------------
.proc OPEN_CHANNEL_4_AS_H
ldx #IOCB4 ; offset odvozený od čísla IOCB kanálu
lda #OPEN ; prováděná operace
sta ICCOM, x ; zápis prováděné operace do bloku IOCB
; specifikace jména zařízení + jména souboru (16bitový ukazatel)
lda #<device_name
sta ICBAL, x
lda #>device_name
sta ICBAH, x
lda #OPNIN ; režim otevření: čtení (odpovídá druhému parametru příkazu OPEN v BASICu)
sta ICAX1, x
lda #0 ; odpovídá třetímu parametru příkazu OPEN v BASICu
sta ICAX2, x
jsr CIOV ; zavolání rutiny pro CIO
rts ; návrat ze subrutiny
.endproc
; ---------------------------------------------------------------------
; čtení zprávy z kanálu číslo 4
; ---------------------------------------------------------------------
.proc READ_MESSAGE_FROM_CHANNEL_4
ldx #IOCB4 ; offset odvozený od čísla IOCB kanálu
lda #GETCHR ; prováděná operace
sta ICCOM, x ; zápis prováděné operace do bloku IOCB
; adresa bloku
lda #<buffer
sta ICBAL, x
lda #>buffer
sta ICBAH, x
; nastavení počtu čtených bajtů
lda #(end_of_buffer-buffer)
sta ICBLL, x
lda #0
sta ICBLH, x
jsr CIOV ; zavolání rutiny pro CIO
rts ; návrat ze subrutiny
.endproc
; ---------------------------------------------------------------------
; zápis zprávy na obrazovku
; ---------------------------------------------------------------------
.proc WRITE_MESSAGE_INTO_CHANNEL_0
ldx #IOCB0 ; offset odvozený od čísla IOCB kanálu
lda #PUTCHR ; prováděná operace
sta ICCOM, x ; zápis prováděné operace do bloku IOCB
; adresa bloku
lda #<buffer
sta ICBAL, x
lda #>buffer
sta ICBAH, x
; nastavení počtu čtených bajtů
lda #(end_of_buffer-buffer)
sta ICBLL, x
lda #0
sta ICBLH, x
jsr CIOV ; zavolání rutiny pro CIO
rts ; návrat ze subrutiny
.endproc
; jméno zařízení (+ jméno souboru) ukončené nulou
device_name: .byte "H:HELLO.TXT", 0
; buffer
buffer: .res 13
end_of_buffer:
end:
.segment "EXEHDR"
.word $ffff ; uvodni sekvence bajtu v souboru XEX
.word main ; zacatek kodoveho segmentu
.word end - 1 ; konec kodoveho segmentu
.segment "AUTOSTRT" ; segment s pocatecni adresou
.word RUNAD ; naplni se pouze adresy RUNAD a RUNAD+1
.word RUNAD+1
.word main ; adresa vstupniho bodu do programu
; finito
Druhý příklad se odlišuje pouze odlišnou velikostí bufferu:
; buffer buffer: .res 52 end_of_buffer:
Kontrola chyb po provedení CIO operace
U většiny I/O operací může dojít k nějaké chybě. Buď není zařízení připraveno, nebo nepodporuje vyžadovanou operaci (čtení z tiskárny, zápis na klávesnici) nebo dojde ke skutečné chybě (čtení z kazety či diskety). Informace o provedení či naopak neprovedení I/O operace se zapisuje do bajtu ICSTA v IOCB. Postup je tedy následující:
- IOCB se vyplní parametry I/O operace, která se má provést
- Zavolá se rutina CIOV
- Zkontroluje se bajt ICSTA v IOCB
Chyba je indikována bitem číslo 7 (nejvyšší bit). To je výhodné, protože stav tohoto bitu se při načtení do akumulátoru A automaticky propíše do příznakového bitu NEGATIVE a je tedy možné použít podmíněné skoky BPL a BMI, kde PL znamená plus a MI pochopitelně minus.
Demonstrační příklad: zápis na zařízení E: s následnou kontrolou chyb
V dalším demonstračním příkladu je realizován zápis na zařízení E:. Po zápisu je provedena kontrola bajtu ICSTA v IOCB na přítomnost chyby. Pokud chyba nastala, změní se pozadí obrazovky na tmavě červenou. V případě, že k chybě nedošlo, bude pozadí zelené:
; zavolání rutiny pro CIO
jsr CIOV
lda ICSTA, x ; status poslední operace
bpl ok ; test bitu 7
lda #18 ; kod barvy
sta COLOR2 ; ulozit do registru COLOR2
jmp loop
ok:
lda #$c3 ; kod barvy
sta COLOR2 ; ulozit do registru COLOR2
Zápis na E: je většinou bezproblémový, takže by obrazovka měla vypadat takto:
Obrázek 3: Po bezchybném načtení řetězce ze souboru obrazovka zezelená.
Následuje výpis celého kódu tohoto demonstračního příkladu:
.include "atari.inc"
.CODE
.proc main
ldx #0 ; offset odvozený od čísla IOCB kanálu (nutno násobit šestnácti)
lda #PUTREC ; prováděná operace
sta ICCOM, x
; adresa zapisovaného bloku
lda #<message
sta ICBAL, x
lda #>message
sta ICBAH, x
; nastavení počtu zapisovaných bajtů na 256!!!
lda #0
sta ICBLL, x
lda #1
sta ICBLH, x
; zavolání rutiny pro CIO
jsr CIOV
lda ICSTA, x ; status poslední operace
bpl ok ; test bitu 7
lda #18 ; kod barvy
sta COLOR2 ; ulozit do registru COLOR2
jmp loop
ok:
lda #$c3 ; kod barvy
sta COLOR2 ; ulozit do registru COLOR2
loop:
jmp loop ; program vlastně nice nedělá - jen cyklí!
.endproc
message: .byte "Hello, world!", $9b
end_of_message:
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
Jak dopadne pokus o zápis do uzavřeného kanálu?
Pokusme se nyní nasimulovat nějakou I/O chybu. Pravděpodobně nejjednodušší je pokusit se o zápis do uzavřeného kanálu s následným testem, zda zápis proběhl v pořádku. V takovém případě by program měl chybu zjistit a zobrazit tmavě červenou obrazovku smrti (DRSOD):
Obrázek 4: V případě jakékoli I/O chyby obrazovka zčervená.
Zdrojový kód příkladu je upraven jen minimálně – změnilo se číslo kanálu, to je vše:
.include "atari.inc"
.CODE
.proc main
ldx #nějaký_uzavřený_kanál ; offset odvozený od čísla IOCB kanálu (nutno násobit šestnácti)
lda #PUTREC ; prováděná operace
sta ICCOM, x
; adresa zapisovaného bloku
lda #<message
sta ICBAL, x
lda #>message
sta ICBAH, x
; nastavení počtu zapisovaných bajtů na 256!!!
lda #0
sta ICBLL, x
lda #1
sta ICBLH, x
; zavolání rutiny pro CIO
jsr CIOV
lda ICSTA, x ; status poslední operace
bpl ok ; test bitu 7
lda #18 ; kod barvy
sta COLOR2 ; ulozit do registru COLOR2
jmp loop
ok:
lda #$c3 ; kod barvy
sta COLOR2 ; ulozit do registru COLOR2
loop:
jmp loop ; program vlastně nice nedělá - jen cyklí!
.endproc
message: .byte "Hello, world!", $9b
end_of_message:
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
Operace XIO
Připomeňme si, že mezi základní operace, které mohou zařízení podporovat, patří především:
| Operace |
|---|
| OPEN |
| CLOSE |
| GET |
| PUT |
| STATUS |
V případě assembleru a IOCB je každá operace reprezentována svým kódem, což jsme si již řekli minule:
| Kód | Operace | Stručný popis operace |
|---|---|---|
| $03 | Open | otevření zařízení ve zvoleném režimu (viz dále) a přiřazení ke kanálu |
| $0C | Close | uzavření příslušného kanálu |
| (volá se odlišně) | Status | získání stavu zařízení (lze zavolat i pro zavřený kanál) |
| $07 | Get Character | přečtení znaku (bajtu) |
| $09 | Put Character | zápis znaku (bajtu) |
| $05 | Read Record | čtení řetězce, používá se ukončovací znak s kódem $9B (vysvětlím níže) |
| $09 | Write Record | tisk řetězce, používá se ukončovací znak s kódem $9B |
| >$0D | Special | různé speciální příkazy, pochopitelně se liší podle zařízení |
Ovšem mnoho zařízení má různé speciální požadavky, které nespadají do výše uvedené množiny. Představme si například sofistikovanější implementaci sériového portu, u něhož budeme chtít nastavit přenosovou rychlost, počet start bitů, počet stop bitů, povolení či zákaz paritního bitu atd. Nebo zařízení typu „obrazovka“, u něhož kromě čtení a zápisů (pixelů) budeme chtít implementovat i sofistikovanější kreslicí operace. V assembleru jsou takové operace dostupné snadno – postačuje vyplnit bajt ICCOM v bloku IOCB požadovaným kódem (větším než $0D) a naplnit další požadované parametry operace. Ovšem v Atari BASICu je tomu jinak – zde se ke „speciálním“ operacím, která zařízení podporují, přistupuje příkazem XIO.
Syntaxe a sémantika příkazu XIO
Příkaz XIO je nejsložitějším příkazem Atari BASICu, minimálně z pohledu počtu parametrů a jejich zápisu. Jeho syntaxe je následující:
XIO kód_příkazu, #kanál, aux1, aux2, "zařízení:jméno souboru" XIO kód_příkazu, #kanál, aux1, aux2, řetězec XIO kód_příkazu, #kanál, aux1, aux2, proměnná
Jaké kódy příkazu se ovšem používají? U většiny zařízení lze použít všechny standardní kódy, tedy například 3 odpovídá OPEN, 12 odpovídá CLOSE, 7 je GET, 9 odpovídá PUT atd. Prakticky všechny I/O příkazy je tedy možné nahradit za volání XIO. Ostatně si to můžeme ukázat. Nahradíme tento program (ten již známe):
10 REM Zapis textovych dat 11 REM na disk namapovany emulatorem. 20 REM 21 REM Pro jistotu zavreme kanal 22 REM pred jeho pouzitim 22 CLOSE #4 30 REM Otevreme kanal pro zapis 31 OPEN #4, 8, 0, "H:test.txt" 40 REM Provedeni zapisu 41 PRINT #4; "Hello Atari!" 50 REM Zavreme kanal 51 CLOSE #4
Náhrada, která využívá XIO, bude přímo pracovat s čísly příkazů zařízení:
10 REM Zapis textovych dat 11 REM na disk namapovany emulatorem. 20 REM 21 REM Pro jistotu zavreme kanal 22 REM pred jeho pouzitim 22 XIO 12, #4, 0, 0, "" 30 REM Otevreme kanal pro zapis 31 XIO 3, #4, 8, 0, "H:test.txt" 40 REM Provedeni zapisu jednoho znaku 41 XIO 9, #4, 8, 0, "Hello, Atari!" 50 REM Zavreme kanal 51 XIO 12, #4, 0, 0, ""
Vykreslovací příkazy volané přes XIO
Jen na okraj si v této kapitole ukážeme jedno ze zajímavých použití CIO a konkrétně příkazu XIO. Připomeňme si, že v Atari BASICu (ale i například v Turbo BASICu XL) se pracuje se dvěma zařízeními. Zařízení E: reprezentuje klávesnici a obrazovku editoru BASICu, tj. (stručně řečeno) jeho část používající grafický režim 0 (GR.0). Po přepnutí do jiného grafického režimu je stále E: dostupné, neboť jsou většinou zobrazeny čtyři textové řádky (což pochopitelně neplatí pro režimy GTIA). Zbylá část obrazovky – tj. buď rastrová grafika nebo vícebarevné textové režimy, se ovládá přes zařízení S: (screen), které je dostupné přes kanál #6. To tedy například znamená, že je možné, i když dosti krkolomným způsobem, vykreslovat jednotlivé pixely přes PRINT #6 nebo příkazem PUT #6. Příkaz PUT #6 má v tomto kontextu logickou sémantiku: každý zápis vede k vybarvení jednoho pixelu a posunutí (neviditelného) kurzoru doprava.
To si můžeme snadno otestovat v grafickém režimu 40×24 pixelů (nebo resp. 40×20 pixelů) se čtyřmi barvami. Příkazem POSITION přesuneme (neviditelný) kurzor na pozici 10, 10 a posléze vybarvíme tři po sobě jdoucí pixely:
10 REM Kresleni pixelu pomoci prikazu PUT 11 REM 20 REM Nastaveni grafickeho rezimu 40x20x4 21 GRAPHICS 3 30 REM Umisteni na obrazovce 31 POSITION 10, 10 40 REM Kresleni pres prikaz PUT 41 PUT #6, 1 42 PUT #6, 2 43 PUT #6, 3 50 REM Finito
Obrázek 5: Vykreslení tří pixelů příkazem PUT.
Mnohem zajímavější je kreslení úsečky. Požírači koláčů pochopitelně mohou použít příkaz DRAWTO (Atari BASIC je v tomto ohledu dále, než například MS BASIC na C64), ale proč stejnou operaci nerealizovat přes CIO? Zařízení S: totiž podporuje speciální příkazy dostupné přes XIO. Příkaz s kódem 17 dokáže vykreslit úsečku. K tomu je nutné si zapamatovat dvě souřadnice – počáteční a koncovou. Jak se to provádí ukazuje následující příklad (ano, je to velmi krkolomný způsob, ovšem umožní nám navázat dalším příkladem):
10 REM Kresleni usecky pomoci prikazu XIO 11 REM 20 REM Nastaveni grafickeho rezimu 40x20x4 21 GRAPHICS 3 30 REM Umisteni na obrazovce + kresleni prvniho bodu 31 POSITION 0, 0 32 PUT #6, 1 40 REM Vykresleni usecky 42 POSITION 10, 10 43 XIO 17, #6, 0, 0, "S:" 50 REM Finito
Obrázek 6: Vykreslení úsečky příkazem XIO.
Nikdo příčetný pravděpodobně nebude úsečky vykreslovat výše uvedeným způsobem, ovšem pomůže nám to pochopit další příklad. V něm voláme speciální operaci nazvanou FILL, kterou zařízení S: podporuje, ovšem která není (popravdě neznám důvod) dostupná v Atari BASICu. Příkaz FILL je navázán na kreslení úsečky, ovšem na každém obrazovém řádku se nevykreslí jen jeden pixel, ale všechny pixely napravo od úsečky, které jsou vyplněny barvou nastavenou do registru FILDAT, jenž je uložen na adrese 765. Vyplňování řádku skončí až na pixelu s odlišnou barvou pozadí. Pokud takový pixel neexistuje, bude výplň pokračovat i na levé straně obrazovky:
10 REM Kresleni polygonu pomoci prikazu XIO 11 REM 20 REM Nastaveni grafickeho rezimu 40x20x4 21 GRAPHICS 3 30 REM Umisteni na obrazovce + kresleni prvniho bodu 31 POSITION 0, 0 32 PUT #6, 1 40 REM Vykresleni polygonu 42 POSITION 10, 10 43 POKE 765, 2 44 XIO 18, #6, 0, 0, "S:" 50 REM Finito
Obrázek 7: Pokus o vyplnění polygonu v případě, že neexistuje „zarážka“ napravo.
V posledním příkladu tohoto typu nejprve vykreslíme vertikální „zarážku“ na sloupci číslo 20. Výplň se zastaví právě na této zarážce:
10 REM Kresleni polygonu pomoci prikazu XIO 11 REM 20 REM Nastaveni grafickeho rezimu 40x20x4 21 GRAPHICS 3 22 COLOR 1 23 PLOT 20, 0 24 DRAWTO 20, 20 30 REM Umisteni na obrazovce + kresleni prvniho bodu 31 POSITION 0, 0 32 PUT #6, 1 40 REM Vykresleni polygonu 42 POSITION 10, 10 43 POKE 765, 2 44 XIO 18, #6, 0, 0, "S:" 50 REM Finito
Obrázek 8: Pokus o vyplnění polygonu v případě, že existuje „zarážka“ napravo.
Tabulka zařízení: HATABS (Handler Address Table)
Ve třetí části dnešního článku si – prozatím alespoň ve stručnosti – popíšeme tabulku nazvanou HATABS (Handler Address Table). Je to velmi jednoduchá, ovšem o to užitečnější tabulka, díky které je možné do operačního systému zaregistrovat nová zařízení se zvoleným jménem i s libovolnými operacemi. Jakmile je tabulka naplněna (resp. doplněna) o nové zařízení a do paměti jsou nahrány jeho ovladače (ony handlery), může prakticky jakýkoli program začít toto zařízení používat.
Tabulka HATABS je umístěna na adresách 794–831 ($31A-$33F); jedná se tedy o pouhých 38 bajtů. Do této tabulky lze zapsat informace až o dvanácti zařízeních, přičemž pro každé zařízení (resp. pro každý řádek tabulky) jsou rezervovány tři bajty. První bajt obsahuje jméno zařízení v ATASCII (tedy S, E, C atd.). Další dva bajty pak adresu handleru zařízení. Ten bude volán operací CIOV atd. Nepoužité záznamy jsou vynulovány a na konci tabulky zbývají dva nulové bajty (fungují jako zarážka při průchodu tabulkou).
Stisk klávesy RESET by měl tabulku HATABS nastavit do této podoby:
| Adresa | Hex | Zařízení | Adresa handleru | Hex |
|---|---|---|---|---|
| 794 | $31A | P: | 58416 | $E430 |
| 797 | $31D | C: | 58432 | $E440 |
| 800 | $320 | E: | 58368 | $E400 |
| 803 | $323 | S: | 58384 | $E410 |
| 806 | $326 | KL | 58400 | $E420 |
Realizace výpisu obsahu tabulky HATABS v Atari BASICu
Vzhledem k tomu, jak jednoduchý je formát tabulky HATABS, můžeme velmi snadno realizovat její přečtení a výpis v Atari BASICu. Jedna z možných realizací vypadá následovně:
10 REM Vypis obsahu tabulky HATABS 15 REM 20 REM adresa zacatku tabulky HATABS 25 HATABS=794 30 REM smycka pro vypis tabulky 35 FOR ADDRESS=HATABS TO HATABS+38 STEP 3 40 DEVICE=PEEK(ADDRESS) 45 REM test na posledni zarizeni 50 IF DEVICE=0 THEN STOP 55 REM adresa handleru 60 HANDLER=PEEK(ADDRESS+1)+256*PEEK(ADDRESS+2) 65 PRINT CHR$(DEVICE), HANDLER 70 REM opakujeme smycku 75 NEXT ADDRESS
Nebo můžeme pro větší čitelnost odsazením zvýraznit programovou smyčku (ovšem Atari BASIC mezery odstraní – nejsou součástí tokenizovaného programu):
10 REM Vypis obsahu tabulky HATABS 15 REM 20 REM adresa zacatku tabulky HATABS 25 HATABS=794 30 REM smycka pro vypis tabulky 35 FOR ADDRESS=HATABS TO HATABS+38 STEP 3 40 DEVICE=PEEK(ADDRESS) 45 REM test na posledni zarizeni 50 IF DEVICE=0 THEN STOP 55 REM adresa handleru 60 HANDLER=PEEK(ADDRESS+1)+256*PEEK(ADDRESS+2) 65 PRINT CHR$(DEVICE), HANDLER 70 REM opakujeme smycku 75 NEXT ADDRESS
Výsledkem může být například následující výpis, ovšem konkrétní obsah tabulky HATABS pochopitelně závisí na mnoha faktorech (přítomnost DOSu, TTDOSu, ovladače BT-100 atd. atd.):
Obrázek 9: Výpis tabulky se zařízeními v případě emulovaného Atari (bez emulátoru bude pravděpodobně chybět zařízení H:).
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 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 \
key_01.xex key_02.xex \
key_03.xex key_04.xex \
key_05.xex \
cio_put_char.xex cio_put_block.xex \
cio_get_block.xex cio_modify_block.xex \
cio_print_1.xex cio_print_2.xex \
cio_print_3.xex cio_print_4.xex \
cio_read_file.xex cio_read_file_2.xex \
cio_write_byte_1.xex cio_write_byte_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
key: \
key_01.xex \
key_02.xex \
key_03.xex \
key_04.xex \
key_05.xex
cio: \
cio_put_char.xex \
cio_put_block.xex \
cio_get_block.xex \
cio_modify_block.xex \
cio_print_1.xex \
cio_print_2.xex \
cio_print_3.xex \
cio_print_4.xex \
cio_read_file.xex \
cio_read_file_2.xex \
cio_write_byte_1.xex \
cio_write_byte_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.
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) - Atari Graphics Demonstrations by Underground Software, 1985 | Atari 8 bit Demo
https://www.youtube.com/watch?v=h7N9EYSyCkw - Atari 8-bit Display List Interrupts: A Complete(ish) Tutorial
https://playermissile.com/dli_tutorial/ - Atari Assembler Editor manual
https://atariwiki.org/wiki/attach/Atari%20Assembler%20Editor/ATARI%20Assembler%20Editor%20User-s%20Manual-OCR.pdf - Atari 8-bit Fine Scrolling: A Complete(ish) Tutorial
https://playermissile.com/scrolling_tutorial/index.html - Atari Fine Scrolling
https://www.atarimagazines.com/compute/issue67/338_1_Atari_Fine_Scrolling.php - CTIA / GTIA Pinout Diagram
https://user.xmission.com/~trevin/atari/gtia_pinout.html - GTIA Modes
https://page6.org/archive/issue_02/page_10.htm - 56 graphic modes
https://www.atari800×l.eu/docs/kb/kb-hardware-0005-atari-8bit-56-graphic-modes.html - UNLOCKING THE 56 GRAPHIC MODES
https://www.atarimagazines.com/v3n5/allmodes.html - GTIA Modes 9, 10 & 11 + ANTIC data and color clocks
https://forums.atariage.com/topic/366256-gtia-modes-9–10–11-antic-data-and-color-clocks/ - ANTIC, GTIA and timing info
https://atarimax.com/jindroush.atari.org/atanttim.html - 6.10 Cycle timing
https://github.com/AnimaInCorpore/A8E/blob/main/AHRM/6.%20CTIA-GTIA/10.%20Cycle%20timing.md - Doug Neubauer
https://en.wikipedia.org/wiki/Doug_Neubauer - POKEY
https://en.wikipedia.org/wiki/POKEY - Inside the Atari 800XL
https://www.goto10retro.com/p/800×l-inside - Grayscale Project – „Jam Session“ – Chiptune Visualization / Atari SAP
https://www.youtube.com/watch?v=Qx-AHgvwrHo&list=PL92E73FD91764173B - POKEY MUSIC ( ATARI XL / XE ) =+ MUSIC FROM POLAND += DEMO
https://www.youtube.com/watch?v=5PswfMjMop4&list=RD5PswfMjMop4&start_radio=1 - Atari.org
http://www.atari.org/ - Atari POKEY
http://www.absoluteastronomy.com/topics/Atari_POKEY - Chiptune
http://www.absoluteastronomy.com/topics/Chiptune - ASAP – Another Slight Atari Player
http://asap.sourceforge.net/ - Atari SAP music archive
http://asma.atari.org/ - RASTER Music Tracker (RMT)
http://raster.infos.cz/atari/rmt/rmt.htm - POKEY explorer
https://github.com/ivop/pokey-explorer - POKEY C012294 Documentation
https://7800.8bitdev.org/index.php/POKEY_C012294_Documentation - Pokey Registers
https://user.xmission.com/~trevin/atari/pokey_regs.html - POKEY CO12294
http://krap.pl/mirrorz/atari/homepage.ntlworld.com/kryten_droid/Atari/800XL/atari_hw/pokey.htm - De Re Atari: SOUND
https://www.atariarchives.org/dere/chapt07.php#H7_3_5 - Paddle (game controller)
https://en.wikipedia.org/wiki/Paddle_(game_controller) - Interfacing Your Atari
https://www.atariarchives.org/creativeatari/Interfacing_Your_Atari.php - Atari SIO
https://en.wikipedia.org/wiki/Atari_SIO - Atari Chips
https://atarimax.com/jindroush.atari.org/achip.html - Table 4: Keyboard Code Index, KEYCODE: ATASCII
https://www.atariarchives.org/c3ba/kcindex.php - SIO2PC
http://raster.atariportal.cz/hw/sio2pc.htm - Using Serial Input/Output
https://www.atarimagazines.com/compute/issue64/insight_atari.php - SIO ROUTINES
https://www.atariarchives.org/mmm/sio.php - ATARI 8 bit Serial Input/Output (SIO)
https://allpinouts.org/pinouts/connectors/serial/atari-8-bit-serial-input-output-sio/ - SIOspecs
https://archive.org/details/SIOspecs - Interview with Joe Decuir
http://www.atarimuseum.com/articles/joedecuir.html - USB AND OS/2
http://www.os2voice.org/VNL/past_issues/VNL1199H/vnewsf5.htm - Standards and specs: The ins and outs of USB
http://www.ibm.com/developerworks/power/library/pa-spec7.html - USB Class Codes
http://www.usb.org/developers/defined_class - Universal Serial Bus
http://en.wikipedia.org/wiki/Usb - SMBus.org
http://www.smbus.org - SMBus FAQ
http://www.smbus.org/faq/faq.htm - System Management Bus
http://en.wikipedia.org/wiki/System_Management_Bus - SMBus Specifications
http://www.smbus.org/specs - SMBus Control Method Interface Specification Version 1.0
http://www.smbus.org/specs/smbus_cmi10.pdf - System Management Bus (SMBus) Specification Version 2.0
http://www.smbus.org/specs/smbus20.pdf - Atari Connection Machine
http://acm.atariportal.cz/s/con8bit/8bits - Atari Program Recorder
https://en.wikipedia.org/wiki/Atari_Program_Recorder - THE ATARI CASSETTE
https://www.atariarchives.org/dere/chaptC.php - Turbo-2000
https://www.atari-800.cz/turbo-2000 - Atari XC12 FSK Decoder
https://zeninstruments.blogspot.com/2024/08/atari-xc12-fsk-decoder.html - Clock recovery
https://en.wikipedia.org/wiki/Clock_recovery - Jiří Richter (programátor)
https://cs.wikipedia.org/wiki/Ji%C5%99%C3%AD_Richter_(program%C3%A1tor) - Spectrum tape interface
https://sinclair.wiki.zxnet.co.uk/wiki/Spectrum_tape_interface - How Tape Loading Works
https://lemmings.info/how-tape-loading-works/ - CIO Reference
https://atarifoundry.com/docs/forge/advanced-topics/cio-reference - The central input-output system in Atari computers
https://www.atariarchives.org/alp/chapter_9.php - ATR: chpt.1: Central Input/Output (CIO)
https://www.atariarchives.org/cfn/12/02/0010.php - NOTE and POINT
https://atarifoundry.com/docs/forge/advanced-topics/note-point
