Programování pro osmibitová Atari: volání instrukcí procesoru MOS 6502

Dnes
Doba čtení: 29 minut

Sdílet

Projekt Atari perex.
Autor: Michal Tauchman, podle licence: CC BY-SA 4.0
Projekt Atari perex.
Popíšeme si základní instrukce mikroprocesoru MOS 6502 a samozřejmě je použijeme v reálných příkladech. Taktéž si ukážeme způsob rozdělení programu do menších bloků – podprogramů (subrutin).

Obsah

1. Programátorský model mikroprocesoru MOS 6502

2. Registry a příznakové bity mikroprocesoru MOS 6502

3. Aritmetické a logické instrukce

4. Praktický příklad: výpočet barvy s využitím instrukce pro součet

5. Bitové posuny a rotace

6. Praktický příklad: výpočet barvy založený na bitovém posunu

7. Skoky a rozvětvení

8. Praktický příklad: skok do podprogramu bez předávání parametrů

9. Skok do podprogramu s předáním parametrů

10. Rozsáhlejší projekt: tisk hexadecimálních číslic na obrazovku

11. ATASCII

12. Interní kódy znaků při zápisu do video paměti

13. Realizace tisku jedné decimální číslice

14. Převod hodnoty 0..15 na kód znaku odpovídajícího hexadecimální cifře

15. Realizace tisku jedné hexadecimální číslice

16. Refaktoring v assembleru?

17. Strukturovaná varianta příkladu pro tisk jedné hexadecimální číslice

18. Příloha: Makefile pro překlad všech demonstračních příkladů

19. Repositář s demonstračními příklady

20. Odkazy na Internetu

1. Programátorský model mikroprocesoru MOS 6502

Z pohledu programátora, který pracuje v assembleru, se mikroprocesor MOS 6502 dosti podstatným způsobem odlišuje jak od konkurenčního Intelu 8080 (i od později vydaného Zilogu Z80), tak i například od čipu RCA-1802. Zatímco mikroprocesor Intel 8080 obsahoval poměrně rozsáhlou sadu obecně použitelných osmibitových registrů (konkrétně se jednalo o registry A, B, C, D, E, H a L), které se u některých instrukcí kombinovaly do šestnáctibitových registrových párů, obsahoval MOS 6502 pouze jeden osmibitový akumulátor (registr A) a dva taktéž osmibitové index-registry pojmenované X a Y. Oba zmíněné typy mikroprocesorů samozřejmě obsahovaly další speciální registry, mezi které patří ukazatel na vrchol zásobníku (SP), programový čítač (PC) a příznakový registr (F nebo P).

Na první pohled by se mohlo zdát, že počet pracovních registrů mikroprocesoru MOS 6502 je zcela nedostatečný pro provádění většiny aritmetických či logických operací. Ve skutečnosti tomu tak ovšem není, protože tento mikroprocesor podporuje načtení druhého operandu z operační paměti (rychlost RAM nebyla tak limitujícím faktorem, jako je tomu dnes – ve skutečnosti byl přístup do RAM dvojnásobně rychlý v porovnání s mikroprocesorem, což například umožnilo konstrukci sofistikovaných grafických subsystémů). U mnoha instrukcí je navíc podporován větší počet adresovacích režimů; celkově je možné operandy strojových instrukcí adresovat třinácti navzájem odlišnými způsoby. Při adresování se často používají oba index-registry, které je možné inkrementovat a dekrementovat – tím je umožněno provádění blokových přenosů dat, mazání souvislé oblasti paměti atd.

Mikroprocesor MOS 6502 také zavádí pojem takzvané nulté stránky paměti, která byla důsledně využita v instrukční sadě. Jedná se o prvních 256 bytů operační paměti, kterou je možné adresovat zjednodušeným způsobem. Adresa libovolné buňky z nulté stránky paměti je totiž uložena v jednom bajtu v operačním kódu instrukce, takže celá instrukce může být kratší (typicky pouze dva bajty). Současně je i provádění instrukcí adresujících nultou stránku paměti rychlejší než při šestnáctibitovém adresování (například se provádí pouze osmibitové sčítání atd.).

Z tohoto důvodu se můžeme na nultou stránku paměti dívat jako na pole 256 registrů resp. alternativně na 128 plnohodnotně využitelných 16bitových ukazatelů (musíme si opět uvědomit, že operační paměti byly v té době stejně rychlé jako procesor, takže čtení či zápis dat do paměti byla záležitost jednoho či dvou cyklů). Myšlenka nulté stránky paměti byla dále rozšířena v procesoru Motorola 6809, kde se však tato stránka dala v adresovatelné paměti posouvat na libovolné místo, podobně jako v pokračovateli 6502 – 16bitovém čipu 65816 (použit například v herní konzoli SNES).

2. Registry a příznakové bity mikroprocesoru MOS 6502

V předchozí kapitole jsme si řekli, že osmibitový mikroprocesor MOS 6502 obsahoval pouze minimální, ovšem ještě stále prakticky použitelný počet registrů. Všechny tyto registry jsou vypsány v následující tabulce:

# Registr Šířka Význam
1 A 8 bitů akumulátor
2 X 8 bitů index registr (osmibitová adresa nebo offset adresy)
3 Y 8 bitů index registr (osmibitová adresa nebo offset adresy)
4 SP 8 bitů část ukazatele na vrchol zásobníku (+ $0100)
5 PC 16 bitů čítač instrukcí
6 P 7/8 bitů příznakový a stavový registr

Většina aritmetických a logických operací používala jako jeden z operandů akumulátor A. Druhý operand (pokud se pochopitelně jednalo o instrukci se dvěma operandy) byl typicky načítán z operační paměti. Přitom se pro adresování často používaly index registry X a Y. Ukazatel na vrchol zásobníku SP (nebo jen S) dokázal adresovat zásobník v rozsahu $0100 až $01FF, tedy 256 bajtů (což většinou postačuje při práci v assembleru, ovšem vyšší programovací jazyky nedokážou zásobník využívat jako zásobníkový rámec, resp. mohou, ale s omezeními). A příznakový registr P měl obsazen jen sedm bitů:

Bit Označení Význam
7 N záporný výsledek
6 V přetečení do sedmého bitu
5 neobsazeno
4 B rozlišení přerušení od instrukce BRK či PHP
3 D režim výpočtů: binární versus BCD
2 I zákaz přerušení
1 Z nulový výsledek
0 C přenos
Poznámka: dá se říci, že každý z registrů má unikátní způsob použití. Dokonce ani registry X a Y se nepoužívají stejně – každý z nich podporuje odlišné adresovací režimy. I z tohoto důvodu je programování MOS 6502 zajímavé.

3. Aritmetické a logické instrukce

Mikroprocesor MOS 6502 obsahuje, což může být překvapující, pouze 56 instrukcí, přičemž mnoho instrukcí podporuje větší množství adresovacích režimů a tudíž i více variant (i tak však zdaleka není obsazeno všech 256 možných kombinací – ty byly postupně obsazovány v dalších procesorech, popř. na původním MOS 6502 měly sice oficiálně nedokumentovanou, ovšem logickou/očekávanou funkci [odkaz je funkční jen „náhodně“]).

Nejprve si popíšeme aritmetické a logické instrukce mikroprocesoru MOS 6502. Většina dále popsaných instrukcí jako svůj první operand akceptuje akumulátor (viz předchozí kapitolu) a druhým operandem může být konstanta popř. hodnota načtená z operační paměti s využitím minule popsaných adresovacích režimů. Výjimkou jsou instrukce s jediným operandem, v nichž nemusí vystupovat akumulátor, popř. instrukce, v nichž je přímo operand vyjádřen názvem instrukce (INX znamená zvýšení obsahu index registru X o jedničku atd.):

# Instrukce Plné jméno Popis
1 ADC add with carry součet hodnoty s akumulátorem (včetně přetečení)
2 SBC subtract with carry odečtení hodnoty od akumulátoru (včetně výpůjčky)
       
3 AND and with accumulator logické AND s akumulátorem
4 ORA or with accumulator logické OR s akumulátorem
5 EOR exclusive or with accumulator logické XOR s akumulátorem
       
6 INC increment zvýšení hodnoty o 1 (kupodivu nelze s akumulátorem, ovšem s pamětí ano)
7 INX increment X zvýšení hodnoty index registru X o 1
8 INY increment Y zvýšení hodnoty index registru Y o 1
9 DEC decrement snížení hodnoty o 1 (opět nelze s akumulátorem)
10 DEX decrement X snížení hodnoty index registru X o 1
11 DEY decrement Y snížení hodnoty index registru Y o 1
       
12 CMP compare with accumulator odečtení hodnoty od akumulátoru bez zápisu výsledku
13 CPX compare with X odečtení hodnoty od index registru X bez zápisu výsledku
14 CPY compare with Y odečtení hodnoty od index registru Y bez zápisu výsledku
15 BIT bit test logické AND bez uložení výsledků (změní se jen příznakové bity)
Poznámka: povšimněte si, že součet a rozdíl je realizován pouze dvojicí instrukcí ADC a SBC. Tyto instrukce vždy pracují i s příznakem přenosu carry, což konkrétně v případě součtu znamená, že výsledek může být o jedničku vyšší (pokud je carry nastaven). Z tohoto důvodu velmi často můžeme v praxi vidět instrukci CLC následovanou instrukcí ADC, čímž se vlastně „simuluje“ neexistující instrukce ADD (podobně je tomu u rozdílu).

4. Praktický příklad: výpočet barvy s využitím instrukce pro součet

Ukažme si nyní použití instrukcí ADC a CLC na sice poněkud umělém, ale snadno pochopitelném příkladu. Budeme v něm počítat kód barvy, který je složený ze dvou hodnot. První hodnotou je číslo barevného odstínu (0–15) a druhou hodnotou intenzita barvy (sudé hodnoty 0–14). Barevný odstín je nutné posunout doprava o čtyři bity popř. vynásobit šestnácti. Můžeme si tedy připravit tabulku se jmény odstínů a jejich hodnotami, které jsou již posunuty o čtyři bity:

HUE_COLOR_GRAY        = 16 * $0
HUE_COLOR_GOLD        = 16 * $1
HUE_COLOR_ORANGE_1    = 16 * $2
HUE_COLOR_PINK        = 16 * $3
HUE_COLOR_MAGENTA     = 16 * $4
HUE_COLOR_BLUE        = 16 * $5
HUE_COLOR_INDIGO      = 16 * $6
HUE_COLOR_SKY_BLUE    = 16 * $7
HUE_COLOR_ROYAL_BLUE  = 16 * $8
HUE_COLOR_LIGHT_BLUE  = 16 * $9
HUE_COLOR_TURQOISE    = 16 * $A
HUE_COLOR_AQUAMARIN   = 16 * $B
HUE_COLOR_SEA_GREEN   = 16 * $C
HUE_COLOR_LIGHT_GREEN = 16 * $D
HUE_COLOR_OLIVE       = 16 * $E
HUE_COLOR_ORANGE_2    = 16 * $F

Výpočet kódu barvy na základě čísla jejího odstínu a intenzity může proběhnout takto – do akumulátoru načteme odstín (již posunutý o čtyři bity) a přičteme k němu intenzitu (bez započtení příznaku přenosu). Následně je již možné nastavit barvu pozadí s využitím vypočteného kódu barvy:

        lda #HUE_COLOR_MAGENTA  ; kod odstinu barvy
        clc                     ; vymazat priznak prenosu
        adc #6                  ; svetlost v rozsahu 0..14 s krokem 2
        sta COLOR2              ; ulozit do registru COLOR2

Celý zdrojový kód příkladu může vypadat následovně:

.include "atari.inc"
 
HUE_COLOR_GRAY        = 16 * $0
HUE_COLOR_GOLD        = 16 * $1
HUE_COLOR_ORANGE_1    = 16 * $2
HUE_COLOR_PINK        = 16 * $3
HUE_COLOR_MAGENTA     = 16 * $4
HUE_COLOR_BLUE        = 16 * $5
HUE_COLOR_INDIGO      = 16 * $6
HUE_COLOR_SKY_BLUE    = 16 * $7
HUE_COLOR_ROYAL_BLUE  = 16 * $8
HUE_COLOR_LIGHT_BLUE  = 16 * $9
HUE_COLOR_TURQOISE    = 16 * $A
HUE_COLOR_AQUAMARIN   = 16 * $B
HUE_COLOR_SEA_GREEN   = 16 * $C
HUE_COLOR_LIGHT_GREEN = 16 * $D
HUE_COLOR_OLIVE       = 16 * $E
HUE_COLOR_ORANGE_2    = 16 * $F
 
.CODE
 
.proc main
        lda #HUE_COLOR_MAGENTA  ; kod odstinu barvy
        clc                     ; vymazat priznak prenosu
        adc #6                  ; svetlost v rozsahu 0..14 s krokem 2
        sta COLOR2              ; ulozit do registru COLOR2
loop:   jmp loop
end:
.endproc
 
 
.segment "EXEHDR"
.word   $ffff                   ; uvodni sekvence bajtu v souboru XEX
.word   main                    ; zacatek kodoveho segmentu
.word   main::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

Po překladu a spuštění tohoto demonstračního příkladu by se měla nastavit fialová barva pozadí se zhruba střední intenzitou (6/15):

Obrázek 1: Pozadí textu bylo nastaveno na barvu s vypočteným kódem.

Obrázek 1: Pozadí textu bylo nastaveno na barvu s vypočteným kódem.

Autor: tisnik, podle licence: Rights Managed
Poznámka: pochopitelně si můžete otestovat i další odstíny a intenzity.

5. Bitové posuny a rotace

Samostatnou skupinu instrukcí tvoří instrukce, které dokážou provádět bitové posuny a rotace. Pro MOS 6502, ostatně podobně, jako i pro mnohé další osmibitové procesory, je typické, že se posun/rotace provádí o jediný bit; není tedy možné nastavit ani specifikovat větší počet bitů. V praxi se tak můžeme setkat s opakovaným použitím těch samých instrukcí za sebou:

# Instrukce Plné jméno Popis
16 ASL arithmetic shift left aritmetický posun doleva o jeden bit
17 LSR logical shift right logický posun doprava o jeden bit
18 ROL rotate left rotace doleva o jeden bit
19 ROR rotate right rotace doprava o jeden bit

U instrukcí ASL a LSR je do výsledku nasouván nulový bit. Mikroprocesor MOS 6502 tedy nepodporuje aritmetický posun doprava (se znaménkem), to je však možné v případě potřeby relativně snadno simulovat. Operace rotací vždy pracují s devíti bity – osmi bity operandu a příznakem carry.

Všechny tyto operace nastavují resp. modifikují příznakové bity přenosu (carry), nulovosti (zero) a záporného výsledku (negative). I tím se MOS 6502 odlišuje od dalších mikroprocesorů, které typicky nastavují jen příznak přenosu.

6. Praktický příklad: výpočet barvy založený na bitovém posunu

Pokusme se nyní o využití instrukce pro provedení aritmetického posunu doleva, tj. instrukce, která vlastně provádí násobení dvěma. V úvodním demonstračním příkladu jsme byli nuceni posunout (či vynásobit) index barvového odstínu o čtyři bity již v definici odstínů. Nyní budeme postupovat odlišně. Všech šestnáct odstínů bude reprezentováno hodnotami 0 až 15:

HUE_COLOR_GRAY        = $0
HUE_COLOR_GOLD        = $1
HUE_COLOR_ORANGE_1    = $2
HUE_COLOR_PINK        = $3
HUE_COLOR_MAGENTA     = $4
HUE_COLOR_BLUE        = $5
HUE_COLOR_INDIGO      = $6
HUE_COLOR_SKY_BLUE    = $7
HUE_COLOR_ROYAL_BLUE  = $8
HUE_COLOR_LIGHT_BLUE  = $9
HUE_COLOR_TURQOISE    = $A
HUE_COLOR_AQUAMARIN   = $B
HUE_COLOR_SEA_GREEN   = $C
HUE_COLOR_LIGHT_GREEN = $D
HUE_COLOR_OLIVE       = $E
HUE_COLOR_ORANGE_2    = $F

Výpočet kódu barvy tedy bude vypadat takto: přímo v kódu vynásobíme index odstínu konstantou 16. Pochopitelně namísto násobení použijeme aritmetický posun doleva, který bude opakovaný čtyřikrát za sebou. Poté k mezivýsledku připočítání světlost:

        lda #HUE_COLOR_MAGENTA  ; kod odstinu barvy
        clc                     ; vymazat priznak prenosu
        asl A                   ; provest 4x aritmeticky posun doprava
        asl A
        asl A
        asl A
        adc #6                  ; svetlost v rozsahu 0..14 s krokem 2
        sta COLOR2              ; ulozit do registru COLOR2

Výsledek by měl vypadat následovně:

Obrázek 2: Pozadí textu bylo nastaveno na barvu s vypočteným kódem.

Obrázek 2: Pozadí textu bylo nastaveno na barvu s vypočteným kódem.  

Autor: tisnik, podle licence: Rights Managed

Pro úplnost si pochopitelně uvedeme úplný zdrojový kód tohoto demonstračního příkladu:

.include "atari.inc"
 
HUE_COLOR_GRAY        = $0
HUE_COLOR_GOLD        = $1
HUE_COLOR_ORANGE_1    = $2
HUE_COLOR_PINK        = $3
HUE_COLOR_MAGENTA     = $4
HUE_COLOR_BLUE        = $5
HUE_COLOR_INDIGO      = $6
HUE_COLOR_SKY_BLUE    = $7
HUE_COLOR_ROYAL_BLUE  = $8
HUE_COLOR_LIGHT_BLUE  = $9
HUE_COLOR_TURQOISE    = $A
HUE_COLOR_AQUAMARIN   = $B
HUE_COLOR_SEA_GREEN   = $C
HUE_COLOR_LIGHT_GREEN = $D
HUE_COLOR_OLIVE       = $E
HUE_COLOR_ORANGE_2    = $F
 
.CODE
 
.proc main
        lda #HUE_COLOR_MAGENTA  ; kod odstinu barvy
        clc                     ; vymazat priznak prenosu
        asl A                   ; provest 4x aritmeticky posun doprava
        asl A
        asl A
        asl A
        adc #6                  ; svetlost v rozsahu 0..14 s krokem 2
        sta COLOR2              ; ulozit do registru COLOR2
loop:   jmp loop
end:
.endproc
 
 
.segment "EXEHDR"
.word   $ffff                   ; uvodni sekvence bajtu v souboru XEX
.word   main                    ; zacatek kodoveho segmentu
.word   main::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

7. Skoky a rozvětvení

Následují instrukce skoku, popř. skoku a výskoku ze subrutiny (podprogramu). Skákat je možné v rámci celé adresovatelné RAM, tedy v rozsahu 64kB:

# Instrukce Plné jméno Popis
20 JMP jump skok (existuje několik adresovacích režimů)
21 JSR jump to subroutine skok do podprogramu s uložením návratové adresy na zásobník
22 RTS return from subroutine návrat z podprogramu
23 RTI return from interrupt návrat z prerušovací rutiny

Relativní skoky v rámci rozsahu –128 až 127 jsou naproti tomu provedeny na základě vyhodnocení nějaké podmínky, konkrétně testování zvoleného příznakového bitu. Oproti Motorole 6800 byl počet podmíněných skoků snížen na polovinu, takže některé kombinace podmínek neexistují (včetně BRA a BRN):

# Instrukce Plné jméno Popis
24 BCC branch on carry clear rozvětvení za podmínky C==0
25 BCS branch on carry set rozvětvení za podmínky C==1
26 BEQ branch on equal (zero set) rozvětvení za podmínky Z==1
27 BMI branch on minus (negative set) rozvětvení za podmínky N==1
28 BNE branch on not equal (zero clear) rozvětvení za podmínky Z==0
29 BPL branch on plus (negative clear) rozvětvení za podmínky N==0
30 BVC branch on overflow clear rozvětvení za podmínky O==0
31 BVS branch on overflow set rozvětvení za podmínky O==1

8. Praktický příklad: skok do podprogramu bez předávání parametrů

Skok do podprogramu lze realizovat instrukcí JSR (Jump to SubRoutine) a návrat z podprogramu instrukcí RTS (ReTurn from Subroutine). Při skoku do podprogramu se na zásobník uloží návratová adresa, konkrétně adresa instrukce za JSR. A pochopitelně při návratu ze subrutiny se adresa získá právě ze zásobníku. Vzhledem k tomu, že zásobník má maximální kapacitu 256 bajtů, lze provést pouze 127 skoků do subrutiny (potom se začnou přepisovat adresy na nejhlubších prvcích zásobníku).

Podívejme se nyní, jak se v assembleru CA65 subrutiny zapisují. Používají se zde konstrukce .proc a .endproc, jejichž výhoda je ta, že identifikátory deklarované v subrutině (tedy většinou návěští) jsou pouze lokální. Vytvoříme novou subrutinu pro tisk znaku na začátek obrazovky. Tuto subrutinu potom zavoláme:

.include "atari.inc"
 
.CODE
 
.proc main
        jsr print_char
loop:   jmp loop
.endproc
 
.proc print_char
        lda #33                 ; kod znaku, ktery se bude tisknout
        ldy #0                  ; vynulovat registr Y
        sta (88), y             ; tisk znaku na první místo na obrazovce
        rts
.endproc
 
end:                            ; potrebujeme znat adresu konce kodoveho segmentu
 
.segment "EXEHDR"
.word   $ffff                   ; uvodni sekvence bajtu v souboru XEX
.word   main                    ; zacatek kodoveho segmentu
.word   end - 1                 ; konec kodoveho segmentu
 
 
.segment "AUTOSTRT"             ; segment s pocatecni adresou
.word   RUNAD                   ; naplni se pouze adresy RUNAD a RUNAD+1
.word   RUNAD+1
.word   main                    ; adresa vstupniho bodu do programu
 
; finito

Výsledek by měl vypadat následovně:

Obrázek 3: Tisk znaku pomocí subrutiny.

Obrázek 3: Tisk znaku pomocí subrutiny.

Autor: tisnik, podle licence: Rights Managed

9. Skok do podprogramu s předáním parametrů

V mnoha případech je nutné subrutinám předávat parametry. Pro tento účel se používají různé techniky: původně se parametry předávaly přes pracovní registry (což počet parametrů nutně omezuje), posléze se přešlo k předávání parametrů přes zásobník (ovšem nikoli na MOS 6502) a dnes se vracíme k předávání parametrů opět přes registry, kterých je ovšem nyní o řád více, než v případě minimalistického MOS 6502. My si prozatím vystačíme s předáváním několika parametrů, a proto využijeme registry A, X a Y. Až ve chvíli, kdy to nebude dostačující, použijeme odlišný způsob, například předávání přes oblast v nulté stránce paměti atd.

Subrutinu pro tisk znaku upravíme do takové podoby, že bude v akumulátoru A akceptovat kód tisknutého znaku:

.include "atari.inc"
 
.CODE
 
.proc main
        lda #10                 ; kod znaku, ktery se bude tisknout
        jsr print_char          ; tisk znaku
loop:   jmp loop
.endproc
 
.proc print_char
        ldy #0                  ; vynulovat registr Y
        sta (88), y             ; tisk znaku na první místo na obrazovce
        rts
.endproc
 
end:                            ; potrebujeme znat adresu konce kodoveho segmentu
 
.segment "EXEHDR"
.word   $ffff                   ; uvodni sekvence bajtu v souboru XEX
.word   main                    ; zacatek kodoveho segmentu
.word   end - 1                 ; konec kodoveho segmentu
 
 
.segment "AUTOSTRT"             ; segment s pocatecni adresou
.word   RUNAD                   ; naplni se pouze adresy RUNAD a RUNAD+1
.word   RUNAD+1
.word   main                    ; adresa vstupniho bodu do programu
 
; finito

Výsledek by měl v tomto případě vypadat takto:

Obrázek 4: Tisk znaku, jehož kód byl předán subrutině. 

Obrázek 4: Tisk znaku, jehož kód byl předán subrutině. 

Autor: tisnik, podle licence: Rights Managed

10. Rozsáhlejší projekt: tisk hexadecimálních číslic na obrazovku

Zbytek dnešního článku a začátek článku následujícího bude věnován zdánlivě jednoduché úloze, která ovšem v assembleru bude relativně rozsáhlá (a navíc se u ní naučíme mnoho nových postupů). Budeme se snažit o vytvoření subrutiny, která na obrazovku vytiskne hexadecimální hodnotu v rozsahu 0..0×ffff. Ovšem to není triviální úloha, zejména pokud s programováním v assembleru teprve začínáme. Proto si tuto úlohu rozdělíme do více kroků:

  1. Tisk jediné dekadické cifry 0 až 9 na první místo na obrazovce
  2. Tisk hexadecimální cifry 0 až F na první místo na obrazovce
  3. Tisk hexadecimální hodnoty v rozsahu 0 až 0×ff na první dvě místa na obrazovce
  4. Tisk hexadecimální hodnoty v rozsahu 0 až 0×ffff na první čtyři místa na obrazovce
  5. Rozšíření podprogramu o umožnění specifikace souřadnic na obrazovce, kde se má provést zápis
  6. Rozšíření celého I/O systému o koncept textového kurzoru

11. ATASCII

Při programování osmibitových mikropočítačů Atari se dříve či později setkáme se zkratkou ATASCII. Tato zkratka znamená Atari ASCII a jedná se o tabulku, která každému ze 128 tisknutelných znaků přiřazuje hodnotu 0 až 128. ATASCII je do značné míry podobná standardní tabulce ASCII, ovšem některé znaky chybí (složené závorky atd.) a jiné naopak „přebývají“ (ale to platí i pro mnohé další mikropočítače, které většinou doplňují nějaké znaky na pozice 0 až 31). ATASCII vypadá následovně:

Znak ATASCII Znak ATASCII Znak ATASCII Znak ATASCII
CTRL-, 0 SPACE 32 @ 64 CTRL-. 96
CTRL-A 1 ! 33 A 65 a 97
CTRL-B 2 " 34 B 66 b 98
CTRL-C 3 # 35 C 67 c 99
CTRL-D 4 $ 36 D 68 d 100
CTRL-E 5 % 37 E 69 e 101
CTRL-F 6 & 38 F 70 f 102
CTRL-G 7 ' 39 G 71 g 103
CTRL-H 8 ( 40 H 72 h 104
CTRL-I 9 ) 41 I 73 i 105
CTRL-J 10 * 42 J 74 j 106
CTRL-K 11 + 43 K 75 k 107
CTRL-L 12 , 44 L 76 l 108
CTRL-M 13 45 M 77 m 109
CTRL-N 14 . 46 N 78 n 110
CTRL-O 15 / 47 O 79 o 111
CTRL-P 16 0 48 P 80 p 112
CTRL-Q 17 1 49 Q 81 q 113
CTRL-R 18 2 50 R 82 r 114
CTRL-S 19 3 51 S 83 s 115
CTRL-T 20 4 52 T 84 t 116
CTRL-U 21 5 53 U 85 u 117
CTRL-V 22 6 54 V 86 v 118
CTRL-W 23 7 55 W 87 w 119
CTRL-X 24 8 56 X 88 x 120
CTRL-Y 25 9 57 Y 89 y 121
CTRL-Z 26 : 58 Z 90 z 122
ESCAPE 27 ; 59 [ 91 CTRL-; 123
UP ARROW 28 < 60 \ 92 | 124
DOWN ARROW 29 = 61 ] 93 CLEAR 125
LEFT ARROW 30 > 62 ^ 94 DELETE 126
RIGHT ARROW 31 ? 63 _ 95 TAB 127
Poznámka: v ATASCII je definováno pouze 128 kódů/znaků, protože hodnoty 129 až 255 jsou vyhrazeny inverzním znakům. To znamená, že znak A má v ATASCII hodnotu 65 a jeho inverzní varianta pak hodnotu 128+65=193.

12. Interní kódy znaků při zápisu do video paměti

Pokusme se tedy přímo do obrazové paměti rezervované pro textový režim zapsat kódy 0 až 255. Prozatím nemáme všechny informace potřebné k tomu naprogramovat tisk celé tabulky přímo v assembleru, proto se uchýlím ke standardnímu Atari BASICu. Celý postup je zřejmý z komentářů: do mřížky 16×16 znaků se zapisují hodnoty 0 až 255, a to do oblasti paměti, která začíná na adrese uložené v bajtech 88 a 89:

1 REM *****************************
2 REM Vypis vsech znaku primo na
3 REM obrazovku v rezimu GRAPHICS 8
4 REM
5 REM Uprava pro Atari BASIC
6 REM
7 REM *****************************
8 REM
9 REM
10 GRAPHICS 0
20 REM Pocatecni adresa video RAM
25 START=PEEK(88)+256*PEEK(89)
30 REM Tisk sestnacti radku
35 FOR Y=0 TO 15
40 REM Tisk sestnacti sloupcu
45 FOR X=0 TO 15
50 REM Adresa ve video RAM pro zapis
55 ADDR=START+X+Y*40
60 REM Kod znaku pro zapis
65 CODE=X+Y*16
70 REM Vlastni zapis znaku na obrazovku
75 POKE ADDR,CODE
80 NEXT X
85 NEXT Y
90 REM finito
99 GOTO 99

Výsledek bude vypadat následovně:

Obrázek 5: Všech 128 znaků vytištěných v přímé i inverzní variantě

Obrázek 5: Všech 128 znaků vytištěných v přímé i inverzní variantě.

Autor: tisnik, podle licence: Rights Managed

Z tohoto screenshotu je zřejmé, že se ve skutečnosti nepoužila ATASCII. Osmibitové Atari mají několik nepříjemných vlastností (skutečně jen několik :-). Patří mezi ně i fakt, že kódy v ATASCII neodpovídají kódu znaku zapsaného na obrazovku a navíc ani neodpovídají kódu odpovídající stisknuté klávesy. Zaměřme se na první rozdíl, tj. na to, jaký znak odpovídá hodnotě 0..255 zapsané do textové obrazovky (přímým zápisem do paměti). Vztah mezi zapsaným bajtem a zobrazeným znakem je následující:

Znak Interní kód Znak Interní kód Znak Interní kód Znak Interní kód
SPACE 0 @ 32 CTRL-, 64 CTRL-. 96
! 1 A 33 CTRL-A 65 a 97
" 2 B 34 CTRL-B 66 b 98
# 3 C 35 CTRL-C 67 c 99
$ 4 D 36 CTRL-D 68 d 100
% 5 E 37 CTRL-E 69 e 101
& 6 F 38 CTRL-F 70 f 102
' 7 G 39 CTRL-G 71 g 103
( 8 H 40 CTRL-H 72 h 104
) 9 I 41 CTRL-I 73 i 105
* 10 J 42 CTRL-J 74 j 106
+ 11 K 43 CTRL-K 75 k 107
, 12 L 44 CTRL-L 76 l 108
13 M 45 CTRL-M 77 m 109
. 14 N 46 CTRL-N 78 n 110
/ 15 O 47 CTRL-O 79 o 111
0 16 P 48 CTRL-P 80 p 112
1 17 Q 49 CTRL-Q 81 q 113
2 18 R 50 CTRL-R 82 r 114
3 19 S 51 CTRL-S 83 s 115
4 20 T 52 CTRL-T 84 t 116
5 21 U 53 CTRL-U 85 u 117
6 22 V 54 CTRL-V 86 v 118
7 23 W 55 CTRL-W 87 w 119
8 24 X 56 CTRL-X 88 x 120
9 25 Y 57 CTRL-Y 89 y 121
: 26 Z 58 CTRL-Z 90 z 122
; 27 [ 59 ESCAPE 91 CTRL-; 123
< 28 \ 60 UP ARROW 92 | 124
= 29 ] 61 DOWN ARROW 93 CLEAR 125
> 30 ^ 62 LEFT ARROW 94 DELETE 126
? 31 _ 63 RIGHT ARROW 95 TAB 127
Poznámka: ve skutečnosti zde můžeme najít celé bloky, které jsou oproti ATASCII posunuty o určitý offset. Přepočet lze tedy provést výpočtem, nikoli převodní tabulkou (ostatně kdo by obětoval celých 128 bajtů?). Výpočet bude relativně krátký a většinou i dostatečně rychlý.

13. Realizace tisku jedné decimální číslice

Začneme tím nejjednodušším možným a přitom stále funkčním příkladem. Budeme v něm realizovat podprogram nazvaný dec_digit, který na obrazovku vytiskne číslici, jejíž hodnota je předána v akumulátoru A. Nebudeme přitom (prozatím) provádět žádné kontroly. Realizace je snadná, protože při pohledu do tabulky uvedené v předchozí kapitole je zřejmé, že pouze postačuje přičíst k číslici konstantu 16 a získáme interní kód odpovídajícího znaku:

.include "atari.inc"
 
.CODE
 
.proc main
        lda #9                  ; cislo, ktere se bude tisknout
        jsr dec_digit
loop:   jmp loop
.endproc
 
.proc dec_digit
        clc                     ; vymazat priznak prenosu
        adc #16                 ; prevod hodnoty na interni kod (ne ATASCII!)
        ldy #0                  ; vynulovat registr Y
        sta (88), y             ; tisk znaku na první místo na obrazovce
                                ; (adresa Video RAM je na adresách 88 a 89)
        rts                     ; navrat z podprogramu
.endproc
 
end:                            ; potrebujeme znat adresu konce kodoveho segmentu
 
 
.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

Podívejme se na výsledek, který byl získán pro číslici 9 (což přesně odpovídá zdrojovému kódu):

Obrázek 6: Tisk číslice 9.

Obrázek 6: Tisk číslice 9.

Autor: tisnik, podle licence: Rights Managed

V podprogramu dec_digit nekontrolujeme meze, takže číslice 10 (neexistující) se vytiskne takto (opět se podívejte na tabulku v předchozí kapitole a zjistíte, že dvojtečka skutečně leží za kódem číslice 9):

Obrázek 7: Pokus o tisk číslice 10.

Obrázek 7: Pokus o tisk číslice 10.

Autor: tisnik, podle licence: Rights Managed

14. Převod hodnoty 0..15 na kód znaku odpovídajícího hexadecimální cifře

Předchozí příklad nyní upravíme, a to konkrétně do takové podoby, aby dokázal vytisknout nikoli „pouze“ dekadickou číslici, ale číslici hexadecimální. Konkrétně tedy budeme chtít, aby se pro vstupní hodnotu 0, 1, … 9, 10, … 15 vytiskly znaky 0, 1, … 9, A, … F. Samotná realizace bude vyžadovat buď provedení různých triků založených na binárně-desítkovém kódování (tento trik se využíval na Z80) nebo se jednoduše zjistí, zda je vstupní hodnota větší nebo rovna deseti. Pokud tomu tak je, přičteme k hodnotě sedmičku. Tato konstanta je opět získána z tabulky zobrazené ve dvanácté kapitole. Budeme totiž chtít, aby se pro vstup 10 nevytiskla dvojtečka, ale znak A. Ten má kód 33, zatímco dvojtečka má kód 26, tudíž je rozdíl skutečně roven 33–26=7.

.proc hex_digit
        cmp #$0a                ; test na hodnotu 0-9 nebo 10-15
        bcc skip_add            ; je to hodnota 0-9
        adc #6                  ; pricist sedmicku
skip_add:
        adc #16                 ; prevod hodnoty na interni kod (ne ATASCII!)
        ldy #0                  ; vynulovat registr Y
        sta (88), y             ; tisk znaku na první místo na obrazovce
                                ; (adresa Video RAM je na adresách 88 a 89)
        rts                     ; navrat z podprogramu
.endproc
Poznámka: pro hexadecimální číslice A až F se provádí součet dvakrát. Dokážete navrhnout takovou úpravu, která jeden ze součtů eliminuje (tj. pro všechny vstupy se provede jen jediný součet)?

15. Realizace tisku jedné hexadecimální číslice

Podprogram hex_digit můžeme snadno zařadit do demonstračního příkladu, jehož úplný zdrojový kód bude vypadat následovně:

.include "atari.inc"
 
.CODE
 
.proc main
        lda #9                  ; cislo, ktere se bude tisknout
        jsr hex_digit
loop:   jmp loop
.endproc
 
.proc hex_digit
        cmp #$0a                ; test na hodnotu 0-9 nebo 10-15
        bcc skip_add            ; je to hodnota 0-9
        adc #6                  ; pricist sedmicku
skip_add:
        adc #16                 ; prevod hodnoty na interni kod (ne ATASCII!)
        ldy #0                  ; vynulovat registr Y
        sta (88), y             ; tisk znaku na první místo na obrazovce
                                ; (adresa Video RAM je na adresách 88 a 89)
        rts                     ; navrat z podprogramu
.endproc
 
end:                            ; potrebujeme znat adresu konce kodoveho segmentu
 
 
.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

Chování příkladu si pochopitelně otestujeme, nejdříve pro vstupní hodnotu v rozsahu 0 až 9:

Obrázek 8: Tisk číslice 9.

Obrázek 8: Tisk číslice 9.

Autor: tisnik, podle licence: Rights Managed

Ve druhém kroku předáme podprogramu libovolnou hodnotu z rozsahu 10 až 15 a opět zkontrolujeme výsledek:

Obrázek 9: Tisk číslice 10 dekadicky, tj. A hexadecimálně

Obrázek 9: Tisk číslice 10 dekadicky, tj. A hexadecimálně.

Autor: tisnik, podle licence: Rights Managed

16. Refaktoring v assembleru?

Programy psané v assembleru jsou psány na relativně nízké úrovni abstrakce. Proto je prakticky nutné nějakým způsobem neustále provádět jejich refaktoring, protože v opačném případě bychom získali „špagetový kód“ skládající se z nic neříkajících instrukcí. Assemblery a do jisté míry i samotné mikroprocesory nám nabízí dvě základní techniky, které je možné využít a různým způsobem je kombinovat. Jedná se o rozdělení úlohy na jednotlivé podprogramy (subrutiny), ideálně s rozumně nastaveným rozhraním, které specifikuje, jakým způsobem se mají do subrutin předávat parametry. A druhou technologií jsou makra, kterými se budeme zabývat v navazujícím článku. Ovšem již samotné rozdělení programu na podprogramy může zvětšit čitelnost a vlastně se dostat na vyšší úroveň abstrakce (o programu budeme uvažovat jako o vzájemně se volajících blocích, nikoli jako o sekvenci instrukcí).

Poznámka: z tohoto pohledu je klasický BASIC vlastně ještě nízkoúrovňovějším jazykem, než assembler.

17. Strukturovaná varianta příkladu pro tisk jedné hexadecimální číslice

Program pro tisk jedné hexadecimální číslice se po logické stránce skládá ze tří bloků: hlavního programu, podprogramu pro výpočet interního kódu znaku, který se má tisknout a konečně z podprogramu, který tisk provede. Díky tomu, že se do podprogramů předává pouze jediný parametr, který je navíc osmibitový, lze přenos parametrů realizovat s využitím akumulátoru A. Rozdělení programu do menších celků by tedy mohlo vypadat například následovně:

.include "atari.inc"
 
.CODE
 
 
.proc main
        lda #9                  ; cislo, ktere se bude tisknout
        jsr hex_digit           ; prevod na interni kod cislice
        jsr print_char          ; tisk cislice/znaku
loop:   jmp loop
.endproc
 
 
.proc hex_digit
        cmp #$0a                ; test na hodnotu 0-9 nebo 10-15
        bcc skip_add            ; je to hodnota 0-9
        adc #6                  ; pricist sedmicku
skip_add:
        adc #16                 ; prevod hodnoty na interni kod (ne ATASCII!)
        rts                     ; navrat z podprogramu
.endproc
 
 
.proc print_char
        ldy #0                  ; vynulovat registr Y
        sta (88), y             ; tisk znaku na první místo na obrazovce
                                ; (adresa Video RAM je na adresách 88 a 89)
        rts
.endproc
 
end:                            ; potrebujeme znat adresu konce kodoveho segmentu
 
 
.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

Samozřejmě si můžeme otestovat, že vše (stále) funguje tak, jak se očekává:

Obrázek 10: Tisk číslice 9, používá se dvojice subrutin.

Obrázek 10: Tisk číslice 9, používá se dvojice subrutin.

Autor: tisnik, podle licence: Rights Managed

18. 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:

školení AI

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 \
         hex_number_1.xex        hex_number_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

Výsledkem překladu jsou soubory s koncovkou .xex, které je možné přímo spustit v emulátoru osmibitových počítačů Atari.

19. Repositář s demonstračními příklady

Všechny demonstrační příklady, s nimiž jsme se v dnešním článku 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:

# Příklad Stručný popis příkladu Adresa
1 Makefile definice cílů pro překlad všech demonstračních příkladů z této tabulky https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/Makefile
2 linker.cfg konfigurační soubor pro linker https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/linker.cfg
       
3 dummy.asm pouze nekonečná smyčka https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/dummy.asm
4 dummy_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/dummy_list.asm
5 dummy_list.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/dummy.map
       
6 background_color1.asm změna barvy pozadí – základní varianta příkladu https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/background_color1.asm
7 background_color1_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/background_color1_list.asm
8 background_color1.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/background_color1.map
       
9 background_color2.asm změna barvy pozadí – využití předdefinovaných konstant https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/background_color2.asm
10 background_color2_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/background_color2_list.asm
11 background_color2.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/background_color2.map
       
12 print_a.asm tisk znaku přímo do obrazové paměti https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/print_a.asm
13 print_a_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/print_a_list.asm
14 print_a.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/print_a.map
       
15 color_computation1.asm výpočet barvy, varianta bez bitových posunů https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/color_computation1.asm
16 color_computation1_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/color_computation1_list.asm
17 color_computation1.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/color_computation1.map
       
18 color_computation2.asm výpočet barvy, varianta s bitovými posuny https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/color_computation2.asm
19 color_computation2_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/color_computation2_list.asm
20 color_computation2.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/color_computation2.map
       
21 subroutine1.asm skok do podprogramu bez předávání parametrů https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/subroutine1.asm
22 subroutine1_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/subroutine1_list.asm
23 subroutine1.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/subroutine1.map
       
24 subroutine2.asm skok do podprogramu s předáním parametru https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/subroutine2.asm
25 subroutine2_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/subroutine2_list.asm
26 subroutine2.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/subroutine2.map
       
27 hex_number1.asm tisk jedné hexadecimální číslice (nekorektní varianta) https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number1.asm
28 hex_number1_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number1_list.asm
29 hex_number1.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number1.map
       
30 hex_number2.asm tisk jedné hexadecimální číslice (korektní varianta) https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number2.asm
31 hex_number2_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number2_list.asm
32 hex_number2.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number2.map
       
33 hex_number3.asm tisk jedné hexadecimální číslice (korektní varianta po refaktoringu) https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number3.asm
34 hex_number3_list.asm „listing“ vygenerovaný assemblerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number3_list.asm
35 hex_number3.map mapa paměti; soubor vytvořený linkerem https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/hex_number3.map
       
36 chars.bas tisk všech znaků na obrazovku (varianta naprogramovaná v BASICu) https://github.com/tisnik/8bit-fame/blob/master/Atari800-ca65/chars.bas

20. Odkazy na Internetu

  1. MOS 6502 instruction set
    http://www.6502.org/users/o­belisk/6502/instructions.html
  2. EXE File Format Description
    https://gury.atari8.info/ref­s/file_formats_exe.php
  3. XEX Filter – A toolkit to analyze and manipulate Atari binary files
    https://www.vitoco.cl/atari/xex-filter/index.html
  4. chkxex.py
    https://raw.githubusercon­tent.com/seban-slt/tcx_tools/refs/heads/mas­ter/chkxex.py
  5. ca65 Users Guide
    https://cc65.github.io/doc/ca65.html
  6. cc65 Users Guide
    https://cc65.github.io/doc/cc65.html
  7. ld65 Users Guide
    https://cc65.github.io/doc/ld65.html
  8. da65 Users Guide
    https://cc65.github.io/doc/da65.html
  9. Překladače jazyka C pro historické osmibitové mikroprocesory
    https://www.root.cz/clanky/prekladace-jazyka-c-pro-historicke-osmibitove-mikroprocesory/
  10. 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/
  11. Getting Started Programming in C: Coding a Retro Game with C Part 2
    https://retrogamecoders.com/getting-started-with-c-cc65/
  12. NES game development in 6502 assembly – Part 1
    https://kibrit.tech/en/blog/nes-game-development-part-1
  13. 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/
  14. Minimal NES example using ca65
    https://github.com/bbbradsmith/NES-ca65-example
  15. List of 6502-based Computers and Consoles
    https://www.retrocompute.co.uk/list-of-6502-based-computers-and-consoles/
  16. 6502 – the first RISC µP
    http://ericclever.com/6500/
  17. 3 Generations of Game Machine Architecture
    http://www.atariarchives.or­g/dev/CGEXPO99.html
  18. “Hello, world” from scratch on a 6502 — Part 1
    https://www.youtube.com/wat­ch?v=LnzuMJLZRdU
  19. A Tour of 6502 Cross-Assemblers
    https://bumbershootsoft.wor­dpress.com/2016/01/31/a-tour-of-6502-cross-assemblers/
  20. Adventures with ca65
    https://atariage.com/forum­s/topic/312451-adventures-with-ca65/
  21. example ca65 startup code
    https://atariage.com/forum­s/topic/209776-example-ca65-startup-code/
  22. 6502 PRIMER: Building your own 6502 computer
    http://wilsonminesco.com/6502primer/
  23. 6502 Instruction Set
    https://www.masswerk.at/6502/6502_in­struction_set.html
  24. Chip Hall of Fame: MOS Technology 6502 Microprocessor
    https://spectrum.ieee.org/tech-history/silicon-revolution/chip-hall-of-fame-mos-technology-6502-microprocessor
  25. Single-board computer
    https://en.wikipedia.org/wiki/Single-board_computer
  26. www.6502.org
    http://www.6502.org/
  27. 6502 PRIMER: Building your own 6502 computer – clock generator
    http://wilsonminesco.com/6502pri­mer/ClkGen.html
  28. Great Microprocessors of the Past and Present (V 13.4.0)
    http://www.cpushack.com/CPU/cpu.html
  29. Jak se zrodil procesor?
    https://www.root.cz/clanky/jak-se-zrodil-procesor/
  30. Osmibitové mikroprocesory a mikrořadiče firmy Motorola (1)
    https://www.root.cz/clanky/osmibitove-mikroprocesory-a-mikroradice-firmy-motorola-1/
  31. 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/
  32. 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/
  33. 25 Microchips That Shook the World
    https://spectrum.ieee.org/tech-history/silicon-revolution/25-microchips-that-shook-the-world
  34. Comparison of instruction set architectures
    https://en.wikipedia.org/wi­ki/Comparison_of_instructi­on_set_architectures
  35. How To Start Learning Atari 8 Bit Assembly For Free
    https://forums.atariage.com/to­pic/300732-how-to-start-learning-atari-8-bit-assembly-for-free/
  36. WUDSN (Demo Group)
    https://www.wudsn.com/
  37. Machine Language For Beginners
    https://www.atariarchives.org/mlb/
  38. Assembly language: all about I/O
    https://www.atarimagazines­.com/v3n8/AllAbout_IO.html
  39. Sedmdesátiny assemblerů: lidsky čitelný strojový kód
    https://www.root.cz/clanky/sed­mdesatiny-assembleru-lidsky-citelny-strojovy-kod/
  40. Color names
    https://atariwiki.org/wiki/Wi­ki.jsp?page=Color%20names
  41. ATASCII
    https://en.wikipedia.org/wiki/ATASCII
  42. Put characters in display ram isn't ATASCII?
    https://forums.atariage.com/to­pic/359973-put-characters-in-display-ram-isnt-atascii/
  43. ATASCII And Internal Character Code Values
    https://www.atariarchives­.org/mapping/appendix10.php

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.



Nejnovější články