Navážeme na článek o vývoji pro osmibitové mikropočítače Atari a ukážeme si použití slavného assembleru MAC/65, což po dlouhou dobu byl nejlepší assembler pro mikroprocesory MOS 6502.
Pokud se mluví o MAC/65, je dobré mít na paměti, že s se v praxi jedná jak o editor zdrojového kódu, tak i o assembler, ale současně i o debugger. Způsob ovládání MAC/65 je do značné míry odvozen od minule použitého Atari Assembler Editoru, takže mnohé příkazy budou stejné či alespoň velmi podobné.
Ve skutečnosti je však MAC/65 prakticky po všech stránkách lepší (tedy až na poněkud vyšší cenu, zejména v případě varianty dostupné na cartridge). Za vývojem MAC/65 stála společnost Optimized Systems Software (OSS), se kterou se později setkáme ještě jednou v souvislosti s programovacím jazykem nazvaným Action! (i s oním vykřičníkem na konci).
Obrázek 1: První verze slavného assembleru MAC/65, která je již dostupná na cartridge (ta měla kapacitu 16kB).
Autor: tisnik, podle licence: Rights Managed
Společnost OSS: zaměření na vývoj vývojových nástrojů namísto herNa chvíli se zastavme u autorů assembleru MAC/65, kterým byla společnost Optimized Systems Software známá pod zkratkou (OSS). Historie této společnosti se začala psát vlastně již se samotným vznikem osmibitových domácích počítačů Atari a souvisí s vývojem (resp. hledáním dodavatele) Atari BASICu. Původně se uvažovalo, že BASIC pro osmibitové mikropočítače Atari dodá Micro-Soft (ano, to je napsáno správně). Ovšem ukázalo se, že Micro-Soft nedokáže svůj Atari Microsoft BASIC „nacpat“ do požadované kapacity ROM. Firma Atari totiž pro BASIC počítala s ROM modulem o kapacitě osmi kilobajtů (ovšem Atari Microsoft BASIC byl nakonec vydán, a to dokonce ve dvou verzích, jak jsme si již řekli ve článku věnovaném historii tohoto programovacího jazyka). Resp. abych byl přesnější – Micro-Soft byla schopna dodat BASIC, který se vejde do osmi kilobajtů, ovšem ten by neobsahoval příkazy pro ovládání grafiky a zvuků. Ty ovšem společnost Atari vyžadovala, aby uživatelé mohli snadno využívat možností nabízených čipy ANTIC a GTIA, které byly (právem) považovány za největší zbraň osmibitových mikropočítačů Atari.
Poznámka: všichni se ostatně mohou sami přesvědčit na příkladu konkurenčních počítačů Commodore C64, jak Microsoft BASIC vypadá a co nabízí resp. naopak nenabízí. Dovolím si s odstupem času tvrdit, že BASIC na C64 byl vlastně nejhorší standardní součástí tohoto po hardwarové stránce dobře vybaveného počítače.
Vraťme se však k OSS. Za vznikem této společnosti stáli Bill Wilkinson, Mike Peters, Paul Laughton a Kathleen O'Brien, přičemž třetí jmenovaný vydal Atari BASIC a jeho žena Kathleen pracovala mj. i na FP rutinách operačního systému Atari (k nim se ještě v tomto seriálu vrátíme). Původní Atari BASIC a taktéž první verze DOSu byla odkoupena od společnosti Shepardson Microsystems, která ukončila svoji existenci právě v roce 1981 a kde původně zakladatelé OSS pracovali. V dalších letech se OSS věnovala jak rozšiřování možností původních produktů (řada DOS, řada BASICů), tak i dalším projektům, mj. i jazyku Action! a právě assembleru MAC/65.
Příkladem produktu vydaného společností OSS je OS/A+, tedy dosový systém založený na systému menu. Později vznikl DOS XL, který podporoval diskety s dvojnásobnou hustotou a kromě menu se ovládal i příkazovou řádkou nazývanou CP neboli command processor. OSS vyvinula i takzvanou supercartridge s kapacitou 16kB (a na této cartridge byla dodávána mj. i druhá verze assembleru MAC/65).
Jen pro zajímavost si uveďme příklad, jak vypadalo menu z DOSu XL:
C - Copy Files P - Protect Files D - Duplicate Disk Q - Quit to DOS XL E - Erase Files R - Rename File F - Files on Disk S - Save Binary G - Go to Address T - To Cartridge I - Initialize Disk U - Unprotect Files L - Load Binary X - Xtended Command
Na příkazovém řádku byly v tomto DOSu podporovány interní příkazy, mezi něž patří například D1: (přepnutí disků), DIR (asi není nutné vysvětlovat), END, ERA atd. A většinou byly k dispozici i příkazy externí: COPY, DUPDSK, VERIFY atd.
Z portfolia dobových produktů nabízených společností OSS stojí za zmínku především:
Poznámka: na tomto místě je vhodné doplnit, že v případě programovacího jazyka C se však nejednalo o plnohodnotné céčko odpovídající standardu. Jak C/65, tak i pozdější Tiny C (interpret) obsahovaly jen podmnožinu vlastností klasického céčka. Navíc C/65 při překladu generoval kód v assembleru, který se musel v další fázi překládat právě pomocí MAC/65. To je sice z pohledu architektury dobrá myšlenka (ostatně mnohokrát implementovaná dalšími překladači céčka), ovšem „malé“ počítače Atari nebyly na tento koncept dostatečně výkonné.
Obrázek 2: Dobová reklama na některé vývojové nástroje dodávané společností OSS.
Autor: OSS corp., podle licence: Rights Managed
MAC/65: jeden z nejúspěšnějších projektů společnosti OSSPrvní verze assembleru MAC/65, za jejímž vývojem stojí Stephen D. Lawrow, začala být prodávána již v roce 1982, tedy zhruba o rok později, než Atari Assembler/Editor. Typické je, že tato verze byla dostupná na disketě, protože se předpokládalo, že tento assembler budou používat profesionálové vybavení disketovou jednotkou, tj. (velmi drahým) záznamovým zařízením. V roce 1984 vyšla druhá verze MAC/65, která se stala mnohem známější. Tato verze byla dodávána na specializované cartridgi s kapacitou 16kB, což je dvojnásobná kapacita, než jakou počítače Atari oficiálně podporují (konektor pro zapojení cartridge totiž měl vyvedených 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í. Mimochodem: 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 – to je však téma na samostatný článek, který se teprve připravuje.
Obrázek 3: Druhá verze MAC/65 dodávaná na cartridge. V praktické části dnešního článku použijeme právě tuto verzi.
Autor: tisnik, podle licence: Rights Managed
Poznámka: mimochodem je zajímavé, že se (podle dobových pramenů) prodalo více kopií assembleru MAC/65, než jazyka Action!. Ještě lépe se však prodával jejich Basic XL (to je ovšem jiný interpret, než slavný Turbo Basic XL).
Interaktivní prostředí assembleru MAC/65Assembler MAC/65 se ovládal podobným způsobem, jako minule popsaný Atari Assembler/Editor. To znamená, že se příkazy nevybíraly z menu, ale zapisovaly se na obrazovku. MAC/65 byl vybaven i prakticky stejným editorem zdrojového kódu, což ovšem není příliš překvapivé, protože se využívaly systémové rutiny používané Atari BASICem. A i zde se rozlišovalo mezi režimem Edit a Debug; ve skutečnosti byl režim Debug implementován relativně samostatným nástrojem nazvaným DDT, k jehož popisu se dnes ještě vrátíme.
Poznámka: i systém nápovědy zůstal zachován – žádný totiž neexistuje…
Obrázek 4: Obsah diskety obsahující další pomocné nástroje a ukázky programů pro MAC/65.
Autor: tisnik, podle licence: Rights Managed
Dostupné byly následující příkazy:
| Příkaz | Stručný popis |
|---|---|
| ASM | překlad programu |
| BLOAD | načtení (binárního) bloku paměti |
| BSAVE | uložení (binárního) bloku paměti |
| BYE | návrat do Self Testu |
| C | editace obsahu paměti |
| D | zobrazení obsahu paměti |
| DDT | přepnutí do debuggeru |
| DEL | smazání vybraných programových řádků |
| DOS | návrat do DOSu |
| ENTER | načtení zdrojového kódu (text) |
| FIND | hledání řetězce v paměti |
| LIST | výpis/uložení zdrojového kódu |
| LOAD | načtení tokenizovaného zdrojového kódu |
| LOMEM | určení oblasti paměti, od které bude uložený (tokenizovaný) zdrojový kód |
| NEW | vymazání programu |
| NUM | automatický zápis čísel řádků v editoru |
| jako LIST, ovšem bez čísel řádků | |
| REN | přečíslování řádků |
| REP | náhrada řetězce za jiný řetězec |
| SAVE | uložení zdrojového textu v tokenizované podobě |
| SIZE | zobrazení adres čtyř paměťových oblastí |
| TEXT | přepnutí do režimu, ve kterém se neprovádí průběžná kontrola syntaxe |
Obrázek 5: Ukázkový program je možné přímo v DOSu zkopírovat na pevný disk (pochopitelně při použití emulátoru).
Autor: tisnik, podle licence: Rights Managed
Způsob interní reprezentace zdrojových kódů programůAssembler MAC/65 se od ostatních assemblerů odlišuje tím, že nepracuje se zdrojovými kódy reprezentovanými v čistě textové podobě. Namísto toho je zde využita technologie používaná například většinou (?) interpretrů programovacího jazyka BASIC – v operační paměti jsou uloženy tokeny jednotlivých příkazů (zde spíše instrukcí). Čísla řádků jsou uložena jako šestnáctibitové hodnoty, instrukce jsou uloženy v jediném bajtu, návěští a symboly pak jako indexy do (dynamické) tabulky symbolů.
Uvádí se, že se tímto způsobem může ušetřit 60% až 80% potřebné kapacity paměti (ovšem toto tvrzení, které mimochodem pochází přímo od autorů MAC/65, si ověříme). Ovšem tokenizací se ztrácí informace o přesném naformátování zdrojového kódu, což znamená, že ztratíme například původní odsazení apod. Na druhou stranu je to ovšem poměrně dobrá vlastnost, protože zaručuje, že všechny zdrojové kódy budou mít naprosto stejný formát (to se týká jak odsazení, tak i například mezer v operandech instrukcí atd.).
Poznámka: v průběhu tokenizace se provádí i kontrola syntaxe, což je výhodné. Nemusí se totiž čekat na chyby vypisované příkazem ASM.
Obrázek 6: V MAC/65 se není nutné příliš starat o formátování zdrojového kódu, protože dochází k jeho naformátování při zpětném převodu na text.
Autor: tisnik, podle licence: Rights Managed
Ve druhé polovině dnešního článku pracujeme s programem, který po svém překladu a spuštění zobrazí sprity a umožňuje jejich pohyb po obrazovce. Tento příklad je relativně dlouhý, takže se pokusíme zjistit, jak se skutečně liší velikost souboru s původním zdrojovým textem od tokenizované varianty:
| Způsob uložení | Velikost souboru | Relativní velikost |
|---|---|---|
| zdrojový kód | 3262 | 100% |
| tokenizovaný kód | 2152 | 66% |
A jak jsem získal soubor s tokeny? Je to snadné:
ENTER #H:SPRITES SAVE #H:TOKENS
Poznámka: ušetření paměti není tak velké, jak tvrdí oficiální materiály, ovšem to může být způsobeno i tím, že náš program obsahuje mnoho definicí symbolů s dlouhými jmény a málo reálného kódu. Jména symbolů jsou totiž zachována a minimálně zpočátku „natahují“ tokenizovaný soubor.
Překlad programu s uložením výsledků na zvolené zařízeníPokusme se nyní přeložit program, jehož zdrojový kód byl ukázán na screenshotu v předchozí kapitole. Kód je napsán tak, jako bych použili Atari Assembler/Editor:
1000 *=$6000 1001 LDA #42 1002 STA 712 1003 BRK
Pro překlad se použije příkaz ASM. Průběh překladu je ukázán na dalším screenshotu:
Obrázek 7: Pokus o překlad sice dopadne (zdánlivě) v pořádku, ovšem ve skutečnosti nebyla korektně nastavena počáteční adresa kvůli chybějící mezeře.
Autor: tisnik, podle licence: Rights Managed
Z výpisu je zřejmé, že v programu je chyba, protože je překlad proveden od adresy $0000 a nikoli od $0600. Zde máme poněkud štěstí, protože se výsledný strojový kód do paměti nezapsal, protože jinak by výsledkem byl pravděpodobně pád systému (práce s nultou stránkou má svá pravidla).
Když už se bavíme o obsazení operační paměti, je vhodné použít příkaz SIZE, který zobrazí trojici adres: tzv. LOMEM, dále nejvyšší použitou adresu a nejvyšší volnou adresu. Ideální je tedy programy ukládat do adresního prostoru mezi druhou a třetí adresou:
Obrázek 8: Získání informací o obsazených a volných oblastech paměti.
Autor: tisnik, podle licence: Rights Managed
Z výpisu příkazu SIZE je zřejmé, že programy můžeme ukládat například od adresy $9000. Ta je dostatečně vysoko, ovšem ještě nezasahuje do display listu, video RAM a ROM. V programu navíc opravíme záludnou chybu – specifikace *= musí být posunuta doprava minimálně o dvě mezery (to v Atari Assembler/Editoru vyžadováno nebylo):
Obrázek 9: Korektně zapsaný program i s uvedením počáteční adresy.
Autor: tisnik, podle licence: Rights Managed
Nyní překlad proběhne bez chyby a dokonce se použijí korektní adresy, jak je to patrné z výpisu:
Obrázek 10: Nyní již překlad dopadne podle očekávání.
Autor: tisnik, podle licence: Rights Managed
Ve skutečnosti se ovšem (prozatím) neprovede zápis do paměti – o to musíme assembler explicitně požádat. Nicméně se můžeme pokusit o uložení výsledného binárního souboru na disk. Příkazu ASM se předá jen třetí parametr s názvem výsledného spustitelného souboru:
ASM ,,#H:OUTDDT: vestavěný debugger
Assembler MAC/65 je doplněn nástrojem nazvaným DDT. Jak již název tohoto nástroje naznačuje, slouží k odstraňování chyb (bugů) z vyvíjených programů. DDT kombinuje možnosti monitoru a debuggeru. V DDT je možné prohlížet obsah vybraného bloku operační paměti, modifikovat obsah operační paměti, vyhledat bajt s určitou hodnotou (hledání místa pro nastavení většího množství životů ve hrách apod.), ale zejména spouštět laděný program popř. ho krokovat. Po překladu programu se do nástroje DDT přepneme jednoduše – zadáním příkazu DDT. Prostředí tohoto programu vypadá následovně:
Obrázek 11: Zajímavé - na adrese $9000 se nachází pouze samé nuly.
Autor: tisnik, podle licence: Rights Managed
Obrazovka DDT (mimochodem – se zkráceným display listem) je rozdělena do čtyř oblastí. V horní oblasti se zobrazuje výsek operační paměti a typicky zde můžeme vidět výsledek zpětného překladu (disassembler) dané oblasti. Pod touto oblastí se nachází dva řádky se zobrazením adres breakpointů a taktéž s obsahem příznakového registru. Třetí oblast obsahuje výpis všech ostatních registrů mikroprocesoru: čítače instrukcí PC, akumulátoru A, index registrů X a Y a taktéž ukazatele na vrchol zásobníku S. Vedle této oblasti je „schován“ příkazový řádek.
Poznámka: co ovšem zobrazené není je způsob ovládání tohoto programu:
| Příkaz | Stručný popis |
|---|---|
| B | nastavení nebo vymazání breakpointu |
| D | zápis bajtu/bajtů do paměti |
| E | výpis paměti (disassembler) |
| G | skok na zadanou adresu |
| I | spuštění programu se zobrazením průběhu (nutné vidět!) |
| M | přesun bloku paměti |
| Q | ukončení DDT a návrat do MAC/65 |
| R | modifikace vybraného registru |
| S | vyhledávání v paměti |
| START | odpovídá příkazu G |
| SELECT | přepnutí na obrazovku programu |
| OPTION | jeden krok při ladění/krokování |
Poznámka: na první pohled sice může DDT vypadat primitivně, ale jedná se o velmi dobře ovladatelný debugger. Jeden z důvodů, proč se šetří místem na obrazovce, je možnost přepnutí na obrazovku aplikace klávesou SELECT. Asi si dokážete představit, že to znamená mj. i nastavení jiného display listu, nastavení DMA, povolení/zákaz spritů atd., tedy nikoli zcela triviální operace.
Překlad programu s uložením výsledků do zvolené oblasti operační pamětiDo příkazového řádku programu DDT se nyní pokusíme zapsat příkaz E 9000, což znamená prohlížení paměti (examine) od zvolené hexadecimální adresy, tedy v tomto případě od adresy $9000. Výsledek jsme již viděli a nebude příliš uspokojivý, protože na této adrese jsou uloženy samé nuly (to je – nikoli náhodou – kód instrukce BRK, což je velmi užitečné, lepší než například NOP):
Obrázek 11: Zajímavé - na adrese $9000 se nachází pouze samé nuly.
Autor: tisnik, podle licence: Rights Managed
Assembler MAC/65 totiž sice provádí překlady, ale jen v případě, kdy se výsledky (binární soubor) ukládají na nějaké záznamové zařízení. Pokud se překlad provádí bez uvedení zařízení/cesty k výslednému souboru, provede se překlad bez zápisu. Ovšem přepínačem .OPT OBJ můžeme MAC/65 „donutit“ k zápisu výsledku do RAM, konkrétně na adresu určenou pomocí *=:
Obrázek 12: Vynucení překladu se zápisem výsledného strojového kódu do operační paměti.
Autor: tisnik, podle licence: Rights Managed
Samotný překlad sice proběhne (zdánlivě) stejně, jako tomu bylo v předchozí kapitole, ovšem výsledný strojový kód se skutečně uloží od zvolené adresy $9000:
Obrázek 13: Překlad je proveden s uložením od adresy $9000.
Autor: tisnik, podle licence: Rights Managed
Poznámka: tímto způsobem se MAC/65 brání vlastnímu přepsaní v případě, že se překládají programy využívající stejný adresní prostor, jako MAC/65 nebo DOS.
Spuštění programu v DDTVzhledem k tomu, že strojový kód našeho programu byl skutečně uložen od adresy $9000, můžeme se pokusit o jeho spuštění v DDT. Napíšeme tedy příkaz:
DDT
V nástroji DDT použijeme příkaz:
E 9000
Nyní by obrazovka měla vypadat přesně takto:
Obrázek 14: Nyní je program skutečně uložen od adresy $9000 a je tak viditelný i v DDT.
Autor: tisnik, podle licence: Rights Managed
Nyní je již možné program spustit příkazem:
G 9000
V horní polovině obrazovky dojde k posunu na řádek s instrukcí BRK, ovšem zdánlivě se nic dalšího nestalo – jak to, že nevidíme barevný okraj obrazovky? Přesně to totiž tato aplikace provádí. Je tomu tak z toho důvodu, že si DDT „hlídá“ svoji obrazovku, aby ji nepoškodil například kód hry provádějící překreslení atd. Musíme stisknout klávesu SELECT, která vrátí zobrazení na obrazovku laděné aplikace. A tam je již vše v pořádku:
Obrázek 15: Výsledek činnosti programu - byl změněn okraj obrazovky.
Autor: tisnik, podle licence: Rights Managed
Poznámka: DDT je tedy poměrně sofistikovaným programem určeným i pro ladění her a dalších grafických programů. V porovnání s debug v DOSu (který je tak v tomto ohledu jasně vyhrává… a to je debug.exe cca 10× větší.
Krokování programu v DDTPři ladění aplikací a zejména aplikací psaných v assembleru, se mnohdy nevyhneme nutnosti krokování programu, tj. provádění jednotlivých instrukcí po stisku určité klávesy. Debugger by v takovém případě měl zobrazit aktuální obsah všech registrů a měl by umožnit i další operace, zejména prohlížení obsahu paměti, vyhledávání v paměti, modifikaci paměti atd. (a když mluvíme o paměti – sem na osmibitových Atari spadají i řídicí registry ANTIC a GTIA, které se „tváří“ jako paměťové oblasti). Krokování je podporováno i aplikací DDT. K tomuto účelu se používá klávesa SELECT. Podívejme se tedy, jak krokování vypadá v praxi:
Obrázek 16: Krokování v DDT.
Autor: tisnik, podle licence: Rights Managed
Zajímavé je, že při krokování nemá DDT prostor na plnou obnovu své obrazovky a proto můžeme vidět vliv zápisu do paměťové oblasti 712 (což je stínový registr čipu GTIA):
Obrázek 17: Krokování v DDT.
Autor: tisnik, podle licence: Rights Managed
Poznámka: mikroprocesor MOS 6502 nemá přímou podporu pro nastavení breakpointů ani pro krokování a proto je nutné používat různé triky. Ty většinou spočívají v tom, že se další instrukce (na chvíli) přepíše instrukcí BRK. Mikroprocesor v takovém případě provede skok na obsluhu BRK, kterou plně ovládá debugger, který zobrazí obsah pracovních registrů a obnoví původní instrukci (jejíž kód si uložil do své oblasti paměti).
Vytvoření spustitelného programuAssembler MAC/65 dokáže vyprodukovat dva typy souborů se strojovým kódem:
Nás bude zajímat především způsob vytvoření spustitelných souborů. Postup je v tomto případě jednoduchý, protože takový soubor je vytvořen přímo příkazem ASM. V emulátoru tedy můžeme vyzkoušet:
ENTER #H:PRG2 LIST ASM ,,#H:PRG2.OBJ
Výsledkem bude soubor PRG2.OBJ, jehož obsah je následující:
$ od -tx1 PRG2.OBJ 0000000 ff ff 00 90 05 90 a9 2a 8d c8 02 00 0000014
Dekódování uložených informací jsme si již ukázali minule, takže jen v krátkosti:
| Offset | Hodnoty bajtů | Stručný popis |
|---|---|---|
| 00–01 | ff ff | označení segmentu EXEHDR, jedná se tedy o spustitelný soubor |
| 02–03 | 00 90 | startovní adresa je rovna $9000 (odpovídá adrese nastavené přes *=) |
| 04–05 | 05 90 | koncová adresa je rovna $9005 |
| 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 |
Znak „M“ v názvu MAC/65 znamená macro, protože makra jsou důležitou a nedílnou součástí jak tohoto assembleru, tak i mnoha dalších (moderních) assemblerů. Jsou však makra skutečně tak důležitá? Mnoho vysokoúrovňových mainstreamových jazyků (vlastně většina mainstreamových jazyků) přece makra vůbec nepodporuje. Ovšem zde je háček – jedná se totiž o vysokoúrovňové jazyky s možností definice komplikovaných datových struktur, s nativní podporou funkcí (kterou dokonce po desetiletích čekání nakonec nabízí i Java) a taktéž s možností využívání strukturovaných řídicích příkazů (podmínky, smyčky, rozeskoky).
Ovšem assemblery patří mezi nízkoúrovňové jazyky, což mj. znamená i to, že překážkou či určitou komplikací při vývoji mohl být i samotný assembler. A právě zde se nabízí minimálně dvě techniky umožňující tvorbu rozsáhlejších aplikací. První technikou je tvorba procedur (nebo, chcete-li, funkcí), druhou technikou pak podpora maker. A právě s makry, konkrétně s makry realizovanými v assembleru MAC/65, se ve stručnosti seznámíme v dalším textu.
Nástroje typu „assembler“ je možné podle principu jejich práce rozdělit do několika kategorií. Do první kategorie spadají assemblery interaktivní, které uživateli nabízejí poměrně komfortní vývojové prostředí, v němž je v případě potřeby možné zapisovat jednotlivé instrukce, spouštět programy, krokovat je, vypisovat obsahy pracovních registrů mikroprocesoru, prohlížet si obsah operační paměti, zásobníku atd. Velkou výhodou byla nezávislost těchto assemblerů na rychlém externím paměťovém médiu, proto jsme se s nimi mohli setkat například na osmibitových domácích mikropočítačích či dnes na různých zařízeních typu IoT (i když zde úlohu pouhého interaktivního assembleru mnohdy přebírá interaktivní debugger).
Druhý typ assemblerů je široce používán dodnes – jedná se vlastně o běžné překladače, kterým se na vstupu předloží zdrojový kód a po překladu se výsledný nativní kód taktéž uloží na paměťové médium (odkud ho lze přímo spustit, což se dělo například v operačním systému DOS, popř. ho ještě před spuštěním slinkovat, což je případ Linuxu a dalších moderních operačních systémů).
Assemblery spadající do druhé kategorie jsou mnohdy vybaveny více či méně sofistikovaným systémem maker; odtud ostatně pochází i jejich často používané označení macroassembler. Makra, která se většinou aplikují na zdrojový kód v první fázi překladu, je možné použít pro různé činnosti, ať již se jedná o zjednodušení zápisu kódu či o jeho zkrácení a zpřehlednění. Existují například sady poměrně složitých maker, která do assembleru přidávají některé konstrukce známé z vyšších programovacích jazyků – rozvětvení, programové smyčky, deklaraci objektů atd.
Poznámka: všechny moderní assemblery používané například na PC (Linux i Windows) podporují práci s makry, a to mnohdy na velmi dobré úrovni (kontrola parametrů maker, srozumitelná chybová hlášení, podpora pro lokální návěští atd.).
Definice jednoduchého makraMakro bez parametrů je definováno mezi řádky, které začínají specifikací .MACRO a končí řádkem obsahujícím pouze slovo .ENDM. Příkladem může být makro, které na zásobník uloží obsah obou index registrů X i Y (přitom se ovšem přepíše akumulátor – ostatně si makro můžete sami vylepšit, aby k tomu nedocházelo):
10 .MACRO PUSHXY 20 TXA 30 PHA 40 TYA 50 PHA 60 .ENDM
Expanze makra proběhne na tom řádku, na kterém je jméno makra zmíněno a popř. jsou mu předány parametry:
0202 PUSHXY
Můžeme si to otestovat na uceleném příkladu, který po spuštění naplní oba index registry X a Y hodnotami 1 a 2 a následně jsou tyto hodnoty (makrem) uloženy na zásobník:
10 .MACRO PUSHXY 20 TXA 30 PHA 40 TYA 50 PHA 60 .ENDM 0100 .OPT OBJ 0102 *= $9000 0200 LDX #1 0201 LDY #2 0202 PUSHXY 0203 BRK
Poznámka: obsah zásobníku lze zkontrolovat přímo v DDT – je na první stránce paměti.
Expanze makra při překladuPříkaz ASM provede překlad, během něhož pochopitelně dojde i k expanzi maker. To je vidět ve výpisu (listingu) vygenerovaného během překladu. Expandované řádky mají ve druhém sloupci znak M:
10 .MACRO PUSHXY
20 TXA
30 PHA
40 TYA
50 PHA
60 .ENDM
0000 0100 .OPT OBJ
0000 0102 *= $9000
9000 A201 0200 LDX #1
9002 A002 0201 LDY #2
0202 PUSHXY
9004 8A M TXA
9005 48 M PHA
9006 98 M TYA
9007 48 M PHA
M .ENDM
9008 00 0203 BRK
ASSEMBLY ERRORS: 0 33988 BYTES FREE
PAGE 2
SYMBOLS
%173A PUSHXYZdrojový kód programu pro zobrazení spritů i pro posun spritů na obrazovce upravený pro MAC/65Podobně, jako tomu bylo v článku o Atari Assembler/Editoru, si i dnes vyzkoušíme, jakým způsobem bude proveden překlad poněkud delšího programu. Opět se bude 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.
Ve skutečnosti jsem ovšem příklad znovu nepřepisoval, ale použil jsem zdrojový kód upravený pro Atari Assembler/Editor. Ten je možné do MAC/65 načíst příkazem ENTER #zařízení:jméno_souboru, tedy například ENTER #H:SPRITES.ASM (v emulátoru). Po načtení a tokenizaci (obě operace mimochodem proběhly bez chyby) bylo nutné upravit pouze první řádek tak, aby mezi číslem řádku a znakem hvězdičky byly dvě mezery. Zbytek zdrojového kódu je plně kompatibilní s MAC/65:
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,165Překlad programu, jeho spuštění v DDT a otestování funkcionality
Program přeložíme běžným způsobem:
ASM
Obrázek 18: Zdrojový kód, který se bude překládat a spouštět.
Autor: tisnik, podle licence: Rights Managed
Následně přejdeme do DDT a příkazem:
G 0600
program spustíme.
Obrázek 19: Prozkoumání obsahu paměti, na které leží začátek našeho programu.
Autor: tisnik, podle licence: Rights Managed
Díky tomu, že se hlavní smyčka programu neustále opakuje, nemá DDT možnost obnovit svoji obrazovku. Program tedy poběží na s původní obrazovkou (standardní display list atd.):
Obrázek 20: Po spuštění příkazem G by měla obrazovka vypadat následovně (textový obsah se může lišit, ovšem sprity by měly být viditelné).
Autor: tisnik, podle licence: Rights Managed
A pochopitelně bude možné prvním hráčem horizontálně posunovat s využitím joysticku:
Obrázek 21: Posun prvního hráče do pravé části obrazovky s využitím joysticku.
Autor: tisnik, podle licence: Rights Managed
Ukončení programu zajistí (bezpečný!) RESET.
Obrázek 22: Načtení zdrojového kódu a jeho překlad s výpisem listingu do jiného souboru.
Autor: tisnik, podle licence: Rights Managed
Obrázek 23: Uložení zdrojového kódu v tokenizovaném formátu.
Autor: tisnik, podle licence: Rights Managed
Kontrolní výpis (listing) vygenerovaný assemblerem MAC/65Pro úplnost se ještě podívejme na kontrolní výpis (listing), který byl vygenerován assemblerem MAC/65 v průběhu překladu programu. Formát listingu se liší od výsledku vyprodukovaného Atari Assembler/Editorem. Navíc byl na konec výpisu přidán seznam všech symbolů, které byly ve zdrojovém textu definovány a byla jim přiřazena nějaká (vypočtená) hodnota:
PAGE 1
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
2000 .PAGE MAIN
PAGE 2
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
3000 .PAGE MAIN LOOP
PAGE 3
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
4000 .PAGE WSYNC
PAGE 4
0697 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 183C7EDB 5000 SPRITE .BYTE 24,60,126,219,255,36,90,165
06A2 FF245AA5
ASSEMBLY ERRORS: 0 31216 BYTES FREE
PAGE 5
SYMBOLS
=9800 ADDR =D400 ANTIC
=02C7 COLOR3
=026F GPRIOR =D01D GRACTL =D00D GRAFP0 =D00E GRAFP1
=D00F GRAFP2 =D010 GRAFP3 =D000 GTIA
=D004 HPOSM0 =D005 HPOSM1 =D006 HPOSM2 =D007 HPOSM3
=D000 HPOSP0 =D001 HPOSP1 =D002 HPOSP2 =D003 HPOSP3
=0007 HUEBLUE =0008 HUEBLUE2 =000A HUEBLUEGREEN =000B HUEBLUEGREEN2
=0009 HUECYAN =0001 HUEGOLD =0002 HUEGOLDORANGE =000C HUEGREEN
=0000 HUEGREY =0005 HUEMAGENTA =0004 HUEORANGE =0006 HUEPURPLE
=0003 HUEREDORANGE =000E HUEYELLOW =000D HUEYELLOWGREEN
=000F HUEYELLOWRED
067C LOOP
=0180 MISSILESOFFSET
0665 NEXT 068C NOTL 0691 NOTR
=02C0 PCOLR0 =02C1 PCOLR1 =02C2 PCOLR2 =02C3 PCOLR3
=0200 PLAYER0OFFSET =0280 PLAYER1OFFSET =0300 PLAYER2OFFSET =0380 PLAYER3OFFSET
=D407 PMBASE
=0012 RTCLOK
=022F SDMCTL 069E SPRITE =0278 STICK0
0697 WAITWSYNC 0699 WTPorovnání rychlosti překladu programu v Atari Assembler/Editoru a v MAC/65V úvodní části dnešního článku jsme si řekli, že jednou z velkých předností assembleru MAC/65 je větší rychlost překladu, především v porovnání s původním Atari Assembler/Editorem, jenž byl nechvalně známý svou pomalostí. Taková tvrzení se opakují v mnoha dobových materiálech, takže nám nezbývá, než je ověřit. Výše uvedený program určený pro ovládání spritu joystickem byl nejprve přeložen v Atari Assembler/Editoru, a to s provedením listingu na obrazovku i se zákazem této operace.
Následně byl prakticky naprosto stejný program (liší se jen řádkem s nastavením počáteční adresy) přeložen v assembleru MAC/65, a to opět nejdříve s povolením listingu a podruhé s jeho zákazem (na začátek zdrojového kódu byl přidán řádek .OPT NOLISTING). Změřené časy jsou uvedeny v tabulce pod tímto odstavcem. Z tabulky je naprosto jasné, že MAC/65 je skutečně mnohem rychlejší (zde více než 24×, ale toto je ovlivněno chybou měření času, spíše je rychlost překladu ještě vyšší):
| Assembler | Listing | Bez listingu |
|---|---|---|
| Atari Assembler/Editor | 33s | 24s |
| MAC/65 | 14s | <1s |
Poznámka: listing na obrazovku je skutečně pomalý a většinou ani není nutné ho (neustále) opakovat. Jednou z oblastí, kde se ovšem skutečně hodí ho používat, je náhled na způsob expanze maker.
Repositář s demonstračními příkladyVšechny demonstrační příklady, s nimiž jsme se v předchozích článcích i v článku dnešním seznámili a které jsou určeny pro překlad s využitím assembleru ca65, jsou dostupné, jak je zvykem, na GitHubu. V tabulce níže jsou uvedeny odkazy na jednotlivé zdrojové kódy příkladů psané v assembleru i „listingy“ vygenerované samotným assemblerem, ze kterých je patrné, jakým způsobem se jednotlivé příklady přeložily do výsledného XEX souboru:
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | Klávesnice osmibitových počítačů Atari: až překvapivě komplikovaná problematika | 0 | 5 | 06-07-2026 |
| 2 | Kdo v NATO zbrojí nejrychleji? Zkuste uhádnout státy, které překonaly USA | 0 | 7 | 07-07-2026 |
| 3 | Další funkce podporované čipem POKEY | 0 | 7 | 01-07-2026 |
| 4 | Box64 v0.4.4 Released With New Box64-Configurator App | 0 | 29.3 | 02-08-2026 |
| 5 | Příští rok opustí jádro řada starých procesorů a SoC ARM | 0 | 6 | 06-07-2026 |
| 6 | Dojemné gesto Dustina Hoffmana: Lístek pro smutného vozíčkáře | 7 | 5 | 05-07-2026 |
| 7 | Big Bang (Full Version) | 0 | 11.44 | 23-06-2026 |
| 8 | Expozice MěKS Kojetín – Když ještě technika byla v plenkách | 0 | 6.16 | 05-05-2026 |
| 9 | Mesas de Pinball Arcade deTerminator 2, Mars Attack, Top Gun. | 0 | 15.53 | 05-08-2026 |