Dnes navážeme na článek Programovací jazyk Action! pro osmibitové domácí mikropočítače Atari, který na Rootu vyšel minulý týden. V předchozím článku jsme si popsali základní vlastnosti jazyka Action! Mj. jsme si řekli, že tento jazyk byl oblíbený i z toho důvodu, že programy v něm napsané byly velmi rychlé, zejména v porovnání s existujícími interpretry programovacího jazyka BASIC (a především se to týká původního Atari BASICu).
Co se dozvíte v článku
- Čekání na stisk klávesy START, SELECT nebo OPTION
- Měření času běhu benchmarku na osmibitových mikropočítačích Atari/
- Realizace měření času v jazyku Action!
- Praktický příklad na měření času realizovaného v jazyku Action!
- Jak rychlé jsou programy psané v jazyku Action! v porovnání s dobovými interpretry?
- Interpretry jazyka BASIC pro osmibitové mikropočítače Atari
- Porovnání rychlosti interpretrů jazyka BASIC pro osmibitová Atari
- Benchmark typu snowcrash napsaný v BASICu
- Výsledky benchmarku pro různé interpretry jazyka BASIC
- Přepis benchmarku do jazyka Action!
- Změřené výsledky, porovnání s dostupnými interpretry jazyka BASIC
- Knihovna dodávaná k jazyku Action!
- Procedury určené pro tisk hodnot různých typů
- Funkce PrintF v jazyku Action!
- Základní operace v grafickém režimu
- Vykreslení úseček v grafickém režimu GRAPHICS 7
- Jak rychlá je práce s grafikou při použití knihovních funkcí?
- Repositář s demonstračními příklady
- Odkazy na Internetu
Toto tvrzení je však dobré ověřit, takže si v úvodní části dnešního článku ukážeme jednoduchý benchmark, z něhož bude patrné, že je Action! skutečně velmi rychlý, pochopitelně pro určité operace (netýká se to ovšem práce s numerickými hodnotami s plovoucí řádovou čárkou atd.).
Obrázek 1: Obrazovka, kterou zná každý atarista: takto vypadá prostředí Atari BASICu po spuštění počítače.
Ve druhé části článku se seznámíme s některými procedurami a funkcemi, které jsou součástí standardní knihovny jazyka Action! Nalezneme zde například různé varianty procedury PRINT, což je v praxi velmi užitečné. Ale ve standardní knihovně lze nalézt například i operace pro práci s grafickými režimy atd. (zde se kupodivu Action! do značné míry přibližuje BASICu).
Obrázek 2: Úvodní obrazovka vývojového prostředí jazyka Action!
Čekání na stisk klávesy START, SELECT nebo OPTION
V příkladech, které budou popsány v dalších kapitolách, budeme potřebovat interaktivně čekat na stisk nějaké klávesy. Prozatím jsme (při práci v assembleru) pro tento účel využívali službu operačního systému, ovšem samozřejmě je možné čekání realizovat vlastními silami. Jednou z nejjednodušších možností je čekání na stisk některé z kláves START, SELECT nebo OPTION. Stav těchto kláves lze přečíst z adresy $D01F. Nejnižší tři bity přečtené z této adresy mají následující význam (další bity jsou nulové):
| Bit | Význam |
|---|---|
| 0 | 0=stisk klávesy START |
| 1 | 0=stisk klávesy SELECT |
| 2 | 0=stisk klávesy OPTION |
Stisk je tedy reprezentován nulovým bitem, což znamená, že hodnota 7 a vyšší značí, že žádná z kláves nebyla stlačena. Přečíst je možné i libovolnou kombinaci stisku kláves.
Realizaci čekání na stisk libovolné klávesy START, SELECT či OPTION (či jejich kombinace) je možné v jazyku Action! naprogramovat například s využitím programové smyčky WHILE s prázdným tělem mezi klíčovými slovy DO a OD:
PROC WAITKEY()
BYTE CONSOL=$D01F
WHILE CONSOL>6
DO
OD
RETURN
Měření času běhu benchmarku na osmibitových mikropočítačích Atari/
U benchmarků je v naprosté většině případů nutné nějakým způsobem měřit čas, který uplyne mezi začátkem a dokončením benchmarku. V případě osmibitových mikropočítačů Atari je realizace časovače poměrně triviální (a v assembleru ji lze realizovat jen několika instrukcemi). Můžeme totiž využít toho, že v operačním systému Atari už jeden časovač běží. S frekvencí 50 či 60 Hz (v závislosti na použité televizní normě) totiž dochází k modifikaci hodnot uložených na adresách 18, 19 a 20 ($12, $13, $14). Tato oblast se nazývá RTCLOK neboli real time clock. Předpokládejme, že máme osmibitové Atari upravené pro televizní normu PAL. V takovém případě se při každém VBLANKu (50× za sekundu, tedy každý půlsnímek) zvýší osmibitová hodnota uložená na adrese 20 ($14). Při přetečení hodnoty na adrese 20 ($14) se zvýší hodnota uložená na adrese 19 ($13) a pokud i tato hodnota přeteče (tedy po cca 21 minutách), tak se zvýší hodnota uložená na adrese 18 ($12).
Teoreticky tedy musíme na začátku benchmarku přečíst 24bitovou hodnotu a po jeho dokončení přečíst další 24bitovou hodnotu. Tyto hodnoty se od sebe odečtou a výsledek po vydělení padesáti bude reprezentovat dobu běhu benchmarku v sekundách. Ovšem ve skutečnosti to není 1) tak lehké 2) tak složité. Můžeme totiž časovač nejdříve vynulovat, čímž odstraníme potřebu odečítat dvě 24bitové hodnoty (a to si můžeme dovolit, protože lze předpokládat, že žádný další proces již v systému neběží). Navíc se můžeme omezit pouze na spodních šestnáct bitů, pokud bude benchmark dokončen v cca 21 minutách. A ta složitá část: vydělení padesáti sice je možné, ovšem jazyk Action! nepodporuje hodnoty s plovoucí řádovou čárkou, takže získáme jen údaj v celých sekundách. A to je pro benchmark běžící jen několik sekund velmi malé rozlišení. Proto je zapotřebí před dělením padesáti přemýšlet, v jakém kontextu se čas měří – dlouhé výpočty či relativně krátká smyčka?
Realizace měření času v jazyku Action!
Postup, který byl teoreticky popsán v předchozí kapitole, nyní můžeme přepsat do programovacího jazyka Action! Nejprve nadefinujeme trojici proměnných typu BYTE s určením jejich adres v operační paměti (v céčku by se tedy jednalo o ukazatele):
BYTE RTC1=18
BYTE RTC2=19
BYTE RTC3=20
Před déletrvající operací všechny tři proměnné vynulujeme:
BYTE RTC1=18
BYTE RTC2=19
BYTE RTC3=20
A po dokončení operace vypočteme čas v jednotkách nazývaných jitties (což jsou padesátiny nebo šedesátiny sekundy):
CARD TIME
TIME=RTC2*256+RTC3
Převod na sekundy je již snadný:
PRINT("FINISHED IN ")
PRINTC(TIME/50)
PRINTE(" SECONDS")
Celý příklad může vypadat zhruba následovně:
PROC MAIN()
BYTE RTC1=18
BYTE RTC2=19
BYTE RTC3=20
CARD TIME
RTC1=0
RTC2=0
RTC3=0
...
...
...
TIME=RTC2*256+RTC3
PRINT("FINISHED IN ")
PRINTC(TIME/50)
PRINTE(" SECONDS")
WAITKEY()
RETURN
Sami si můžete otestovat, zda je možné pracovat s časovačem jako se šestnáctibitovou hodnotou typu CARD, nikoli jako s dvojicemi proměnných typu BYTE. Tím se omezí nutnost čtení dvou bajtů a násobení 256 (to je na MOS 6502 velmi pomalá operace).
Praktický příklad na měření času realizovaného v jazyku Action!
Měření času si můžeme otestovat na následujícím příkladu. Ten po svém spuštění čeká na stisk libovolné klávesy START, SELECT či OPTION (nebo jejich kombinace – viz úvodní kapitoly). Posléze se doba čekání získaná v jitties převede na sekundy a vypočtený výsledek se vypíše na obrazovku. Na konci programu pro jistotu opět čekáme na stisk klávesy, protože se může stát, že monitor zabudovaný do jazyka Action! obrazovku po dokončení programu přepíše (chová se odlišně, než například BASIC):
PROC WAITKEY()
BYTE CONSOL=$D01F
WHILE CONSOL>6
DO
OD
RETURN
PROC MAIN()
BYTE RTC1=18
BYTE RTC2=19
BYTE RTC3=20
CARD TIME
RTC1=0
RTC2=0
RTC3=0
WAITKEY()
TIME=RTC2*256+RTC3
PRINT("FINISHED IN ")
PRINTC(TIME/50)
PRINTE(" SECONDS")
WAITKEY()
RETURN
Obrázek 3: Zdrojový kód programu pro měření času zapsaného v jazyku Action!
Obrázek 4: Program pro měření času byl spuštěn v monitoru.
Obrázek 5: Výsledek zobrazený po stisku některé z kláves START, SELECT či OPTION.
Jak rychlé jsou programy psané v jazyku Action! v porovnání s dobovými interpretry?
Podle stránek Tiobe i PYPL PopularitY of Programming Language je v současnosti nejvíce používaný programovací jazyk Python (resp. dotazy na Python jsou nejčastější). Každá z těchto stránek používá odlišné metriky (které navíc s nástupem AI asi přestávají platit) a v případě PYPL se pravděpodobně jedná o nějakou chybu (viz grafy s nápadným růstem Pythonu), ovšem Python je skutečně velmi populární. A prakticky stejnou niku na přelomu sedmdesátých a osmdesátých let minulého století „okupoval“ programovací jazyk BASIC.
Ve skutečnosti se nejedná o jediný jazyk popsaný nějakou normou (i ta ovšem vznikla – a byla většinou implementací vesele ignorována), ale o rodinu jazyků sdílejících společnou myšlenku: umožnit relativně snadnou tvorbu programů i těmi uživateli, kteří nejsou profesionálními vývojáři. Z toho plyne i poměrně specifický přístup k datovým typům, který se v BASICu používal (omezení množství typů na nezbytné minimum: čísla, řetězce, jednorozměrná a dvourozměrná pole čísel a jednorozměrná, někdy i dvourozměrná pole řetězců – to je většinou vše).
Interpretry jazyka BASIC pro osmibitové mikropočítače Atari
V rámci dalších kapitol se pokusíme implementovat jednoduchý benchmark a změřit rychlosti jednotlivých implementací BASICu pro osmibitové domácí mikropočítače Atari. Ovšem o jaké BASICy se vlastně jedná?
V první řadě se jedná o originální Atari BASIC, který byl součástí standardní ROM (8kB BASIC+16kB operační systém). Jednalo se o velmi pomalý interpret, což si ostatně ověříme.
V roce 1983 byl společností OSS vydán dialekt BASICu pojmenovaný BASIC A+. Tento dialekt obsahoval opravy a vylepšení původního Atari BASICu a navíc byl tento interpret rychlejší, než původní BASIC. Zajímavé je, že BASIC A+ nebyl dodáván na cartridge, ale na disketě, a to společně se systémem OS/A+ a EASMD (Editor/Assembler). Celková cena za tyto tři programy byla 80 dolarů, takže je patrné že se jednalo o jiný segment trhu, než tomu bylo v případě profesionálnějších nástrojů BUG/65 a MAC/65. Samotný interpret zabral dalších 15 kB RAM. Byl (jak již víme) rychlejší než původní Atari BASIC, obsahoval základní podporu pro PMG (sprity) a taktéž základní podporu pro ladění programů.
O další rok později, tedy v roce 1984, vydala společnost OSS další interpret programovacího jazyka BASIC, který byl pojmenován BASIC XL, a to podle toho, že běžel na systémech Atari XL (s plnou RAM) a pochopitelně taktéž na Atari XE. Opět se jednalo o poměrně významné vylepšení a rozšíření možností původního BASICu, k dispozici byly i metody k urychlení výsledných (interpretovaných) programů.
V roce 1985 společnost OSS vydala svoji poslední verzi interpretru programovacího jazyka BASIC pro osmibitová Atari. Tato varianta se jmenovala BASIC XE, a to z toho důvodu, že byl podporován přístup do rozšířené paměti počítačů Atari 130 XE (celkem neuvěřitelných 128 kB RAM) – program bylo možné oddělit do dat, přičemž program byl umístěn ve druhé bance RAM. BASIC XE nabízel i rychlejší matematické operace a oproti BASICu XL nabízel i několik dalších vylepšení (ovšem ne mnoho).
Dalším interpretrem programovacího jazyka BASIC, s nímž se v dnešním článku ve stručnosti seznámíme, je Atari Microsoft BASIC. Na historii jeho vzniku jsme již upozornili v jednom z předchozích článků o počítačích Atari – původně totiž měly být domácí osmibitové mikropočítače Atari skutečně dodávány s Microsoft BASICem uloženým v ROM, ovšem nakonec nebylo možné tento interpret umístit do požadovaných osmi kilobajtů ROM, takže jako vhodnější alternativa vznikl Atari BASIC. Nicméně společnost Micro-soft skutečně Atari Microsoft BASIC vydala, a to již v roce 1981. Z několika pohledů se však jedná o dosti rozdílný interpret, než je tomu v (ideové) řadě Atari BASIC → BASIC A+ → BASIC XL → BASIC XE → Turbo BASIC.
O rok později po vydání původního Atari Microsoft BASICu (tedy v roce 1982) byla vydána jeho druhá verze s několika opravami a taktéž s několika novými příkazy. Jedná se zejména o příkaz AUTO zajišťující automatické generování čísel řádků a dále o velmi užitečný příkaz MOVE určený pro přesuny paměťových bloků (o dva až tři řády rychlejší, než v samotném BASICu). Příkazem COMMON bylo možné specifikovat ty proměnné, které „přežijí“ samotný program a bude je možné využít v dalším kódu – to teoreticky umožňuje vytvářet moduly, minimálně při použití disketové jednotky.
V žádném případě ovšem nesmíme zapomenout na slavný Turbo BASIC XL (či jen Turbo BASIC), jehož autorem je známý Frank Ostrowski (tento programátor později vytvořil GFA BASIC pro osobní počítače Atari ST). Turbo BASIC téměř splňoval všechny sny BASICových programátorů – byl rychlejší než původní Atari BASIC, byl s Atari BASICem plně kompatibilní, díky programovému „odklápění“ ROM nabízel vývojářům prakticky stejné nebo i větší množství volné operační paměti (což působilo téměř magicky) a navíc Turbo BASIC obsahoval poměrně velké množství nových příkazů, ať již určených pro strukturované programování (nové typy programových smyček), tak i příkazy zjednodušující programátorovu každodenní činnost.
Porovnání rychlosti interpretrů jazyka BASIC pro osmibitová Atari
Rychlost jednotlivých interpretrů programovacího jazyka BASIC zjistíme s využitím dvojice jednoduchých benchmarků. U obou benchmarků se bude měřit čas běhu části programu, přičemž pro měření použijeme časovač dostupný na adresách 18, 19 a 20, o němž jsme se již zmínili v předchozím textu. Tento časovač lze programově vynulovat, což jsme si již ukázali v úvodních kapitolách (v jazyku Action!). Stejné vynulování lze provést i v BASICech:
10 REM VYMAZANI CASOVACE 11 POKE 18,0 12 POKE 19,0 13 POKE 20,0
Na konci programu zjistíme stav časovače a převedeme ho na sekundy podělením půlsnímkovou frekvencí (tedy 50 či 60 Hz podle použité televizní normy):
40 REM PRECTENI CASOVACE 41 REM (PLATNE PRO PAL) 42 T=((PEEK(18)*65536+PEEK(19)*256+PEEK(20))/50) 50 PRINT "FINISHED IN ";T;" SECONDS"
Logická chyba, kterou jsme udělali v jazyku Action!, je přítomna i v tomto programu a vlastně je ještě horší, protože BASIC je o řád až dva řády pomalejší, než program naprogramovaný přímo v jazyku Action!.
Benchmark typu snowcrash napsaný v BASICu
Benchmark, který použijeme pro porovnání rychlostí interpretrů jazyka BASIC, je ve skutečnosti velmi jednoduchý. Testuje se v něm rychlost realizace počítaných programových smyček a taktéž rychlost zápisu do operační paměti. Program po svém spuštění nejprve provede přepnutí do grafického režimu GRAPHICS 8 a následně zaplní obrazovou paměť (pseudo)náhodnými hodnotami a simuluje tak „sněžení“ analogového televizoru bez antény:
Zdrojový kód tohoto příkladu, který je kompatibilní se všemi výše zmíněnými interpretry programovacího jazyka BASIC, vypadá následovně:
1 REM ***************************** 2 REM Vyplneni obrazovky v rezimu 3 REM 320x192 nahodnym vzorkem. 4 REM 5 REM Implementace pro Atari BASIC 6 REM 7 REM Upraveno do podoby benchmarku 8 REM ***************************** 9 REM 10 REM VYMAZANI CASOVACE 11 POKE 18,0 12 POKE 19,0 13 POKE 20,0 20 REM VLASTNI BENCHMARK 21 GRAPHICS 8 22 START=PEEK(88)+256*PEEK(89) 23 FINAL=START+320*160/8 30 FOR I=START TO FINAL 35 REM 17BITOVY POLY CITAC = RND 40 POKE I,PEEK(53770) 50 NEXT I 60 REM PRECTENI CASOVACE 70 REM (PLATNE PRO PAL) 80 T=((PEEK(18)*65536+PEEK(19)*256+PEEK(20))/50) 90 PRINT "FINISHED IN ";T;" SECONDS" 99 END
Tento zdrojový kód nahrajeme do BASICu příkazem ENTER:
Obrázek 6: Benchmark pro vyplnění obrazovky zapsaný v prostředí Atari BASICu.
A následně příkazem RUN benchmark spustíme:
Obrázek 7: Benchmark několik desítek sekund po spuštění.
Čas na dokončení tohoto benchmarku bude v případě Atari BASICu dosahovat přibližně 73 sekund:
Obrázek 8: Benchmark po dokončení a výpisu času, který uběhl.
Výsledky benchmarku pro různé interpretry jazyka BASIC
Stejný benchmark lze spustit i v dalších interpretrech jazyka BASIC dostupných pro osmibitové Atari (je totiž naprogramován tak, aby byl plně kompatibilní). Dosažené časy vyplnění obrazové paměti náhodnými hodnotami se pochopitelně pro různé interpretry BASICu liší, a to dosti podstatně, jak je ostatně patrné při pohledu na tabulku:
| Interpret | Čas | |
|---|---|---|
| Atari BASIC | 73.28 | |
| BASIC A+ | 45.88 | |
| Turbo BASIC XL | 17.14 | |
| BASIC XL | 34.38 | |
| BASIC XL (FAST) | 27.06 | |
| BASIC XE | 63.14 | |
| Microsoft Atari BASIC | 65.18 | |
| Microsoft Atari BASIC II | 65.22 |
Vizualizace výsledků benchmarku:
Obrázek 9: Výsledky benchmarku – porovnání rychlosti všech interpretrů jazyka BASIC.
Vítěz je v tomto případě zřejmý – je jím slavný Turbo BASIC XL Franka Ostrowskeho. Druhý nejrychlejší čas dosažený BASICem XL s příkazem FAST je mnohem horší (a to o celých deset sekund). Nejpomalejší je původní Atari BASIC, což by však nemělo být příliš překvapující – Atari BASIC se svojí pomalostí už stačil proslavit.
Přepis benchmarku do jazyka Action!
Ve standardní knihovně jazyka Action! je k dispozici procedura GRAPHICS(), která se chová prakticky stejně jako příkaz GRAPHICS v BASICu. Kompatibilita je zajištěna do takové míry, že se na adresy 88 a 89 uloží začátek obrazové paměti. Navíc je ve standardní knihovně Actionu dostupná i procedura POKE() což znamená, že přepis benchmarku z BASICu do jazyka Action! je prakticky bezproblémový (i když použití POKE výsledek spíše zpomalí).
Obrázek 10: Benchmark v podobě přepsané do jazyka Action!
Přepis dopadne následovně (a to i s pomocnou procedurou pro čekání na stisk klávesy). Dovolím si tvrdit, že tento program je čitelnější, než jeho BASICový protějšek:
PROC WAITKEY()
BYTE CONSOL=$D01F
WHILE CONSOL>6
DO
OD
RETURN
PROC MAIN()
BYTE RTC1=18
BYTE RTC2=19
BYTE RTC3=20
CARD TIME
CARD GFXMEM=88
CARD START, FINAL
CARD POLY=53770
CARD ADR
RTC1=0
RTC2=0
RTC3=0
GRAPHICS(8)
START=GFXMEM
FINAL=START+(320/8*160)
FOR ADR=START TO FINAL
DO
POKE(ADR, POLY)
OD
TIME=RTC2*256+RTC3
PRINT("FINISHED IN ")
PRINTC(TIME/50)
PRINTE(" SECONDS")
WAITKEY()
RETURN
Ve skutečnosti je benchmark dokončen tak rychle, že se změří čas nula sekund (!):
Obrázek 11: Výsledek běhu benchmarku v případě, že se čas měří v sekundách.
Musíme tedy provést malou úpravu benchmarku – čas se bude vypisovat v desetinách sekundy a ne v celých sekundách:
PROC WAITKEY()
BYTE CONSOL=$D01F
WHILE CONSOL>6
DO
OD
RETURN
PROC MAIN()
BYTE RTC1=18
BYTE RTC2=19
BYTE RTC3=20
CARD TIME
CARD GFXMEM=88
CARD START, FINAL
CARD POLY=53770
CARD ADR
RTC1=0
RTC2=0
RTC3=0
GRAPHICS(8)
START=GFXMEM
FINAL=START+(320/8*160)
FOR ADR=START TO FINAL
DO
POKE(ADR, POLY)
OD
TIME=RTC2*256+RTC3
PRINT("FINISHED IN 0.")
PRINTC(TIME/5)
PRINTE(" SECONDS")
WAITKEY()
RETURN
Obrazovka je překreslena přibližně za 0,4 sekundy:
Obrázek 12: Výsledky běhu benchmarku v případě, že se čas měří v desetinách sekundy.
Jen pro úplnost se podívejme na způsob překladu do strojového kódu:
; da65 V2.18 - Fedora 2.19-12.fc42
; Created: 2026-09-10 22:04:58
; Input file: OBJ2
; Page: 1
.setcpu "6502"
L10F8 := $10F8
L10FB := $10FB
L1108 := $1108
L1114 := $1114
L117E := $117E
L11A8 := $11A8
L11DD := $11DD
L120E := $120E
L2E30 := $2E30
L4553 := $4553
L4E49 := $4E49
LA000 := $A000
LA090 := $A090
LA46C := $A46C
LA47F := $A47F
LA4E6 := $A4E6
LA654 := $A654
LA777 := $A777
lda #$06
cmp $D01F
bcc LFEE5
jmp L1108
LFEE5: jmp L10FB
rts
brk
brk
brk
brk
brk
brk
brk
brk
jmp L1114
ldy #$00
sty $12
sty $13
sty $14
lda #$08
jsr LA654
lda $59
sta $110C
lda $58
sta $110B
lda #$00
sta $85
lda #$08
sta $84
lda #$01
tax
lda #$40
jsr LA090
sta $AE
txa
sta $AF
lda #$00
sta $85
lda #$A0
sta $84
lda $AF
tax
lda $AE
jsr LA000
sta $AC
txa
sta $AD
clc
lda $110B
adc $AC
sta $110D
lda $110C
adc $AD
sta $110E
lda $110C
sta $1110
lda $110B
sta $110F
lda $110D
sta $118F
lda $110E
sta $1190
LFF5E: lda $118F
cmp $110F
lda $1190
sbc $1110
bcs LFF71
jmp L11A8
brk
brk
LFF71: ldy $D20A
ldx $1110
lda $110F
jsr LA777
inc $110F
bne LFF5E
inc $1110
jmp L117E
lda #$01
sta $85
lda #$00
sta $84
lda $13
ldx #$00
jsr LA000
sta $AE
txa
sta $AF
clc
lda $AE
adc $14
sta $1109
lda $AF
adc #$00
sta $110A
jmp L11DD
asl $4946
lsr $5349
pha
eor $44
jsr L4E49
jsr L2E30
ldx #$11
lda #$CE
jsr LA47F
lda #$00
sta $85
lda #$05
sta $84
lda $110A
tax
lda $1109
jsr LA090
sta $A0
txa
sta $A1
ldx $A1
lda $A0
jsr LA4E6
jmp L120E
php
jsr L4553
.byte $43
.byte $4F
lsr $5344
ldx #$12
lda #$05
jsr LA46C
jsr L10F8
rts
rts
.byte $E2
.byte $02
.byte $E3
.byte $02
ora ($11),y
Změřené výsledky, porovnání s dostupnými interpretry jazyka BASIC
Opět porovnejme čas všech benchmarků, nyní i s variantou naprogramovanou v jazyku Action!:
| Interpret | Čas | |
|---|---|---|
| Action! | 0.4 | |
| Atari BASIC | 73.28 | |
| BASIC A+ | 45.88 | |
| Turbo BASIC XL | 17.14 | |
| BASIC XL | 34.38 | |
| BASIC XL (FAST) | 27.06 | |
| BASIC XE | 63.14 | |
| Microsoft Atari BASIC | 65.18 | |
| Microsoft Atari BASIC II | 65.22 |
Z výsledků vyplývá, že legendy o rychlosti jazyka Action! vlastně vůbec nelhaly!
Obrázek 13: Jeden obrázek vydá za tisíc slov: porovnání výsledků, nyní i s variantou naprogramovanou v jazyku Action!
Knihovna dodávaná k jazyku Action!
V předchozím článku o jazyku Action! jsme si řekli, že jak samotný překladač tohoto jazyka, tak i jeho vývojové prostředí s editorem a monitorem bylo dodáváno na paměťové cartridgi s ROM (EPROM) o kapacitě 16 kB. To zajisté není z dnešního pohledu žádná závratná velikost (ostatně primitivní „Hello, world!“ napsaný v céčku se na moderní architektuře, moderním překladačem a na moderním operačním systému bez dalších úprav přeloží do souboru o velikosti 12 kB, o dalších překladačích ani nemluvě). Ovšem na začátku osmdesátých let minulého století se do oněch šestnácti kilobajtů vešlo jak již výše zmíněné vývojové prostředí (celoobrazovkový textový editor), překladač, monitor, tak i standardní knihovna. A právě na popis některých zajímavých a užitečných procedur a funkcí ze standardní knihovny se zaměříme v navazujících kapitolách.
Procedury určené pro tisk hodnot různých typů
Většina programů musí vypisovat informace v textové podobě, přičemž výstup (tisk) je proveden buď na obrazovku nebo na zvolené zařízení, včetně tiskárny, souboru uloženého na disketě atd. V BASICu se pro tento účel používá univerzální příkaz PRINT, jenž dokáže tisknout číselné hodnoty i řetězce, tiskne na zvolené zařízení (resp. přesněji řečeno do zvoleného kanálu) a můžeme určit, jestli se má za vytištěnou informací provést odřádkování nebo „odskočení“ na další tabelační zarážku. V jazyku Action! se namísto příkazu PRINT používá několik variant procedury, jejíž jméno taktéž začíná znaky PRINT, ovšem navíc s přidanými znaky v názvu. Jména všech variant procedury PRINT odpovídají tomuto vzoru:
Print{typ}{D|E}(parametry)
Součástí jména je jak typ hodnoty, která se má vytisknout, tak i určení, jestli má tisk proběhnout na obrazovku nebo do zvoleného kanálu. Navíc se znakem E může vynutit tisk znaku RETURN, tj. odřádkování. Všech šestnáct možných kombinací této procedury je vypsáno v tabulce:
| Variant | řetězec | BYTE | CARD | INT |
|---|---|---|---|---|
| na obrazovku | PrintB | PrintC | PrintI | |
| EOL | PrintE | PrintBE | PrintCE | PrintIE |
| na zařízení | PrintD | PrintBD | PrintCD | PrintID |
| zařízení+EOL | PrintDE | PrintBDE | PrintCDE | PrintIDE |
Hlavičky jednotlivých procedur vypadají takto:
Tisk řetězce:
PROC Print(<řetězec>) PROC PrintE(<řetězec>) PROC PrintD(BYTE <číslo kanálu>, <řetězec>) PROC PrintDE(BYTE <číslo kanálu>, <řetězec>)
Tisk osmibitové hodnoty bez znaménka:
PROC PrintB(BYTE <číslo>) PROC PrintBE(BYTE <číslo>) PROC PrintBD(BYTE <číslo kanálu>, BYTE <číslo>) PROC PrintBDE(BYTE <číslo kanálu>, BYTE <číslo>)
Tisk šestnáctibitové hodnoty bez znaménka:
PROC PrintC(CARD <číslo>) PROC PrintCE(CARD <číslo>) PROC PrintCD(BYTE <číslo kanálu>, CARD <číslo>) PROC PrintCDE(BYTE <číslo kanálu>, CARD <číslo>)
Tisk šestnáctibitové hodnoty se znaménkem:
PROC PrintI(INT <číslo>) PROC PrintIE(INT <číslo>) PROC PrintID(BYTE <číslo kanálu>, INT <číslo>) PROC PrintIDE(BYTE <číslo kanálu>, INT <číslo>)
Interně je použití těchto procedur přeloženo na volání subrutiny.
Funkce PrintF v jazyku Action!
Kromě výše popsaných šestnácti procedur určených pro tisk hodnot různých typů na různá zařízení je ve standardní knihovně jazyka Action! definována i procedura nazvaná PRINTF, která se do jisté míry podobá známé funkci printf z jazyka C. I v proceduře PRINTF je možné používat formátovací znaky, ovšem není například možné definovat šířku tisku atd. Všechny podporované formátovací znaky jsou vypsány v následující tabulce:
| Formátovací znak | Význam |
|---|---|
| %S | řetězec (S podle slova string) |
| %I | INT (I podle slova integer) |
| %U | CARD (U podle slova unsigned) |
| %C | znak (C podle slova character) |
| %H | CARD v hexadecimálním formátu |
| %% | znak % |
| %E | EOR (Return) |
Příklad použití:
PROC TISK()
PRINTF("%U%E", 42)
PRINTF("%H%E", 42)
RETURN
Výsledek by měl vypadat takto:
Obrázek 14: Tisk hodnoty 42 v dekadickém i hexadecimálním formátu.
Základní operace v grafickém režimu
Pro grafické operace jsou nabízeny procedury, které se jmenují stejně jako příkazy v původním Atari BASICu:
| Procedura | Stručný popis |
|---|---|
| GRAPHICS | nastavení grafického režimu |
| SETCOLOR | nastavení barvového registru 0–4 |
| PLOT | vykreslení pixelu na zvolených souřadnicích barvou COLOR |
| DRAWTO | vykreslení úsečky od poslední souřadnice do nových souřadnic barvou COLOR |
| FILL | odpovídá původnímu XIO příkazu pro operaci „fill“ |
Barva vykreslování se volí zápisem do proměnné COLOR. V závislosti na zvoleném grafickém režimu může tato proměnná (typu BYTE) nabývat dvou či čtyř hodnot (v monochromatických režimech se rozlišuje jen mezi sudou a lichou hodnotou atd.). Pozor ovšem na nastavení COLOR=125, které vymaže obrazovku.
Základní příkazy pro vykreslování si otestujeme na tomto jednoduchém prográmku:
PROC MAIN() GRAPHICS(7) COLOR=1 PLOT(0,0) DRAWTO(159,79) COLOR=2 PLOT(159,0) DRAWTO(0,79) RETURN
S výsledkem:
Obrázek 15: Procedury GRAPHICS, PLOT a DRAWTO v akci.
Vykreslení úseček v grafickém režimu GRAPHICS 7
Vyzkoušejme si základní použití procedur GRAPHICS, PLOT a DRAWTO společně s proměnnou COLOR pro vykreslení několika svislých úseček. Využijeme přitom grafický režim GRAPHICS 7, který dokáže zobrazit čtyři barvy s rozlišením 160×80 pixelů (+ textové okno). Zdrojový kód tohoto příkladu je tak přehledný, že nevyžaduje podrobnější popis:
PROC WAITKEY()
BYTE CONSOL=$D01F
WHILE CONSOL>6
DO
OD
RETURN
PROC MAIN()
CARD X
BYTE C
GRAPHICS(7)
C=0
FOR X=10 TO 150 STEP 5
DO
COLOR=C
C=C+1
PLOT(X, 0)
DRAWTO(X, 70)
OD
WAITKEY()
RETURN
Obrázek 16: Kód pro vykreslení několika vertikálních úseček různou barvou.
Obrázek 17: Obrazovka po vykreslení několika vertikálních úseček.
Jak rychlá je práce s grafikou při použití knihovních funkcí?
Programy, které jsou přeloženy překladačem jazyka Action!, jsou většinou velmi rychlé, samozřejmě za předpokladu, že je rychlý samotný implementovaný algoritmus. Ovšem na tomto místě je nutné přiznat, že například procedura DRAWTO bude stejně rychlá (resp. spíše stejně pomalá), jako její obdoba v Atari BASICu. Ostatně si to můžeme ověřit vykreslením 160 svislých úseček společně s měřením času. Povšimněte si triku při výpočtu barvy – musíme totiž zamezit tomu, aby se obraz vymazal v případě, že nastavíme barvu číslo 125:
PROC WAITKEY()
BYTE CONSOL=$D01F
WHILE CONSOL>6
DO
OD
RETURN
PROC DEMO()
CARD X
BYTE C
GRAPHICS(7)
C=0
FOR X=0 TO 159 STEP 1
DO
COLOR=C
C=C+1
C=C&3
PLOT(X, 0)
DRAWTO(X, 70)
OD
RETURN
PROC MAIN()
BYTE RTC1=18
BYTE RTC2=19
BYTE RTC3=20
CARD TIME
RTC1=0
RTC2=0
RTC3=0
DEMO()
TIME=RTC2*256+RTC3
PRINT("FINISHED IN ")
PRINTC(TIME/50)
PRINTE(" SECONDS")
WAITKEY()
RETURN
Obrázek 18: Jednoduchý benchmark pro měření rychlosti vykreslování úseček.
Výsledek tohoto „benchmarku“ není příliš lichotivý:
Obrázek 19: Výsledek jednoduchého benchmarku pro měření rychlosti vykreslování úseček.
V Atari BASICu se stejný obrazec vykreslí za přibližně sedm sekund, takže Action! zde již není tak oslnivě rychlý:
10 GRAPHICS 7 20 C=0 30 FOR X=0 TO 159 40 COLOR C 50 C=C+1 60 IF C=4 THEN C=0 70 PLOT X,0 80 DRAWTO X,79 90 NEXT X
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 - Manuál k MAC/65
https://data.atariwiki.org/DOC/MAC-65_and_BUG-65_Rev._1.1-OSS-OCR.pdf - Manuál k DDT
https://atariwiki.org/wiki/attach/DDT/DDT_1.0_Manual.pdf - MAC/65 na Atari wiki
https://www.atariwiki.org/wiki/Wiki.jsp?page=Mac65 - Madass – home page
https://mads.atari8.info/ - Mad-Assembler (GitHub)
https://github.com/tebe6502/Mad-Assembler - The 6502/65C02/65C816 Instruction Set Decoded
https://llx.com/Neil/a2/opcodes.html - Action
https://atariwiki.org/wiki/Wiki.jsp?page=Action#top - Action: manuál
file:///home/ptisnovs/Downloads/action-manual.pdf - Getting in on the Action 1
https://atariwiki.org/wiki/Wiki.jsp?page=Getting%20in%20on%20the%20Action%201 - Getting in on the Action 2
https://atariwiki.org/wiki/Wiki.jsp?page=Getting%20in%20on%20the%20Action%202 - Category:Action! na RosettaCode
https://rosettacode.org/wiki/Category:Action!
