Na osmibitových mikropočítačích (a nyní se zaměříme především na domácí mikropočítače) měli ti uživatelé, kteří se chtěli zabývat programováním, na výběr z relativně velkého množství různých vývojových nástrojů a pomůcek (bylo jich dokonce až překvapivě velké množství – desítky programovacích jazyků atd.). Některé mikropočítače byly vybaveny pouze velmi jednoduchým operačním systémem zajišťujícím základní vstupně/výstupní operace (čtení klávesnice, zápis znaku na obrazovku, rutiny pro čtení a zápis dat na magnetofon).
Co se dozvíte v článku
- Monitory
- Dobové assemblery pro osmibitová Atari
- Vývoj s využitím Atari Assembler/Editoru krok za krokem
- Zápis jednoduchého programu
- Překlad programu s kontrolou chyb
- Spuštění a ladění s využitím debuggeru
- Uložení a zpětné načtení zdrojového kódu programu, uložení listingu vytvořeného assemblerem
- Uložení výsledného spustitelného programu na zvolené zařízení
- Analýza souboru PRG1.OBJ, který vznikl překladem
- Složitější projekt, pro jehož vývoj použijeme Atari Assembler/Editor
- Zdrojový kód programu určený pro překlad assemblerem CA65
- Definice adres registrů a dalších konstant použitých v programu
- Nastavení barev, pozic hráčů, spojení střel do pátého hráče a povolení DMA
- Nastavení bitmap (tvarů) všech pěti hráčů
- Hlavní programová smyčka: pohyb spritu joystickem
- Výsledná podoba celého programu ve verzi pro Atari Assembler/Editor
- Listing vygenerovaný assemblerem při překladu
- Repositář s demonstračními příklady
- Odkazy na Internetu
Většinou však byly domácí osmibitové počítače vybaveny nějakým dialektem programovacího jazyka BASIC (i když by se spíše hodilo mít k dispozici FORTH, to je však téma na delší debatu). I když se BASIC hodil na provádění různých výpočtů, jednodušších vizualizací a simulací (méně již na zpracování dat), poměrně rychle se narazilo na jeho limity. Především se jednalo o rychlost resp. pomalost samotného interpretru, obtížnou tvorbu strukturovaných programů a mnohdy i větší paměťové nároky.
Obrázek 1: Atari BASIC pochopitelně nebyl jediným dostupným programovacím jazykem pro osmibitové domácí mikropočítače Atari.
Alternativou používanou profesionály byly assemblery. Dnes si ukážeme tvorbu programů v Atari Assembler/Editoru, což je sice pomalý, ovšem možná až (s ohledem na jeho velikost) překvapivě dobrý assembler. Práce v tomto assembleru je do jisté míry interaktivní a možná čtenáře tohoto článku překvapí, jak „hardcore“ vlastně celý proces vývoje byl: muselo se bojovat s omezenou kapacitou operační paměti, s pomalostí assembleru, s kryptickými chybovými kódy, ale i například s takovou „maličkostí“, jakou je malý počet znaků zobrazitelných na obrazovce.
Obrázek 2: Zápis strojových instrukcí přímo s využitím strojového kódu instrukcí (řádky s DATA) a spuštění načteného strojového programu funkcí USR.
Monitory
Mnoho začínajících programátorů se muselo spokojit s takzvaným monitorem, což byl (a na některých platformách doposud je) program umožňující manipulaci s daty uloženými v operační paměti, tj. zápis dat do paměti, čtení (zobrazení) vybraného bloku, přesun bloku, vyplnění určité oblasti konstantou, vyhledávání sekvence hodnot, čtení a zápis dat na externí paměťové médium (typicky na magnetofon). Nutno dodat, že některé pokročilejší monitory byly vybaveny i takzvaným disassemblerem umožňujícím transformaci sekvence bajtů na symbolické instrukce. Mimochodem – při výpisu obsahu operační paměti se v monitorech většinou používal stejný formát, jaký najdeme u mnoha moderních programátorských hexa editorů (některé techniky již pravděpodobně dosáhly své dokonalosti a není nutné je dále vyvíjet).
Obrázek 3: Úvodní obrazovka tuzemského Turbo Monitoru, na který nemůžeme při popisu osmibitových počítačů Atari zapomenout.
Monitory, zejména jejich pokročilejší varianty vybavené disassemblerem (zpětným assemblerem), bylo možné použít i pro tvorbu programů na úrovni strojového kódu. Takový program se většinou nejprve zapsal na papír (nutně se muselo jednat o čtverečkovaný papír :-) ve formě assembleru, dále se provedl ruční překlad jednotlivých instrukcí do sekvence decimálních nebo hexadecimálních číslic a následně se tato sekvence zapsala do monitoru do určité předem vybrané oblasti operační paměti. V případě, že monitor podporoval zápis bloku paměti na externí paměťové médium (kazetový magnetofon, disketu), jednalo se o dosti primitivní, ovšem stále ještě použitelné (a v některých případech i používané) vývojové prostředí.
Obrázek 4: Turbo Monitor obsahuje i disassembler, tudíž ho bylo možné použít jako relativně použitelné vývojové prostředí.
Na druhou stranu je programování na úrovni strojového kódu samozřejmě velmi pracné, zejména ve chvíli, kdy je nutné existující program modifikovat a tím pádem měnit cílové adresy skoků, adresy globálních proměnných atd. Mnohem civilizovanější způsob představovalo použití takzvaných assemblerů, což byly nástroje schopné překládat programy zapsané v jazyku symbolických adres/instrukcí do strojového kódu – ostatně přesně pro podobné činnosti jsou počítače zkonstruovány.
Obrázek 5: Výpis obsahu paměti Turbo Monitorem (jeden z možných formátů).
Obrázek 6: Výpis obsahu paměti Turbo Monitorem (další z možných formátů).
Dobové assemblery pro osmibitová Atari
Na osmibitových domácích mikropočítačích se používaly dva typy assemblerů. Prvním typem byly assemblery interaktivní, které uživateli nabízely poměrně komfortní vývojové prostředí, v němž bylo možné zapisovat jednotlivé instrukce, spouštět programy, krokovat je, vypisovat obsahy registrů mikroprocesoru atd. Výhodou takto pojatého řešení byla nezávislost těchto assemblerů na rychlém externím paměťovém médiu. Se zástupci těchto assemblerů určených pro počítače Atari se ve stručnosti seznámíme i v dnešním článku, protože jak Atari Assembler Editor, tak i MAC/65 náleží do této kategorie.
Obrázek 7: Úvodní obrazovka Atari Assembler Editoru je minimalisticky strohá. A tak to má být.
Druhý typ assemblerů je používán dodnes – jedná se vlastně o běžné překladače, kterým se na vstupu předloží zdrojový kód (v případě osmibitových počítačů Atari uložený na kazetě či disketě) a po překladu se výsledný nativní kód taktéž uloží na paměťové médium (odkud ho lze spustit). Tyto assemblery byly mnohdy vybaveny více či méně dokonalým systémem maker (odtud název macroassembler). Příkladem takového assembleru pro Atari jsou všechny moderní crossassemblery, včetně CA65, který v tomto seriálu hojně používáme.
Obrázek 8: Vestavěná nápověda v programu o velikosti osm kilobajtů? Zapomeňte, ostatně nápověda je jen pro pojídače koláčů.
Jedním z nejstarších vývojových nástrojů pro osmibitové mikropočítače Atari je Atari Assembler Editor, jehož vznik se datuje do let 1979 až 1980. Tento nástroj byl používán i pro vývoj samotného operačního systému počítačů Atari. Jak však tento nástroj vůbec vznikl, když ještě vlastně počítače Atari nebyly dokončené? První (zjednodušené) verze byly ručně děrovány na děrnou pásku, která byla použita pro naprogramování čipu EPROM. Ten byl vložen do prototypu Atari a následně otestován. Jednalo se tak o jednu z forem bootstrapingu, kterým jsme ze zabývali v článku Můžeme věřit překladačům? Projekty řešící schéma „důvěřivé důvěry“. Výsledná podoba Atari Assembler Editoru byla dodávána na standardní cartridge o kapacitě osmi kilobajtů (ovšem ve skutečnosti se do značné míry využívaly subrutiny z operačního systému a používané i Atari BASICem).
Obrázek 9: Zápis programu s instrukcemi pro změnu barvy okraje obrazovky.
Atari Assembler Editor se skládal ze tří částí: editoru, assembleru a debuggeru (což však byl ve skutečnosti pouze monitor – viz předchozí text). Všechny tři části byly dostupné z cartridge a bylo možné se mezi nimi přepínat. Zdrojový kód zapisovaný v editoru byl překládán dvouprůchodovým překladačem a mohl být v operační paměti uložen souběžně se zdrojovým kódem, což ovšem znamenalo omezení maximálního objemu zdrojového kódu. Zajímavé a typické pro interaktivní assemblery je, že řádky zdrojového kódu byly číslovány, podobně jako v BASICu. K dispozici však byly i poměrně pokročilé operace pro vyhledání návěští atd.
Obrázek 10: Překlad programu Atari Assembler Editorem je sice obecně pomalý, ale u našich čtyř řádků to není poznat.
Debugger (spíše monitor) umožňoval zobrazení obsahu operační paměti, zobrazení obsahu registrů mikroprocesoru, modifikaci paměti, zobrazení disassemblované části paměti, krokování programu atd. – ovšem ne tak kvalitně, jako tomu bylo u dále popsaného assembleru MAC/65.
Obrázek 11: Zpětný listing programu.
Obrázek 12: Spuštění programu v debuggeru. Výsledek je ihned viditelný.
Další programátorský nástroj, s nímž se prozatím alespoň ve stručnosti seznámíme, se jmenuje MAC/65. Jedná se o assembler a současně i o debugger, jehož ovládání je odvozeno od výše zmíněného Atari Assembler Editoru; ve skutečnosti je však MAC/65 prakticky po všech stránkách lepší (až na poněkud vyšší cenu). Za vývojem MAC/65 stála společnost Optimized Systems Software (OSS). MAC/65 byl dodáván na specializované cartridgi s kapacitou 16kB, což je dvojnásobná kapacita, než jakou počítače Atari podporují (konektor měl pouze třináct adresních pinů). Z tohoto důvodu bylo oněch 16kB rozděleno do dvojice paměťových bank, z nichž každá měla kapacitu osmi kilobajtů a mezi kterými se provádělo automatické přepínání (taková cartridge se někdy nazývala „supercartridge“ a existovalo jich více typů, které se lišily způsobem přepínání paměťových bank).
Obrázek 13: První verze slavného assembleru MAC/65.
Předností assembleru MAC/65 byl mnohem rychlejší překlad v porovnání s Atari Assembler Editorem. Taktéž byla k dispozici lepší forma debuggeru dostupná pod příkazem DDT (což je velmi příhodné označení).
Obrázek 14: Druhá verze MAC/65 dodávaná na cartridge.
Vývoj s využitím Atari Assembler/Editoru krok za krokem
V praktické části dnešního článku si nejprve ukážeme několik způsobů, jakými lze využít původní Atari Assembler/Editor pro vývoj aplikací. Využívat budu původní verzi tohoto nástroje, která byla dodávána v cartridge. To znamenalo, že samotné načtení assembleru bylo prakticky okamžité – postačilo počítač zapnout ve stavu, kdy v něm byla cartridge nainstalována. Tudíž bylo možné realizovat vývoj i v případě, že jediným záznamovým zařízením byl kazetový magnetofon (to ovšem znamenalo omezení velikosti vyvíjeného programu a samozřejmě také nepříjemná zdržení při čtení a zápisu jak zdrojového kódu programu, tak i výsledného binárního spustitelného souboru).
Ovšem i samotný Atari Assembler/Editor měl mnohá omezení. Zejména standardní kapacity cartridge dosahovaly maximálně osmi kilobajtů (bylo k dispozici jen třináct adresových vodičů) – a přesně tuto velikost má i cartridge s assemblerem. Velmi stručná hlášení assembleru i stručnosti příkazů plynou mj. i z těchto omezení. S dalšími omezeními a nedostatky tohoto assembleru se postupně seznámíme v dalších kapitolách.
Obrázek 15: Hra Caverns of Mars byla celá naprogramována a odladěna v Atari Assembler/Editoru. Její délka (binární soubor) dosahuje 12kB (prakticky jen strojový kód bez dat), což byl slušný výkon.
Zápis jednoduchého programu
Při spuštění se assembler nachází v režimu EDIT:
Obrázek 16: Výchozí stav assembleru.
V tomto režimu se očekává zápis příkazů nebo programových řádků. Podobně jako v BASICu se řádek začínající celým číslem považuje za programový řádek, který je uložen do paměti (zpracovávat se bude ve správném pořadí). Ostatní řádky jsou chápány jako příkazy, které se ihned vykonají.
Každý programový řádek má tvar:
číslo_řádku návěští instrukce operandy komentář
To znamená, že pokud vynecháme návěští, musí být mezi číslem řádku a instrukcí zapsány minimálně dvě mezery (nebo více mezer). Kromě instrukcí lze zapisovat i několik typů pseudoinstrukcí a deklarací. Jednou z nich je i určení adresy, od které budou ukládány další překládané řádky. Náš program je velmi krátký a vejde se celý do šesté stránky paměti, tj. bude ukládán od adresy $0600 (šestá stránka je volná i v BASICu i v prostředí assembleru). Zkusme tedy zapsat následující program (pozor na dvojité mezery):
10 *=$0600 20 LDA #42 30 STA 712 40 BRK
Zdrojový kód si můžete kdykoli zobrazit se správným pořadím řádků pomocí příkazu LIST (tedy jako v BASICu).
Nic nám ovšem nebrání v zápisu programu včetně komentářů. Ty se od operandů oddělují mezerou nebo mezerami:
Obrázek 17: Zdrojový kód je do paměti uložen i s komentáři.
Překlad programu s kontrolou chyb
Po zápisu zdrojového kódu programu do paměti je nutné provést jeho překlad. Pro tento účel slouží příkaz ASM, který sice akceptuje několik parametrů, ovšem jedná se o parametry nepovinné. V případě, že zadáme pouze příkaz:
ASM
provede se postupné načítání programových řádků z operační paměti a výsledek překladu je taktéž uložen do operační paměti (v našem případě od adresy $0600, tedy na šestou stránku paměti). A současně s druhou fází překladu se na obrazovku (resp. přesněji řečeno na zařízení E: vypisuje takzvaný listing), v němž je možné zkontrolovat adresy atd. Listing má pevně daný formát se sloupcem s absolutní adresou, dále se sloupcem s výpisem obsahu paměti, pravé sloupce pak obsahují opis zdrojového kódu:
Obrázek 18: Průběh překladu zdrojového kódu s posláním listingu na obrazovku (pro kontrolu adres atd.).
Po provedení příkazu ASM se assembler vrátí zpět do režimu EDIT.
Pochopitelně ovšem mohou být ve fázi překladu nalezeny různé chyby. Assembler je v tomto případě poměrně strohý a vypíše pouze kód chyby, jehož význam je nutné dohledat v manuálu (ten je ovšem praktický – začíná právě seznamem možných chyb s jejich popisem):
Obrázek 19: Chybová hlášení assembleru jsou (minimálně z dnešního pohledu) poměrně strohá: opis chybného řádku a kód chyby.
Spuštění a ladění s využitím debuggeru
Spuštění programu je nutné provést v režimu debuggeru, do kterého se přepneme příkazem:
BUG
V tomto režimu jsou očekávány odlišné příkazy, než v režimu editoru. Jedním novým příkazem je příkaz pro skok (goto) na určitou adresu, která je zapsána za jméno příkazu G:
G0600
Výsledkem by měla být pozměněná barva okraje obrazovky:
Obrázek 20: Spuštění programu v režimu debuggeru. Podle změněné barvy okraje obrazovky lze ihned vidět, že program byl vykonán korektně.
Debugger ovšem nabízí i další příkazy; k některým z nich se ještě vrátíme:
| Příkaz | Stručný popis |
|---|---|
| DR | zobrazení registrů CPU |
| CR | modifikace registrů CPU |
| Dadresa | zobrazení obsahu paměti |
| Cadresa | modifikace paměti |
| Ladresa | disassembler |
| A | assembler jediné instrukce |
| T | trasování programu |
| Sadresa | krokování programu |
| X | návrat do editoru |
Uložení a zpětné načtení zdrojového kódu programu, uložení listingu vytvořeného assemblerem
Samotný zdrojový kód je možné uložit na libovolné zařízení, které umožňuje zápis. K tomu se příkaz LIST, který může mít následující podobu:
LIST #H:PRG1
Pro nahrání zdrojového kódu ze zařízení se použije příkaz ENTER:
ENTER #H:PRG1
Obrázek 21: Přečtení zdrojového kódu programu ze souboru na zařízení H:
Zařízení se ovšem používají i v příkazu ASM. Příkladem je uložení listingu do souboru či tisk na zařízení P:
ASM ,#P: ASM ,#H:LISTING
Již z předchozí poznámky do jisté míry vyplývá, že assembler dokáže pracovat dávkovým způsobem, tedy tak, jak jsme zvyklí dnes. Vstupní zdrojový text může být načítán ze zvoleného zařízení (souboru), postupně překládán a listing produkovaný assemblerem bude uložen do jiného zařízení či souboru:
ASM #H:PRG1,#H:LISTING
Ostatně samotný listing si můžeme nechat zobrazit operačním systémem. Jen je zapotřebí korektně pracovat se znaky pro konec řádku:
$ tr "\233" "\n" <LISTING 0000 10 *= $0600 0600 A900 20 LDA #0 0602 8DC602 30 STA 710 0605 00 40 BRK 0 ERRORS
Obrázek 22: Překlad s listingem na obrazovku (první příkaz) a listingem do souboru (druhý příkaz).
Obrázek 23: Překlad ze zdrojového kódu načteného ze souboru s listingem provedeným do jiného souboru.
Uložení výsledného spustitelného programu na zvolené zařízení
Nejvíce komplikovaná varianta příkazu ASM obsahuje jména tří zařízení a popř. i tři jména souborů. Formát je následující:
ASM zdroj, listing, cílový_binární_soubor
Můžeme například načítat zdrojový soubor z diskety, listing provádět na tiskárnu (zařízení P:) a výsledný binární soubor ukládat na kazetu ve standardním formátu (bloky 600Bd, zařízení C:):
ASM #D1:PRG1,#P:,#C:
Vzhledem k tomu, že ukázkové screenshoty vytvářím v emulátoru a nikoli na reálném Atari, mohu využít zařízení H:
ASM #H:PRG1,#H:LISTING,#H:PRG1.OBJ
Obrázek 24: Dávkový způsob se specifikací souboru, do kterého se uloží výsledek překladu.
Analýza souboru PRG1.OBJ, který vznikl překladem
Zastavme se na chvíli u souboru PRG1.OBJ, který vznikl jako výsledek činnosti assembleru (a vlastně i linkeru – pokud tedy použijeme moderní terminologii). Tento soubor má délku dvanácti bajtů a jeho obsah si můžeme zobrazit například nástrojem od (octal dump), nebo je možné využít jakéhokoli dobového nebo moderního hexa editoru. Pro jednoduchost ovšem zůstaňme u nástroje od:
$ od -t x1 PRG.OBJ 0000000 ff ff 00 06 05 06 a9 2a 8d c8 02 00 0000014
Tento soubor je možné přímo spustit v emulátoru osmibitových mikropočítačů Atari. Na rozdíl od moderních formátů spustitelných souborů (ELF atd.) má PRG.OBJ interně velmi jednoduchou strukturu. Skládá se (obecně) z jednotlivých segmentů, přičemž na začátku je u spustitelných souborů umístěn speciální segment nazvaný EXEHDR. Každý segment je uložen následovně:
| Offset | Stručný popis |
|---|---|
| 00–01 | obsahuje 0×ffff u prvního segmentu EXEHDR, u dalších segmentů uveden nemusí být |
| 02–03 | startovní adresa (dva bajty); obsah segmentu se do paměti nahraje právě od této adresy |
| 04–05 | koncová adresa určená pro výpočet délky segmentu |
| 06-?? | obsah segmentu |
Náš soubor PRG1.OBJ obsahuje jen jediný segment. Jeho obsah lze tedy dekódovat následujícím způsobem:
| Offset | Hodnoty bajtů | Stručný popis |
|---|---|---|
| 00–01 | ff ff | označení segmentu EXEHDR, jedná se tedy o spustitelný soubor |
| 02–03 | 00 06 | startovní adresa je rovna $0600 (šestá stránka paměti) |
| 04–05 | 05 06 | koncová adresa je rovna $0605 (stále se tedy nacházíme v šesté stránce paměti) |
| 06–07 | a9 2a | instrukce LDA #$2a (původně LDA #42) |
| 08–10 | 8d c8 02 | instrukce STA $02c8 (původně STA #712) |
| 11 | 00 | instrukce BRK |
Složitější projekt, pro jehož vývoj použijeme Atari Assembler/Editor
Při zápisu a překladu programu, který se skládá ze čtyř programových řádků a pouhých tří instrukcí, pochopitelně nedokážeme posoudit, do jaké míry je Atari Assembler/Editor reálně použitelný ani jak je rychlý (nebo naopak pomalý). Proto se pokusíme o naprogramování poněkud delší aplikace. Bude se jednat o přepis příkladu, se kterým jsme se seznámili při popisu konfigurace grafického čipu GTIA. Program zobrazí pětici hráčů (players), přesněji řečeno čtyři hráče doplněné o čtveřici střel, ze kterých byl složen pátý hráč. Uživatel následně může s využitím joysticku horizontálně pohybovat prvním hráčem. Aby byl pohyb dostatečně pomalý (a viditelný pro člověka), je synchronizován s hodinami počítače.
Zdrojový kód bude mít délku cca 130 řádků, tedy zhruba pět obrazovek. Je to již dlouhý program? Záleží na úhlu pohledu. Překlad takového programu totiž Atari Assembler/Editoru trvá neuvěřitelných 24 sekund a překlad s výpisem (listingem) dokonce 33 sekund. Rychlost překladu tedy dosahuje necelých šesti zdrojových řádků za sekundu.
Zdrojový kód programu určený pro překlad assemblerem CA65
Nejprve si ukažme, jak vypadá původní zdrojový kód příkladu, který budeme přepisovat. V něm je zobrazeno pět spritů (pátý hráč je tvořen čtyřmi střelami) a s využitím joysticku je možné horizontálně pohybovat prvním hráčem:
; ---------------------------------------------------------------------
; Ovládání PMG joystickem v horizontální směru, zobrazení pátého hráče.
;
; Tento zdrojový kód byl použit v článku:
;
; Další tipy a triky při práci s čipem GTIA a využití joysticku
; https://www.root.cz/clanky/dalsi-tipy-a-triky-pri-praci-s-cipem-gtia-a-vyuziti-joysticku/
; ---------------------------------------------------------------------
.include "atari.inc"
.CODE
PLAYER_0_OFFSET = 512
PLAYER_1_OFFSET = PLAYER_0_OFFSET + 128
PLAYER_2_OFFSET = PLAYER_1_OFFSET + 128
PLAYER_3_OFFSET = PLAYER_2_OFFSET + 128
MISSILES_OFFSET = 384
.proc main
lda #80 ; horizontální pozice prvního hráče
sta HPOSP0 ; uložit do řídicího registru HPOSP0 na čipu GTIA
lda #95 ; horizontální pozice druhého hráče
sta HPOSP1 ; uložit do řídicího registru HPOSP1 na čipu GTIA
lda #110 ; horizontální pozice třetího hráče
sta HPOSP2 ; uložit do řídicího registru HPOSP2 na čipu GTIA
lda #125 ; horizontální pozice čtvrtého hráče
sta HPOSP3 ; uložit do řídicího registru HPOSP3 na čipu GTIA
lda #146 ; horizontální pozice první střely
sta HPOSM0 ; uložit do řídicího registru HPOSP0 na čipu GTIA
lda #144 ; horizontální pozice druhé střely
sta HPOSM1 ; uložit do řídicího registru HPOSP1 na čipu GTIA
lda #142 ; horizontální pozice třetí střely
sta HPOSM2 ; uložit do řídicího registru HPOSP2 na čipu GTIA
lda #140 ; horizontální pozice čtvrté střely
sta HPOSM3 ; uložit do řídicího registru HPOSP3 na čipu GTIA
lda #HUE_GREEN<<4 + 12 ; barva prvního hráče (odstín+intenzita)
sta PCOLR0 ; uložit do řídicího registru PCOLR0 na čipu GTIA
lda #HUE_YELLOW<<4 + 12 ; barva druhého hráče (odstín+intenzita)
sta PCOLR1 ; uložit do řídicího registru PCOLR1 na čipu GTIA
lda #HUE_MAGENTA<<4 + 12 ; barva třetího hráče (odstín+intenzita)
sta PCOLR2 ; uložit do řídicího registru PCOLR2 na čipu GTIA
lda #HUE_CYAN<<4 + 12 ; barva čtvrtého hráče (odstín+intenzita)
sta PCOLR3 ; uložit do řídicího registru PCOLR3 na čipu GTIA
lda #HUE_YELLOWRED<<4 + 8 ; barva pátého hráče (odstín+intenzita)
sta COLOR3 ; uložit do řídicího registru COLPF3 na čipu GTIA
lda #$ff ; bitová maska všech hráčů
sta GRAFP0 ; uložit do řídicího registru GRAFP0 na čipu GTIA
sta GRAFP1 ; uložit do řídicího registru GRAFP1 na čipu GTIA
sta GRAFP2 ; uložit do řídicího registru GRAFP2 na čipu GTIA
sta GRAFP3 ; uložit do řídicího registru GRAFP3 na čipu GTIA
lda #3 ; bitové pole: povolení hráčů i střel
sta GRACTL ; uložit do řídicího registru GRACTL na čipu GTIA
lda #16 ; priorita hráčů a pozadí -> povolení pátého hráče
sta GPRIOR ; uložit do řídicího registru GPRIOR na čipu GTIA
lda #152 ; paměťová stránka číslo 152
sta PMBASE
addr = 152*256
ldx #8 ; začneme na hodnotě o 1 vyšší
next_line:
lda sprite-1, x ; načíst
sta addr+PLAYER_0_OFFSET+50, x ; uložit byte - první hráč
sta addr+PLAYER_1_OFFSET+50, x ; uložit byte - druhý hráč
sta addr+PLAYER_2_OFFSET+50, x ; uložit byte - třetí hráč
sta addr+PLAYER_3_OFFSET+50, x ; uložit byte - čtvrtý hráč
sta addr+MISSILES_OFFSET+50, x ; uložit byte - střely
dex ; snížit offset + nastavit příznaky
bne next_line ; další byte spritu
lda #46 ; povolení PMG DMA
sta SDMCTL
ldx #80 ; výchozí pozice prvního hráče
loop:
txa ; uložení obsahu X do akumulátoru
jsr _wait_vsync
jsr _wait_vsync
tax ; obnovení obsahu X z akumulátoru
lda STICK0 ; čtení joysticku
cmp #11 ; je nakloněn doleva?
bne not_left
dex ; posun hráče doleva
not_left:
cmp #7 ; je nakloněn doprava?
bne not_right
inx ; posun hráče doprava
not_right:
stx HPOSP0 ; změna pozice prvního hráče
jmp loop
.endproc
.proc _wait_vsync
ldx RTCLOK+2 ; čekání na konec snímku
@wt: cpx RTCLOK+2
beq @wt
rts
.endproc
; data
sprite: .byte 24, 60, 126, 219, 255, 36, 90, 165
end:
.segment "EXEHDR"
.word $ffff ; uvodni sekvence bajtu v souboru XEX
.word main ; zacatek kodoveho segmentu
.word end - 1 ; konec kodoveho segmentu
.segment "AUTOSTRT" ; segment s pocatecni adresou
.word RUNAD ; naplni se pouze adresy RUNAD a RUNAD+1
.word RUNAD+1
.word main ; adresa vstupniho bodu do programu
; finito
Definice adres registrů a dalších konstant použitých v programu
V prvním kroku do syntaxe Assembler/Editoru přepíšeme definici konstant, které představují adresy registrů čipů ANTIC a GTIA, adresy stínových registrů, kódy barev atd. Mnoho těchto konstant je dostupných při použití CA65 (po provedení .include „atari.inc“), ovšem tento luxus v Assembler/Editoru pochopitelně nemáme. Povšimněte si, že se při výpočtu konstant mohou použít i jednoduché výrazy. V názvech konstant nesmí být podtržítka, takže výsledek zrovna neoplývá čitelností:
0100 *=$0600 1000 GTIA=$D000 CTIA/GTIA AREA 1001 ; PLAYERS HORIZONTAL POSITIONS 1002 HPOSP0 = GTIA + $00 1003 HPOSP1 = GTIA + $01 1004 HPOSP2 = GTIA + $02 1005 HPOSP3 = GTIA + $03 1010 ; MISSILES HORIZONTAL POSITIONS 1011 HPOSM0 = GTIA + $04 1012 HPOSM1 = GTIA + $05 1013 HPOSM2 = GTIA + $06 1014 HPOSM3 = GTIA + $07 1020 ; COLOR REGISTERS 1021 PCOLR0 = $02C0 1022 PCOLR1 = $02C1 1023 PCOLR2 = $02C2 1024 PCOLR3 = $02C3 1025 COLOR3 = $02C7 1030 ; PLAYER SHAPES 1031 GRAFP0 = GTIA + $0D 1032 GRAFP1 = GTIA + $0E 1033 GRAFP2 = GTIA + $0F 1034 GRAFP3 = GTIA + $10 1040 ; GTIA CONTROLS 1041 GRACTL = GTIA + $1D 1042 GPRIOR = $026F SHADOW REGISTER 1050 ; ANTIC REGISTERS 1051 ANTIC = $D400 1052 PMBASE = ANTIC + $07 1060 ; OTHER REGISTERS 1061 SDMCTL = $022F SAVE DMCTL 1062 STICK0 = $0278 JOYSTICK 0 1063 RTCLOK = $12 REAL TIME CLOCK 1100 ; PAGE COLORS 1101 HUEGREY = 0 1102 HUEGOLD = 1 1103 HUEGOLDORANGE = 2 1104 HUEREDORANGE = 3 1105 HUEORANGE = 4 1106 HUEMAGENTA = 5 1107 HUEPURPLE = 6 1108 HUEBLUE = 7 1109 HUEBLUE2 = 8 1110 HUECYAN = 9 1111 HUEBLUEGREEN = 10 1112 HUEBLUEGREEN2 = 11 1113 HUEGREEN = 12 1114 HUEYELLOWGREEN = 13 1115 HUEYELLOW = 14 1116 HUEYELLOWRED = 15 1200 ; PMG AREA 1201 PLAYER0OFFSET = 512 1202 PLAYER1OFFSET = PLAYER0OFFSET+128 1203 PLAYER2OFFSET = PLAYER1OFFSET+128 1204 PLAYER3OFFSET = PLAYER2OFFSET+128 LIST 1205 MISSILESOFFSET = 384
Nastavení barev, pozic hráčů, spojení střel do pátého hráče a povolení DMA
Dále přepíšeme původní hlavní proceduru, která nastaví pozice a barvy všech hráčů, nakonfiguruje spojení střel do pátého hráče, povolí DMA, priority hráčů vůči pozadí atd. Vzhledem k tomu, že PMBASE (bitmapy hráčů) nejsou nastaveny, budou sice hráči (po překladu a spuštění) zobrazeni, ovšem prozatím s (pseudo)náhodnými tvary:
Obrázek 25: Sprity se zobrazily na svých místech i se správnými barvami. Musíme pouze nastavit jejich tvar (bitmapy).
Přepis této části opět není nijak složitý:
2000 .PAGE MAIN 2001 LDA #80 2002 STA HPOSP0 2003 LDA #95 2004 STA HPOSP1 2005 LDA #110 2006 STA HPOSP2 2007 LDA #125 2008 STA HPOSP3 2009 LDA #146 2010 STA HPOSM0 2011 LDA #144 2012 STA HPOSM1 2013 LDA #142 2014 STA HPOSM2 2015 LDA #140 2016 STA HPOSM3 2020 ; PLAYER COLORS 2021 LDA #HUEGREEN * 16 + 12 2022 STA PCOLR0 2023 LDA #HUEYELLOW * 16 + 12 2024 STA PCOLR1 2025 LDA #HUEMAGENTA * 16 + 12 2026 STA PCOLR2 2027 LDA #HUECYAN * 16 + 12 2028 STA PCOLR3 2029 LDA #HUEYELLOWRED * 16 + 12 2030 STA COLOR3 2040 ; SHAPES + DMA 2041 LDA #$FF 2042 STA GRAFP0 2043 STA GRAFP1 2044 STA GRAFP2 2045 STA GRAFP3 2046 LDA #3 2047 STA GRACTL 2048 LDA #16 2049 STA GPRIOR 2050 LDA #46 2051 STA SDMCTL
Nastavení bitmap (tvarů) všech pěti hráčů
Konečně se dostáváme k zajímavější části – k programové smyčce sloužící pro nastavení bitmap (tedy tvarů) všech pěti hráčů. Výsledek by měl vypadat takto:
Obrázek 26: Nyní je všech pět spritů zobrazeno zcela korektně – máme napůl vyhráno.
Povšimněte si, jak se mohou zapisovat kratší návěští (na stejný řádek, jako instrukce). Na řádku 5000 je navíc uvedena definice bitmapy, resp. její části:
2060 ; PLAYER BITMAPS 2061 ADDR = 152*256 2062 LDA #152 PAGE 2063 STA PMBASE 2100 LDX #8 2101 NEXT LDA SPRITE-1,X 2102 STA ADDR+PLAYER0OFFSET+50,X 2103 STA ADDR+PLAYER1OFFSET+50,X 2104 STA ADDR+PLAYER2OFFSET+50,X 2105 STA ADDR+PLAYER3OFFSET+50,X 2106 STA ADDR+MISSILESOFFSET+50,X 2107 DEX 2108 BNE NEXT 5000 SPRITE .BYTE 24,60,126,219,255,36,90,165
Hlavní programová smyčka: pohyb spritu joystickem
Konečně se dostáváme k hlavní programové smyčce, ve které se čte náklon joysticku a podle něj se mění horizontální pozice prvního hráče. Navíc je posun synchronizován s hodinami počítače:
Obrázek 27: Pohyb prvního hráče s využitím joysticku (na tomto snímku je to hráč zcela napravo).
Zde používáme jak krátká návěští (LOOP), tak delší návěští zapsaná na samostatném řádku (WAITWSYNC):
3000 .PAGE MAIN LOOP 3001 LDX #80 3002 LOOP TXA 3003 JSR WAITWSYNC 3004 JSR WAITWSYNC 3005 TAX 3006 LDA STICK0 3007 CMP #11 TO THE LEFT? 3008 BNE NOTL 3009 DEX MOVE PLAYER 3010 NOTL CMP #7 TO THE RIGH? 3011 BNE NOTR 3012 INX MOVE PLAYER 3013 NOTR STX HPOSP0 REAL MOVE 3014 JMP LOOP AND AGAIN 4000 .PAGE WSYNC 4001 WAITWSYNC 4002 LDX RTCLOK+2 WAIT FOR CLK 4003 WT CPX RTCLOK+2 SAME VALUE? 4004 BEQ WT 4005 RTS
Výsledná podoba celého programu ve verzi pro Atari Assembler/Editor
Úplný zdrojový kód demonstračního příkladu se sprity, který byl přepsán do formátu plně kompatibilního s Atari Assembler/Editorem, vypadá následovně. Pro jednoduchost jsem vše psal velkými písmeny, aby se zachovaly dobové zvyky:
0100 *=$0600 1000 GTIA=$D000 CTIA/GTIA AREA 1001 ; PLAYERS HORIZONTAL POSITIONS 1002 HPOSP0 = GTIA + $00 1003 HPOSP1 = GTIA + $01 1004 HPOSP2 = GTIA + $02 1005 HPOSP3 = GTIA + $03 1010 ; MISSILES HORIZONTAL POSITIONS 1011 HPOSM0 = GTIA + $04 1012 HPOSM1 = GTIA + $05 1013 HPOSM2 = GTIA + $06 1014 HPOSM3 = GTIA + $07 1020 ; COLOR REGISTERS 1021 PCOLR0 = $02C0 1022 PCOLR1 = $02C1 1023 PCOLR2 = $02C2 1024 PCOLR3 = $02C3 1025 COLOR3 = $02C7 1030 ; PLAYER SHAPES 1031 GRAFP0 = GTIA + $0D 1032 GRAFP1 = GTIA + $0E 1033 GRAFP2 = GTIA + $0F 1034 GRAFP3 = GTIA + $10 1040 ; GTIA CONTROLS 1041 GRACTL = GTIA + $1D 1042 GPRIOR = $026F SHADOW REGISTER 1050 ; ANTIC REGISTERS 1051 ANTIC = $D400 1052 PMBASE = ANTIC + $07 1060 ; OTHER REGISTERS 1061 SDMCTL = $022F SAVE DMCTL 1062 STICK0 = $0278 JOYSTICK 0 1063 RTCLOK = $12 REAL TIME CLOCK 1100 ; PAGE COLORS 1101 HUEGREY = 0 1102 HUEGOLD = 1 1103 HUEGOLDORANGE = 2 1104 HUEREDORANGE = 3 1105 HUEORANGE = 4 1106 HUEMAGENTA = 5 1107 HUEPURPLE = 6 1108 HUEBLUE = 7 1109 HUEBLUE2 = 8 1110 HUECYAN = 9 1111 HUEBLUEGREEN = 10 1112 HUEBLUEGREEN2 = 11 1113 HUEGREEN = 12 1114 HUEYELLOWGREEN = 13 1115 HUEYELLOW = 14 1116 HUEYELLOWRED = 15 1200 ; PMG AREA 1201 PLAYER0OFFSET = 512 1202 PLAYER1OFFSET = PLAYER0OFFSET+128 1203 PLAYER2OFFSET = PLAYER1OFFSET+128 1204 PLAYER3OFFSET = PLAYER2OFFSET+128 LIST 1205 MISSILESOFFSET = 384 2000 .PAGE MAIN 2001 LDA #80 2002 STA HPOSP0 2003 LDA #95 2004 STA HPOSP1 2005 LDA #110 2006 STA HPOSP2 2007 LDA #125 2008 STA HPOSP3 2009 LDA #146 2010 STA HPOSM0 2011 LDA #144 2012 STA HPOSM1 2013 LDA #142 2014 STA HPOSM2 2015 LDA #140 2016 STA HPOSM3 2020 ; PLAYER COLORS 2021 LDA #HUEGREEN * 16 + 12 2022 STA PCOLR0 2023 LDA #HUEYELLOW * 16 + 12 2024 STA PCOLR1 2025 LDA #HUEMAGENTA * 16 + 12 2026 STA PCOLR2 2027 LDA #HUECYAN * 16 + 12 2028 STA PCOLR3 2029 LDA #HUEYELLOWRED * 16 + 12 2030 STA COLOR3 2040 ; SHAPES + DMA 2041 LDA #$FF 2042 STA GRAFP0 2043 STA GRAFP1 2044 STA GRAFP2 2045 STA GRAFP3 2046 LDA #3 2047 STA GRACTL 2048 LDA #16 2049 STA GPRIOR 2050 LDA #46 2051 STA SDMCTL 2060 ; PLAYER BITMAPS 2061 ADDR = 152*256 2062 LDA #152 PAGE 2063 STA PMBASE 2100 LDX #8 2101 NEXT LDA SPRITE-1,X 2102 STA ADDR+PLAYER0OFFSET+50,X 2103 STA ADDR+PLAYER1OFFSET+50,X 2104 STA ADDR+PLAYER2OFFSET+50,X 2105 STA ADDR+PLAYER3OFFSET+50,X 2106 STA ADDR+MISSILESOFFSET+50,X 2107 DEX 2108 BNE NEXT 3000 .PAGE MAIN LOOP 3001 LDX #80 3002 LOOP TXA 3003 JSR WAITWSYNC 3004 JSR WAITWSYNC 3005 TAX 3006 LDA STICK0 3007 CMP #11 TO THE LEFT? 3008 BNE NOTL 3009 DEX MOVE PLAYER 3010 NOTL CMP #7 TO THE RIGH? 3011 BNE NOTR 3012 INX MOVE PLAYER 3013 NOTR STX HPOSP0 REAL MOVE 3014 JMP LOOP AND AGAIN 4000 .PAGE WSYNC 4001 WAITWSYNC 4002 LDX RTCLOK+2 WAIT FOR CLK 4003 WT CPX RTCLOK+2 SAME VALUE? 4004 BEQ WT 4005 RTS 5000 SPRITE .BYTE 24,60,126,219,255,36,90,165
Listing vygenerovaný assemblerem při překladu
Podívejme se pro úplnost ještě na listing, který byl vygenerován následujícím příkazem:
Obrázek 28: Překlad programu, jehož zdrojový kód byl načten z disku. Listing i výsledný spustitelný binární soubor jsou uloženy zpět na disk
0000 0100 *= $0600
D000 1000 GTIA = $D000 CTIA/GTIA AREA
1001 ; PLAYERS HORIZONTAL POSITIONS
D000 1002 HPOSP0 = GTIA + $00
D001 1003 HPOSP1 = GTIA + $01
D002 1004 HPOSP2 = GTIA + $02
D003 1005 HPOSP3 = GTIA + $03
1010 ; MISSILES HORIZONTAL POSITIONS
D004 1011 HPOSM0 = GTIA + $04
D005 1012 HPOSM1 = GTIA + $05
D006 1013 HPOSM2 = GTIA + $06
D007 1014 HPOSM3 = GTIA + $07
1020 ; COLOR REGISTERS
02C0 1021 PCOLR0 = $02C0
02C1 1022 PCOLR1 = $02C1
02C2 1023 PCOLR2 = $02C2
02C3 1024 PCOLR3 = $02C3
02C7 1025 COLOR3 = $02C7
1030 ; PLAYER SHAPES
D00D 1031 GRAFP0 = GTIA + $0D
D00E 1032 GRAFP1 = GTIA + $0E
D00F 1033 GRAFP2 = GTIA + $0F
D010 1034 GRAFP3 = GTIA + $10
1040 ; GTIA CONTROLS
D01D 1041 GRACTL = GTIA + $1D
026F 1042 GPRIOR = $026F SHADOW REGISTER
1050 ; ANTIC REGISTERS
D400 1051 ANTIC = $D400
D407 1052 PMBASE = ANTIC + $07
1060 ; OTHER REGISTERS
022F 1061 SDMCTL = $022F SAVE DMCTL
0278 1062 STICK0 = $0278 JOYSTICK 0
0012 1063 RTCLOK = $12 REAL TIME CLOCK
1100 ; PAGE COLORS
0000 1101 HUEGREY = 0
0001 1102 HUEGOLD = 1
0002 1103 HUEGOLDORANGE = 2
0003 1104 HUEREDORANGE = 3
0004 1105 HUEORANGE = 4
0005 1106 HUEMAGENTA = 5
0006 1107 HUEPURPLE = 6
0007 1108 HUEBLUE = 7
0008 1109 HUEBLUE2 = 8
0009 1110 HUECYAN = 9
000A 1111 HUEBLUEGREEN = 10
000B 1112 HUEBLUEGREEN2 = 11
000C 1113 HUEGREEN = 12
000D 1114 HUEYELLOWGREEN = 13
000E 1115 HUEYELLOW = 14
000F 1116 HUEYELLOWRED = 15
1200 ; PMG AREA
0200 1201 PLAYER0OFFSET = 512
0280 1202 PLAYER1OFFSET = PLAYER0OFFSET+128
0300 1203 PLAYER2OFFSET = PLAYER1OFFSET+128
0380 1204 PLAYER3OFFSET = PLAYER2OFFSET+128 LIST
0180 1205 MISSILESOFFSET = 384
0600 2000 .PAGE MAIN
0600 A950 2001 LDA #80
0602 8D00D0 2002 STA HPOSP0
0605 A95F 2003 LDA #95
0607 8D01D0 2004 STA HPOSP1
060A A96E 2005 LDA #110
060C 8D02D0 2006 STA HPOSP2
060F A97D 2007 LDA #125
0611 8D03D0 2008 STA HPOSP3
0614 A992 2009 LDA #146
0616 8D04D0 2010 STA HPOSM0
0619 A990 2011 LDA #144
061B 8D05D0 2012 STA HPOSM1
061E A98E 2013 LDA #142
0620 8D06D0 2014 STA HPOSM2
0623 A98C 2015 LDA #140
0625 8D07D0 2016 STA HPOSM3
2020 ; PLAYER COLORS
0628 A9CC 2021 LDA #HUEGREEN * 16 + 12
062A 8DC002 2022 STA PCOLR0
062D A9EC 2023 LDA #HUEYELLOW * 16 + 12
062F 8DC102 2024 STA PCOLR1
0632 A95C 2025 LDA #HUEMAGENTA * 16 + 12
0634 8DC202 2026 STA PCOLR2
0637 A99C 2027 LDA #HUECYAN * 16 + 12
0639 8DC302 2028 STA PCOLR3
063C A9FC 2029 LDA #HUEYELLOWRED * 16 + 12
063E 8DC702 2030 STA COLOR3
2040 ; SHAPES + DMA
0641 A9FF 2041 LDA #$FF
0643 8D0DD0 2042 STA GRAFP0
0646 8D0ED0 2043 STA GRAFP1
0649 8D0FD0 2044 STA GRAFP2
064C 8D10D0 2045 STA GRAFP3
064F A903 2046 LDA #3
0651 8D1DD0 2047 STA GRACTL
0654 A910 2048 LDA #16
0656 8D6F02 2049 STA GPRIOR
0659 A92E 2050 LDA #46
065B 8D2F02 2051 STA SDMCTL
2060 ; PLAYER BITMAPS
9800 2061 ADDR = 152*256
065E A998 2062 LDA #152 PAGE
0660 8D07D4 2063 STA PMBASE
0663 A208 2100 LDX #8
0665 BD9D06 2101 NEXT LDA SPRITE-1,X
0668 9D329A 2102 STA ADDR+PLAYER0OFFSET+50,X
066B 9DB29A 2103 STA ADDR+PLAYER1OFFSET+50,X
066E 9D329B 2104 STA ADDR+PLAYER2OFFSET+50,X
0671 9DB29B 2105 STA ADDR+PLAYER3OFFSET+50,X
0674 9DB299 2106 STA ADDR+MISSILESOFFSET+50,X
0677 CA 2107 DEX
0678 D0EB 2108 BNE NEXT
067A 3000 .PAGE MAIN LOOP
067A A250 3001 LDX #80
067C 8A 3002 LOOP TXA
067D 209706 3003 JSR WAITWSYNC
0680 209706 3004 JSR WAITWSYNC
0683 AA 3005 TAX
0684 AD7802 3006 LDA STICK0
0687 C90B 3007 CMP #11 TO THE LEFT?
0689 D001 3008 BNE NOTL
068B CA 3009 DEX MOVE PLAYER
068C C907 3010 NOTL CMP #7 TO THE RIGH?
068E D001 3011 BNE NOTR
0690 E8 3012 INX MOVE PLAYER
0691 8E00D0 3013 NOTR STX HPOSP0 REAL MOVE
0694 4C7C06 3014 JMP LOOP AND AGAIN
0697 4000 .PAGE WSYNC
4001 WAITWSYNC
0697 A614 4002 LDX RTCLOK+2 WAIT FOR CLK
0699 E414 4003 WT CPX RTCLOK+2 SAME VALUE?
069B F0FC 4004 BEQ WT
069D 60 4005 RTS
069E 18 5000 SPRITE .BYTE 24,60,126,219,255,36,90,165
069F 3C
06A0 7E
06A1 DB
06A2 FF
06A3 24
06A4 5A
06A5 A5
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 - Customizing the Atari Operating System Device Handlers: Part 1
https://www.atarimagazines.com/v8n2/customhandlers.html - Customizing the Atari Operating System Device Handlers: Part II
https://www.atarimagazines.com/v8n3/OperatingSystemHandlers.html - Spectrum tape interface
https://sinclair.wiki.zxnet.co.uk/wiki/Spectrum_tape_interface - Turbo 2000
http://wiki.oldcomp.cz/index.php?title=Turbo_2000 - Původní manuál k systému Turbo 2000
http://wiki.oldcomp.cz/images/6/65/Zak_praha_1987_p2_turbo2000.pdf - Mark and space
https://en.wikipedia.org/wiki/Mark_and_space - Obdélníkový průběh
https://cs.wikipedia.org/wiki/Obd%C3%A9ln%C3%ADkov%C3%BD_pr%C5%AFb%C4%9Bh - All you ever wanted to know about: Atari Cartridges
https://atariwiki.org/wiki/Wiki.jsp?page=Cartridges
