Při popisu standardní sériové sběrnice SIO jsme se zmínili o tom, že osmibitové domácí mikropočítače Atari nebyly navrženy pouze takovým způsobem, aby byly použitelné jako sofistikovanější herní konzole. Samotná sběrnice SIO a taktéž dnes popsaná součást operačního systému nazvaná CIO (Central Input/Output) totiž poskytuje unifikovaný přístup k různým zařízením (přes takzvané kanály), umožňuje relativně snadným způsobem přidávat nové typy zařízení (příkladem může být systém Turbo 2000, k němuž se ještě vrátíme). A co je nejdůležitější – v případě, že je nové zařízení do systému přidáno, mohou ho začít prakticky ihned používat všechny aplikace, nehledě na to, zda vůbec byly s tímto zařízením testovány nebo zda zařízení existovalo v době, kdy aplikace vznikala.
Co se dozvíte v článku
- Jména standardních zařízení i zařízení vyžadující vlastní ovladače
- Standardní operace, které mohou zařízení podporovat
- Koncept kanálů (channels)
- Výchozí nastavení kanálů po inicializaci Atari BASICu
- Práce se zařízeními a kanály v Atari BASICu
- Ukázky práce se zařízeními v Atari BASICu
- Čtení a zápisy celých bloků: rozšíření TurboBASICu XL
- Praktická ukázka: zápis obsahu grafické paměti do rastrového formátu BMP
- Práce se zařízeními a kanály v assembleru
- Adresy subrutin používaných v CIO
- Struktura IOCB použitá subrutinou CIOV
- Zápis znaku na textovou obrazovku
- Zápis celého řetězce na textovou obrazovku
- Přečtení řetězce zadávaného z klávesnice
- Přečtení řetězce, jeho úprava na inverzní znaky s následným tiskem na obrazovku
- Rozdíl mezi CIO operacemi PUTCHR a PUTREC
- Příloha: Makefile pro překlad všech demonstračních příkladů
- Repositář s demonstračními příklady
- Odkazy na Internetu
Příkladů lze najít celou řadu – od různých typů disketových jednotek, přes RAM disky až po již zmíněný systém Turbo 2000. Díky kombinaci CIO+SIO bylo možné osmibitové mikropočítače Atari používat i pro kancelářské činnosti (tedy spíše ve funkci osobních počítačů), přičemž bylo umožněno postupné rozšiřování systému (nová tiskárna, další disketová jednotka, RAM disk atd.)
Obrázek 1: SpartaDOS je jedním z mnoha DOSů pro osmibitová Atari.
Jména standardních zařízení i zařízení vyžadující vlastní ovladače
Nejprve si řekněme, jak se se zařízeními pracuje z pohledu běžného uživatele počítače Atari. Zařízení jsou pojmenována (typicky písmenem a popř. doplňujícím číslem) a jak (Atari)BASIC, tak i aplikace (například textový editor atd.) zařízení identifikují právě podle jeho jména. Existuje několik standardních zařízení, které jsou většinou přístupná (prakticky) kdykoli. Tato zařízení jsou vypsána v následující tabulce:
| Jméno zařízení | Význam jména | Stručný popis zařízení |
|---|---|---|
| E: | screen Editor | |
| S: | Screen | použito v BASICu pro výstup do grafické části obrazovky nebo v textových režimech 1 a 2 |
| C: | Cassette recorder | datový rekordér, zde použit se standardním formátem zápisu (popsáno minule) |
| K: | Keyboard | vstup z klávesnice |
Další zařízení lze do systému přidat tak, že se nahraje jejich příslušný ovladač resp. handler (nebo například systém DOS pro disketové jednotky nebo TOS pro Turbo 2000). Nová zařízení přidaná tímto způsobem mohou mít prakticky libovolná jména, ovšem některá jména se ustálila – opět viz následující tabulku:
| Jméno zařízení | Význam jména | Stručný popis zařízení |
|---|---|---|
| P: | line Printer | tiskárna (většinou bez pořadového čísla, i když teoreticky by bylo možné použít více tiskáren současně) |
| D: | Disk drive | disketová jednotka, pokud je v systému jen jedna |
| D1-D8 | Disk drive #n | disketová jednotka s výběrem podle čísla (volí se přepínači) |
| D8 | RAM Disk | někdy je značen jako osmá disketová jednotka |
| T: | Turbo 2000 | Turbo 2000, celý soubor je tvořen jediným blokem |
| B: | Turbo 2000 | Turbo 2000, zápis po blocích |
| H: | hard drive | používán například v emulátorech pro čtení/zápis na souborový systém |
| R: | RS-232 | standardní sériový port (externí „krabička“ připojená k SIO) |
Obrázek 2: Po přechodu do Atari BASICu je nyní možné používat zařízení D1: (až teoreticky D8:).
Standardní operace, které mohou zařízení podporovat
Existuje několik standardních operací, které zařízení mohou (ale nemusí) poskytovat. Tyto operace jsou vypsány (i když poněkud nepřesně) v následující tabulce:
| 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í |
Koncept kanálů (channels)
Ještě předtím, než se s vybraným zařízením bude provádět nějaká operace (čtení, zápis atd.), je nutné k zařízení přiřadit nějaký kanál (channel resp. přesněji řečeno I/O channel): zařízení se otevře (open) pro provádění vybraných operací (typicky pro čtení a/nebo zápis). Kanál je z pohledu programátora (běžný uživatel se s nimi nesetká) reprezentován číslem 0 až 7. Každý kanál může být v daný okamžik přiřazen pouze k jedinému zařízení. Kanál lze navíc kdykoli uzavřít (close), což znamená, že k němu bude možné přiřadit jiné zařízení.
V praxi to tedy znamená, že v jeden okamžik lze pracovat maximálně s osmi zařízeními (sem se typicky počítá i klávesnice a obrazovka, takže se počet dalších zařízení snižuje na šest), což je ovšem většinou dostačující. Příkladem může být zápis dat na kazetu ve standardním formátu. Pouze v době zápisu musí být nějaký kanál otevřen a spojen se zařízením C:. Po provedení zápisu se kanál uzavře a bude volný pro další použití.
Shrňme si předchozí text: osmibitové mikropočítače Atari podporují koncept takzvaných zařízení, která jsou identifikována jedním písmenem a popř. i číslem (za názvem zařízení následuje dvojtečka). Zařízení mohou provádět různé operace standardním způsobem (čtení a zápis znaků či bloků). Ovšem ještě předtím, než je možné nějakou operaci provést, je nutné k zařízení přiřadit kanál (0 až 7). Operace se následně budou provádět přes tento zvolený kanál.
Výchozí nastavení kanálů po inicializaci Atari BASICu
Vše si samozřejmě postupně vyzkoušíme, nejprve v Atari BASICu a posléze i v assembleru. Musíme se však zmínit ještě o jedné důležité informaci – po spuštění počítače a inicializaci Atari BASICu jsou již některé kanály inicializovány, tj. je jim přiřazeno nějaké zařízení otevřené do režimu čtení a/nebo zápisu. Pokud je k Atari připojen jen běžný kazetový magnetofon a není načten ani DOS ani TOS (či ovladač RAMdisku), je výchozí přiřazení zařízení ke kanálům následující:
| Kanál | Zařízení | Režim otevření |
|---|---|---|
| 0 | E: | vstup i výstup |
| 6 | S: | výstup |
| 7 | C: | vstup i výstup |
Práce se zařízeními a kanály v Atari BASICu
V této části článku si ukážeme základní práci se zařízeními z Atari BASICu, a to z toho důvodu, že tyto relativně vysokoúrovňové operace se z BASICu provádí velmi snadno – Atari BASIC je sice pomalý a v mnoha ohledech omezený, ovšem práce se zařízeními je v něm vyřešena relativně dobrým způsobem (a ještě lépe je v tomto ohledu vybavený slavný TurboBASIC XL. V Atari BASICu jsou pro práci se zařízeními určené následující příkazy:
| # | Příkaz | Parametry | Stručný popis |
|---|---|---|---|
| 1 | OPEN | #kanál, režim, další_info, „zařízení:cesta“ | otevření kanálu v režimu čtení, zápisu, připojení na konec nebo čtení+zápisu |
| 2 | CLOSE | #kanál | uzavření kanálu |
| 3 | GET | #kanál, proměnná | načtení bajtu s jeho uložením do proměnné |
| 4 | PUT | #kanál, výraz | výraz je vyhodnocen, převeden na bajt a poslán na zápis do zařízení |
| 5 | INPUT | #kanál, proměnné | načítání dat ze zařízení, převod na numerické hodnoty nebo řetězce s uložením do proměnných |
| 6 | #kanál; výrazy | výrazy jsou vyhodnoceny, převedeny na řetězec a poslány do zařízení | |
| 7 | NOTE | #kanál, proměnná_1, proměnná_2 | do proměnné_1 zaznamená aktuální sektor a do proměnné_2 offset bajtu v sektoru |
| 8 | POINT | #kanál, sektor, offset | provede operaci typu „seek“ na sektor a offset v rámci sektoru |
| 9 | XIO | příkaz, #kanál, režim, 0, výraz | různé specializované operace (závisí na typu zařízení) |
Režim v příkazu OPEN je zakódován takto:
| Režim | Význam |
|---|---|
| 4 | vstup (read) |
| 8 | výstup (write) |
| 12 | vstup+výstup (12=4+8) |
| 9 | připojení za konec (append) |
Číslo sektoru je šestnáctibitové a velikost sektorů dosahuje až 256 bajtů. Z dnešního pohledu zastaralý Atari BASIC tedy dokáže pracovat se soubory o velikosti až 16MB – to není vůbec špatné.
Obrázek 3: Interaktivní zadávání I/O příkazů v BASICu - ten se tedy může použít i jako alternativa k shellu.
Ukázky práce se zařízeními v Atari BASICu
Ve všech výše uvedených příkazech se vždy pracuje s číslem kanálu a toto číslo je zapsáno za znak hashe, tedy #. Uveďme si několik příkladů zápisu (posléze si ukážeme i ucelenější příklady).
Samotné provedení vybraných vstupně/výstupních operací se v Atari BASICu realizuje poměrně snadno. Můžeme se například pokusit o zápis několika bajtů na kazetový magnetofon. Přitom se použije standardní formátu zápisu, který byl popsán v předchozím článku:
10 REM Zapis nekolika hodnot 11 REM na kazetu ve standardnim 12 REM formatu. 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, "C:" 40 REM Provedeni zapisu 41 FOR I=0 TO 100 42 PUT #4, I 43 NEXT I 50 REM Zavreme kanal 51 CLOSE #4
Pokud máte disketovou jednotku a BASIC spuštěný z DOSu, lze předchozí příklad přepsat. Nyní ovšem budeme pracovat nejenom se zařízením, ale i s názvem souboru, do kterého je prováděn zápis:
10 REM Zapis nekolika hodnot 11 REM na disketu. 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, "D:test.bin" 40 REM Provedeni zapisu 41 FOR I=0 TO 100 42 PUT #4, I 43 NEXT I 50 REM Zavreme kanal 51 CLOSE #4
Ještě jednodušší je využití zařízení H: (hard disk) v emulátoru počítačů Atari. V nastavení emulátoru se musí zvolit vhodný adresář na disku a povolit zápis do něj. Následovně lze z Atari BASICu spustit tento program:
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.bin" 40 REM Provedeni zapisu 41 FOR I=0 TO 100 42 PUT #4, I 43 NEXT I 50 REM Zavreme kanal 51 CLOSE #4
Po jeho vykonání by se měl na disku (resp. přesněji řečeno na souborovém systému Linuxu, Microsoft Windows atd.) objevit soubor test.bin s následujícím obsahem:
$ od -tx1 test.bin 0000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 0000020 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 0000040 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 0000060 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 0000100 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 0000120 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 0000140 60 61 62 63 64 0000145
Zápis textových dat (řetězců):
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
Povšimněte si, že řetězec je ukončen znakem pro konec řádku $9b:
$ od -tx1 test.txt 0000000 48 65 6c 6c 6f 20 41 74 61 72 69 21 9b 0000015
Podobným způsobem lze realizovat i čtení dat z nějakého zařízení. Opět si to ukažme na několika demonstračních příkladech. Navážeme na příklad předchozí (spouštěný v emulátoru). Pokusíme se načíst data ze zařízení H: a vypsat je na obrazovku:
10 REM Precteni retezce ze zarizeni 20 REM 21 REM Pro jistotu zavreme kanal 22 REM pred jeho pouzitim 22 CLOSE #4 30 REM Otevreme kanal pro cteni 31 OPEN #4, 4, 0, "H:test.txt" 40 REM Provedeni cteni 41 DIM A$(100) 42 INPUT #4, A$ 50 REM Zavreme kanal 51 CLOSE #4 60 REM Co jsme nacetli? 61 PRINT A$
Výsledek může vypadat následovně:
Obrázek 4: Řetězec načtený z disku se korektně vypsal na obrazovku.
Čtení a zápisy celých bloků: rozšíření TurboBASICu XL
Atari BASIC má při práci se zařízeními jedno poměrně zásadní omezení – nedokáže totiž (bez problémů) pracovat s celými (binárními) datovými bloky. Mohlo by se zdát, že namísto binárních bloků můžeme číst a zapisovat řetězce. To je do jisté míry pravda, ovšem problém způsobí znak pro konec řádku (Return), který u některých operací může operaci předčasně ukončit. V assembleru tyto problémy nenastávají, jak ostatně uvidíme dále. A řešení nabízí například i již výše zmíněný TurboBASIC XL, který podporuje jak všech devět příkazů popsaných výše, tak i dva nové příkazy určené pro čtení a zápis celých (binárních) bloků:
| # | Příkaz | Parametry | Stručný popis |
|---|---|---|---|
| BGET | #kanál, adresa, délka | přečtení celého bloku dat s jejich uložením od zadané adresy | |
| BPUT | #kanál, adresa, délka | zápis celého bloku dat |
Příklad použití je uveden přímo v manuálu TurboBASICu XL. Jedná se o kopii obsahu textové obrazovky (s výpisem programu) do souboru. Dovolil jsem si v kódu provést několik úprav:
100 GRAPHICS 0 101 LIST 110 REM Začátek obrazové paměti 111 ADDR=DPEEK(88) 120 REM Zápis na disk 121 CLOSE 122 OPEN #1, 8, 0, "D1:LISTING" 123 BPUT #1, ADDR, 40*24 123 CLOSE
Obrázek 5: Úvodní obrazovka jedné z mnoha variant slavného Turbo BASICu XL.
Praktická ukázka: zápis obsahu grafické paměti do rastrového formátu BMP
Díky existenci příkazu BPUT bylo možné relativně snadno implementovat program zapsaný v TurboBASICu XL, který přečte obsah grafické paměti v režimu GRAPHICS 8 (320×192 pixelů monochromaticky) a uloží ho do souboru se standardním rastrovým formátem BMP, takže výsledný screenshot bude možné načíst do prakticky libovolného moderního grafického editoru. Povšimněte si, že je řešeno i otočení pořadí obrazových řádků, protože BMP řádky ukládá odspoda nahoru:
1 ------------------------------ 2 REM SIN function plot (graph) 3 REM in graphics mode 8 4 REM 5 REM This source code has been 6 REM prepared for TurboBASIC XL 7 REM 8 REM 9 ------------------------------ 10 DEG 20 EXEC SET_GRAPHICS 30 EXEC DRAW_AXIS 40 REM PLOT FUNCTION 50 FOR X=0 TO 319 60 Y=79-70*SIN((X-160)*90/80) 70 IF Y<0 OR Y>159 THEN GOTO 90 80 PLOT X,Y 90 NEXT X 100 DIM FILENAME$(10) 110 FILENAME$="H:SIN.BMP" 120 EXEC WRITE_BMP 998 REM finito 999 STOP 1000 ------------------------------ 1010 REM SET GRAPHICS MODE 1020 ------------------------------ 1030 PROC SET_GRAPHICS 1040 GRAPHICS 8 1050 COLOR 1 1060 ENDPROC 2000 ------------------------------ 2010 REM DRAW AXIS 2020 ------------------------------ 2030 PROC DRAW_AXIS 2040 PLOT 160,0:DRAWTO 160,159 2050 PLOT 0,80:DRAWTO 319,80 2060 TEXT 0,82,"-90" 2070 TEXT 300,82,"90" 2080 TEXT 162,5,"1" 2090 TEXT 162,145,"-1" 2100 TEXT 162,82,"0,0" 2200 ENDPROC 2300 ------------------------------ 10000 ------------------------------ 10010 REM Store video RAM 10020 REM in graphics mode #8 into 10030 REM BMP file. 10035 REM 10040 REM Filename is to be provided 10050 REM via FILENAME$ variable. 10055 REM (Example: "H:TEST.BMP") 10060 ------------------------------ 10070 PROC WRITE_BMP 10075 PRINT "Writing raster image into file ";FILENAME$ 10080 OPEN #1,8,0,FILENAME$ 10085 REM write BMP header (32 bytes) 10090 RESTORE 10502 10095 DIM B$(3) 10100 FOR I=0 TO 31 10105 READ B$ 10110 B=DEC(B$(2,3)) 10115 PUT #1,B 10120 NEXT I 10125 REM write scanlines from last to first 10130 SCANLINE_START=DPEEK(88) 10135 SCANLINE_END=SCANLINE_START+40*191 10140 PERCENT=0 10145 PERCENT_DELTA=100/191 10150 FOR I=SCANLINE_END TO SCANLINE_START STEP -40 10155 BPUT #1,I,40 10160 REM ATARI BASIC HAVE TO USE PUT 10165 REM FOR J=0 TO 39 10170 REM PUT #1,PEEK(I+J) 10175 REM NEXT J 10180 PERCENT=PERCENT+PERCENT_DELTA 10185 PRINT TRUNC(PERCENT);"% "; 10190 NEXT I 10195 CLOSE #1 10200 ENDPROC 10499 ------------------------------ 10500 REM BMP file header 10501 REM magic number "BM" 10502 DATA $42,$4D 10503 REM file size=7712 bytes 10504 DATA $20,$1E,$00,$00 10505 REM reserved 10506 DATA $00,$00,$00,$00 10507 REM pixel array offset=32 10508 DATA $20,$00,$00,$00 10509 REM bitmap header size=12 bytes 10510 DATA $0C,$00,$00,$00 10511 REM bitmap width in pixels 10512 DATA $40,$01:REM 320 pixels 10513 REM bitmap height in pixels 10514 DATA $C0,$00:REM 192 pixels 10515 REM number of color planes 10516 DATA $01,$00:REM 1 clr.plane 10517 REM bits per pixel 10518 DATA $01,$00:REM 1 BPP 10519 REM first color in palette 10520 DATA $00,$00,$00 10521 REM second color in palette 10522 DATA $FF,$FF,$FF 10523 REM end of BMP file header
Práce se zařízeními a kanály v assembleru
Nyní se konečně dostáváme k zajímavější části článku. Budeme se totiž zabývat způsobem práce s kanály (a později i se zařízeními) v assembleru. V tomto případě sice nemáme k dispozici vysokoúrovňové příkazy tak, jako tomu bylo v Atari BASICu či v TurboBASICu, ovšem i v assembleru lze podobné operace provádět. Pracuje se zde s takzvanými IOCB neboli Input-Output Control Block(s).
Příkazy BASICů pro vstupně-výstupní operace mají obdobu v příkazech (operacích) CIO:
| Konstanta | Číslo operace | Plný název | Stručný popis |
|---|---|---|---|
| OPEN | $03 | OPEN | otevření kanálu pro čtení/zápis/připojení na konec |
| CLOSE | $0C | CLOSE | uzavření kanálu |
| GETCHR | $07 | GET CHARACTER | čtení znaku nebo bloku dat |
| PUTCHR | $0B | PUT CHARACTER | zápis znaku nebo bloku dat |
| GETREC | $05 | READ RECORD | čtení řetězce(!) ukončeného znakem $9B |
| PUTREC | $09 | WRITE RECORD | zápis řetězce(!) ukončeného znakem $9B |
| STATIS | $0D | STATUS | získání informace o stavu zařízení |
| SPECIL | $0E | SPECIAL | další operace specifické pro dané zařízení |
Pojmenování operací GET… a PUT… může být matoucí, ale ještě se k němu vrátíme.
Adresy subrutin používaných v CIO
Celý subsystém CIO se z pohledu programátora používajícího assembler skládá ze šestnácti podprogramů (subrutin), které je možné volat. Všechny tyto podprogramy jsou vypsány v následující tabulce:
| Návěští | Adresa | Popis |
|---|---|---|
| DISKIV | $E450 | Disk handier initiation routine |
| DSKINV | $E453 | Disk handler vector |
| CIOV | $E456 | Central Input/Output vector |
| SIOV | $E459 | Serial Input/Output vector |
| SETVBV | $E45C | Set system timers routine vector |
| SYSVBV | $E45F | System vertical blank interrupt processing |
| XITVBV | $E462 | Exit from vertical blank processing |
| SIOINV | $E465 | Serial Input/Output initialization |
| SENDEV | $E468 | Serial bus send enable routine |
| INTINV | $E46B | Interrupt handler routine |
| CIOINV | $E46E | Central Input/Output initialization |
| BLKBDV | $E471 | Blackboard mode vector to memo pad mode |
| WARMSV | $E474 | Warm start entry (follows SYSTEM RESET) |
| COLDSV | $E477 | Cold start entry point (follows power-up) |
| RBLOKV | $E47A | Cassette read block routine vector |
| CSOPIV | $E47D | Cassette open for input vector |
Pokud ovšem budeme pracovat „jen“ s kanály, vystačíme si se subrutinou CIOV. A právě tato subrutina bude volána ve všech demonstračních příkladech popsaných v navazujících kapitolách (takže na další subrutiny můžeme, alespoň prozatím, zapomenout).
Struktura IOCB použitá subrutinou CIOV
Pro provedení většiny základních vstupně-výstupních operací postačuje zavolat subrutinu CIOV, což se v assembleru provádí triviálním způsobem:
; zavolání rutiny pro CIO jsr CIOV
Jak se ovšem této subrutině předávají parametry? Registry mikroprocesoru MOS 6502 jsou zcela nedostačující, jak svým počtem, tak bitovou šířkou. Zásobník je taktéž obecně velmi malý a navíc se s ním pracuje relativně špatně (neexistují totiž instrukce s adresováním SP+offset). Navíc je nutné počítat s tím, že se některé operace volají i několikrát za sebou. Příkladem může být kopie dat (po blocích) z jednoho zařízení na zařízení jiné.
Řešení, které bylo v Atari OS implementováno, je založeno na takzvaných IOCB neboli Input-Output Control Block. Jedná se o paměťové bloky o velikosti šestnácti bajtů, které obsahují parametry pro další CIO operaci. Počet IOCB je roven osmi, protože pro každý kanál existuje zvláštní IOCB. Je tomu tak z toho důvodu, aby bylo umožněno provádění opakovaných operací. IOCB kanálu číslo #0 začíná na adrese $0340, IOCB kanálu číslo #1 na adrese $0350 atd. Každý IOCB má následující strukturu:
| Adresa | Název | Stručný popis |
|---|---|---|
| $0340 | ICHID | index do tabulky ovladačů zařízení |
| $0341 | ICDNO | číslo zařízení, například pro diskety 1–8 |
| $0342 | ICCOM | číslo příkazu – viz třetí kapitolu s tabulkou příkazů (operací) |
| $0343 | ICSTA | naplněno kódem se stavem provedené operace (OK/chyba) |
| $0344 | ICBAL | adresa bufferu pro zápis či čtení dat (nižší bajt) |
| $0345 | ICBAH | adresa bufferu pro zápis či čtení dat (vyšší bajt) |
| $0346 | ICPTL | používáno jen BASICem |
| $0347 | ICPTH | používáno jen BASICem |
| $0348 | ICBLL | velikost bufferu (nižší bajt) |
| $0349 | ICBLH | velikost bufferu (vyšší bajt) |
| $034A | ICAX1 | závisí na volané operace |
| $034B | ICAX2 | dtto (málokdy použito) |
| $034C | ICAX3 | dtto (málokdy použito) |
| $034D | ICAX4 | dtto (málokdy použito) |
| $034E | ICAX5 | dtto (málokdy použito) |
| $034F | ICAX6 | dtto (málokdy použito) |
Pro základní operace typu čtení či zápisu postačuje:
- Naplnit ICCOM kódem prováděné operace
- Naplnit ICBAH+ICBAL adresou bufferu (naplněného při zápisu, zapisovaného při čtení)
- Naplnit ICBLH+ICBLL délkou resp. kapacitou bufferu
- Zavolat jsr CIOV
Zápis znaku na textovou obrazovku
V dnešním prvním demonstračním příkladu vytvořeném v assembleru vypíšeme na obrazovku znak s kódem $41 (tedy velké „A“). Zápis je proveden do kanálu číslo #0, který je implicitně otevřen pro zařízení E: (screen Editor):
Obrázek 6: Zápis jediného znaku přes CIO.
Použijeme přitom operaci PUTCHR a do IOCB číslo 0 uvedeme adresu jednobajtového bufferu, který obsahuje právě kód zapisovaného znaku:
.include "atari.inc"
.CODE
.proc main
ldx #0 ; offset odvozený od čísla IOCB kanálu (nutno násobit šestnácti)
lda #PUTCHR ; prováděná operace
sta ICCOM, x
; 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
; zavolání rutiny pro CIO
jsr CIOV
loop:
jmp loop ; program vlastně nice nedělá - jen cyklí!
.endproc
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 celého řetězce na textovou obrazovku
Namísto jediného znaku můžeme přes CIO operaci PUTCHR vypsat delší blok (teoreticky celý obsah paměti) resp. řetězec:
message: .byte "Hello, world!"
Postačuje pouze korektně vypočítat počet zapisovaných znaků:
; nastavení počtu zapisovaných bajtů lda #(end_of_message-message) sta ICBLL, x lda #0 sta ICBLH, x
Výsledek:
Obrázek 7: Zápis delšího bloku přes CIO.
Zdrojový kód po výše provedené úpravě vypadá následovně:
.include "atari.inc"
.CODE
.proc main
ldx #0 ; offset odvozený od čísla IOCB kanálu (nutno násobit šestnácti)
lda #PUTCHR ; 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ů
lda #(end_of_message-message)
sta ICBLL, x
lda #0
sta ICBLH, x
; zavolání rutiny pro CIO
jsr CIOV
loop:
jmp loop ; program vlastně nice nedělá - jen cyklí!
.endproc
message: .byte "Hello, world!"
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
Přečtení řetězce zadávaného z klávesnice
Prozatím jsme používali CIO operaci PUTCHR určenou pro zápis bajtů či bloků. Opačnou operací je GETCHR, která dokáže načíst blok o maximální zadané délce (v našem případě se jedná o deset bajtů). I tuto operaci lze provést s kanálem #0, protože zařízení E: podporuje vstup z klávesnice. Program na konci změní barvu obrazovky, aby bylo patrné, že se operace GETCHR skutečně dokončila:
Obrázek 8: Obrazovka se po přečtení bufferu z klávesnice obarví.
Opět si ukažme celý zdrojový kód příkladu:
.include "atari.inc"
.CODE
.proc main
ldx #0 ; offset odvozený od čísla IOCB kanálu (nutno násobit šestnácti)
lda #GETCHR ; prováděná operace
sta ICCOM, x
; adresa, na který se blok zapíše
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
; zavolání rutiny pro CIO
jsr CIOV
lda #18 ; kod barvy
sta COLOR2 ; ulozit do registru COLOR2
loop:
jmp loop ; program vlastně nice nedělá - jen cyklí!
.endproc
buffer: .res 10
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
Přečtení řetězce, jeho úprava na inverzní znaky s následným tiskem na obrazovku
Další demonstrační příklad je již poněkud komplikovanější, protože v něm provádíme trojici operací:
- Načtení řetězce ze zařízení E: (screen Editor) do bufferu
- Negace nejvyšších bitů obsahu celého bufferu, čímž se vlastně všechny znaky změní na svoji inverzní variantu
- Výpis řetězce na zařízení E:, čímž se inverzní znaky objeví na obrazovce
V demonstračním příkladu sice vyplňuji IOCB pro kanál číslo #0 dvakrát za sebou, ale ve skutečnosti tomu tak být nemusí – jak adresa bufferu, tak i jeho délka se přece nemění, takže by mělo postačovat modifikovat bajt na adrese ICCOM. Pro větší čitelnost (resp. kontext) jsem však zvolil „ukecanější variantu“ programu.
Výsledek po načtení řetězce, jeho modifikaci a výpisu:
Obrázek 9: Původní text, který jsem zapsal na klávesnici a text vypsaný programem po jeho úpravě na inverzní znaky.
Následuje výpis celého zdrojové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 #GETCHR ; prováděná operace
sta ICCOM, x
; adresa, na který se blok zapíše
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
; zavolání rutiny pro CIO
jsr CIOV
; modifikace obsahu bufferu
ldx #0
next_char:
lda buffer, x
eor #%10000000 ; inverse video
sta buffer, x
inx
cpx #(end_of_buffer-buffer)
bne next_char
ldx #0 ; offset odvozený od čísla IOCB kanálu (nutno násobit šestnácti)
lda #PUTCHR ; prováděná operace
sta ICCOM, x
; adresa zapisovaného bloku
lda #<buffer
sta ICBAL, x
lda #>buffer
sta ICBAH, x
; nastavení počtu zapisovaných bajtů
lda #(end_of_buffer-buffer)
sta ICBLL, x
lda #0
sta ICBLH, x
; zavolání rutiny pro CIO
jsr CIOV
loop:
jmp loop ; program vlastně nice nedělá - jen cyklí!
.endproc
buffer: .res 10
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
Rozdíl mezi CIO operacemi PUTCHR a PUTREC
Ještě nám zbývá jedna past, resp. specifikum pojmenování operací PUTCHR a PUTREC. Obě operace dokážou do zvoleného kanálu zapsat blok dat, přičemž velikost bloku je předána v IOCB. Vyzkoušejme si tedy, co uvidíme na obrazovce (tedy na zařízení E:) v případě, že operace PUTCHR i PUTREC zavoláme se stejnou zprávou i stejnou velikostí bufferu. Velikost bufferu bude nastavena na 256 bajtů a buffer bude na začátku obsahovat řetězec ukončený znakem pro konec řádku $9b (155):
message: .byte "Hello, world!", $9b
Výsledky se budou lišit, což je patrné ze screenshotů:
Obrázek 10: Výpis bloku o velikosti 256 bajtů CIO operací PUTCHR. Srdíčka mají kód 0.
Obrázek 11: Výpis bloku o velikosti 256 bajtů CIO operací PUTREC.
Rozdíl způsobuje znak $9b (155), tedy konec řádku.
Následují výpisy zdrojových kódů obou demonstračních příkladů. První z nich volá CIO operaci PUTCHR, druhý pak operaci PUTREC:
.include "atari.inc"
.CODE
.proc main
ldx #0 ; offset odvozený od čísla IOCB kanálu (nutno násobit šestnácti)
lda #PUTCHR ; 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
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
Varianta s CIO operací PUTREC:
.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
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
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
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
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/issue02/page10.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/chapter9.php - NOTE and POINT
https://atarifoundry.com/docs/forge/advanced-topics/note-point
