V seriálu o vývoji her i dalších aplikací pro slavné osmibitové domácí mikropočítače Atari jsme primárně využívali assembler mikroprocesoru MOS 6502. Poté jsme se seznámili s několika vyššími programovacími jazyky. Buď se jednalo o překladače spouštěné přímo na Atari (do této kategorie spadají především Action!, Deep Blue C, ale i Kyan Pascal), cross překladače generující strojový kód na PC (CC65) nebo o více či méně výkonné interpretry (Atari BASIC, BASIC A+, Atari Microsoft BASIC, Turbo BASIC XL) či programovací jazyky překládané do bajtkódu (minule popsaný Fast BASIC).
Co se dozvíte v článku
- Vznik programovacího jazyka FORTH
- FORTH a další programovací jazyky
- Zásobníkové programovací jazyky a RPN
- Infixová vs. postfixová notace
- Přednosti a zápory RPN oproti infixové notaci
- Výpis numerické hodnoty uložené na vrcholu zásobníku operandů
- Základní operace prováděné s hodnotami uloženými na zásobníku operandů
- Slovo SWAP
- Slovo DUP
- Slovo DROP
- Slovo OVER
- Slovo ROT
- Definice nových slov
- Příklad definice a otestování nového slova ve fig-FORTHu
- Programové smyčky
- Příklad realizace programové smyčky ve fig-FORTHu
- Další typy programových smyček
- Repositář s demonstračními příklady
- Odkazy na Internetu
Z pohledu úrovně abstrakce spadají tyto programovací jazyky do tří skupin: assemblery, překladače a interpretry s volnějším zápisem kódu. A každá skupina má své přednosti, ale i zápory: assembler je nejtěžší na zápis i ladění, překladače obecně negenerují optimální kód a interpretry sice může používat téměř každý, ale jsou velmi pomalé. Ovšem existuje programovací jazyk, který do jisté míry leží mimo tyto tři skupiny a současně spadá do všech tří skupin. Jedná se o Forth resp. původně psaný FORTH.
Obrázek 1: Úvodní obrazovka fig-FORTHu (kazetová verze) ve variantě pro osmibitové mikropočítače Atari.
Forth, který byl na osmibitových Atari reprezentován především projektem fig-FORTH, je programovací jazyk, který byl – alespoň podle mého názoru – pravděpodobně nejlepším a nejvíce vyhovujícím programovacím jazykem pro „malé“ osmibitové domácí mikropočítače vůbec – a to, že se více neprosadil, byla možná škoda (na druhou stranu se jedná o poměrně „mimozemský“ jazyk, takže jeho prosazení do mainstreamu by bylo problematické v každém případě). Mezi jeho přednosti patří interaktivita (v tomto ohledu se podobá klasickým interpretrům) a současně i možnost zápisu relativně rychlého nízkoúrovňového kódu. Ve fig-FORTHu je navíc možné zapisovat i instrukce mikroprocesoru MOS 6502, takže části programu mohou být v případě potřeby optimalizovány (ovšem jak uvidíme dále, není to zcela jednoduché, protože i tyto části programu je nutné psát „forthovským“ stylem).
Obrázek 2: Interaktivní práce ve FORTHu. Uložení hodnoty na zásobník operandů, tisk hodnoty přečtené ze zásobníku operandů. Podrobnosti budou vysvětleny v dalším textu.
Vznik programovacího jazyka FORTH
Programovacímu jazyku Forth jsme se již na stránkách Rootu kdysi věnovali v samostatném seriálu, ovšem neuškodí krátká rekapitulace. Tento jazyk, který je založený na konceptu dvou zásobníků (jeden je používaný pro operandy a druhý pro uložení návratových adres volajících funkcí), je známý mj. i tím, že jeho implementaci lze v nejjednodušší variantě provést v několika stovkách bajtů paměti, tj. přibližně s 300 až 500 strojovými instrukcemi a navíc se některé dialekty Forthu provozovaly bez použití operačního systému (Forthovské jazyky byly součástí i několika BIOSů). V takto malém počtu instrukcí bude složité uložit jakákoli nebezpečná zadní vrátka. Na druhou stranu je nutné poznamenat, že Forth tvoří svůj velmi zajímavý, ale dosti izolovaný svět, takže v něm pravděpodobně nikdy nevznikne překladač C ani dalšího vyššího programovacího jazyka (typicky se ovšem Forth spojuje s assemblerem, což je ostatně i logičtější).
Obrázek 3: Uložení dvou hodnot na zásobník operandů, jejich součet a tisk výsledku.
V roce 1976 byla firma FORTH Inc. (jejímž zakladatelem byl Chuck Moore, tvůrce jazyka FORTH) požádána, aby Forth portovala na mikroprocesor CDP-1802 (mimochodem, tento procesor, určený pro vojenské a kosmické aplikace, měl velmi zajímavý instrukční soubor – viz například stránku Great Microprocessors of the Past and Present popř. článek RCA 1802: poslední mohykán osmibitové éry mikroprocesorů). Nový produkt byl nazván microFORTH a v dalších letech byl portován na celou skupinu vzájemně odlišných mikroprocesorů, zejména Intel 8080, Motorola 6800, MOS 6502 (což nás zajímá nejvíce) a Zilog Z80. Systém microFORTH byl s úspěchem použit pro vytváření průmyslových a řídicích aplikací, které využívaly právě tyto osmibitové mikroprocesory. Mnohé tyto systémy prý pracují až do dnešní doby.
Všechny výše zmíněné mikroprocesory jsou osmibitové a v průmyslových aplikacích byly osazeny operační pamětí o typické kapacitě 16 kB. Tyto aplikace byly spouštěny většinou z pamětí EPROM nebo PROM, protože disky se používaly pouze v minipočítačích. Ostatní firmy pro tyto mikroprocesory dodávaly buď pouze assembler, nebo jazyk PL/M (raději na něj zapomeňte), ostatní jazyky byly buď příliš náročné na systémové prostředky (C, Pascal), nebo nevhodné pro programování složitějších aplikací (BASIC). V této „konkurenci“ je jasné, že se Forth velmi dobře prosazoval, zejména jako náhrada assembleru.
Programovací jazyk Forth byl použit i na osmibitových domácích počítačích. Zde se významně projevila schopnost Forthu generovat krátký kód, který bylo možné zpracovat velmi jednoduchým interpreterem. Ten byl dlouhý pouze několik strojových instrukcí. Jednou z prvních aplikací Forthu v oblasti osmibitových počítačů byly některé systémové rutiny uložené v paměti ROM počítače ZX-81. Jednalo se o operace s hodnotami uloženými v pohyblivé řádové čárce. Pomocí Forthu byl vytvořen velmi krátký kód hojně používající smyčky a iterace. Běh rutin byl díky tomu pomalý, proto byl v dalších počítačích firmy Sinclair Research použit kód psaný přímo v assembleru, který však byl delší.
Osmibitové počítače, a to včetně osmibitových domácích mikropočítačů Atari, ještě v době svého největšího rozmachu zažily vznik oblíbeného fig FORTHU (byl odvozen od Forthu-78 a taktéž od výše zmíněného microFORTHu), jehož autoři si kladli za cíl vytvořit standard mezi různými dialekty Forthu i mezi různými mikroprocesorovými architekturami (například pro Intel 8080). A právě fig-FORTHem se budeme ve stručnosti zabývat v této kapitole. fig-FORTH byl portován i na mikroprocesory MOS 6502, takže další přenos na počítače Atari (ale i na BBC Micro, či Commodore C64) byl relativně snadnou záležitostí.
fig-FORTH byl na Atari vybaven editorem jednotlivých obrazovek (screen), který se ovládal podobně jako Vi či spíše Ed: zadávalo se vždy číslo řádku a operace, která se má provést. Podporována byla všechna slova (v jiných programovacích jazycích funkce) FIG Forthu a díky možnosti přímého přístupu do paměti bylo možné manipulovat s čipy ANTIC, GTIA i POKEY a využít tak i multimediálních možností počítačů Atari. Ostatně prakticky celý manuál FIG Forthu se skládá z popisu jednotlivých slov.
Obrázek 4: Načtení kódu editoru, který začíná na obrazovce 27.
FORTH a další programovací jazyky
Klasické jazyky, které leží v céčkovské (resp. přesněji řečeno v Algolské) generační větvi, se vyznačují tím, že striktně oddělují výrazy a příkazy. Funkce jsou také považovány za něco odlišného od datových typů. V LISPovských programovacích jazycích (sem spadá Clojure) jsou naopak výrazy, příkazy a funkce z hlediska konstrukce totožné. Funkce jsou totiž považovány za běžný datový typ (datové typy jsou samozřejmě v LISPovských jazycích používány, ale odlišným způsobem: proměnná nemá typ, ale hodnota ano. Ve skutečnosti je interně každá proměnná pouze referencí, což zjednodušuje práci s pamětí).
Forth se v některých svých vlastnostech i původem přibližuje programovacímu jazyku Go. Oba dva jazyky byly vytvořeny pro praktické použití, proto také jejich návrh není zdaleka tak „čistý“, jako je tomu u jazyků vytvořených v akademických institucích, jakými jsou například Haskell, LISP, Pascal nebo jeho předchůdce Algol. To je v některých ohledech výhodné (možnost vytváření kompaktních a elegantních algoritmů), ale při programování komplikovanějších a rozsáhlejších systémů to může přinášet praktické potíže.
Forth však nebyl vytvořen s ohledem na to, aby napravil chyby či nedostatky některého jiného programovacího jazyka, ale aby dovoloval psát kompaktní a snadno odladitelné programy. Z minulosti známe celou řadu takových „upgrade“ programovacích jazyků, například Algol->Pascal, C->C++, C+±>Java nebo C->C# (hmm, možná by sem patřil i Rust). Forth je prostě odlišný, což je z hlediska programátora, který přechází z jiného jazyka, nevýhodné, protože se musí naučit přemýšlet o výstavbě svých programů dosti odlišným způsobem.
Mezi největší nevýhody Forthu patří z tohoto hlediska postfixová notace zápisu matematických operací a řídicích příkazů, která mnoha programátorům zpočátku vadí. Stejnou notaci však používá i PostScript (který ostatně z Forthu vychází), takže jednou naučené zvyky je možné uplatnit i v oblasti DTP apod. Druhou nevýhodou je, že za Forthem nestála a dosud nestojí žádná opravdu silná firma, která by ho aktivně propagovala. Open source komunita je orientovaná spíše do oblasti serverů a výkonných osobních počítačů, Forth je však vhodný zejména pro embedded systémy, PDA, mobilní telefony apod. (a z tohoto důvodu našel své místo i na domácích osmibitových mikropočítačích).
Zásobníkové programovací jazyky a RPN
If you're a frequent calculator user, you owe it to yourself to investigate the advantages of RPN. RPN stands for Reverse Polish Notation. Reverse Polish Notation was developed in 1920 by Jan Lukasiewicz as a way to write a mathematical expression without using parentheses and brackets. Hewlett-Packard Co., realizing that Lukasiewicz's method was superior to standard algebraic expressions when using calculators and computers, adapted RPN for its first hand-held scientific calculator, the HP35, in 1972.
Hewlett-Packard Development Company The RPN Method: An Overview and History
Programovací jazyk Forth, ale například i programovací jazyky Factor a Joy, jsou založeny na použití dvou zásobníků. První z těchto zásobníků se nazývá zásobník operandů (operand stack), druhý zásobník návratových adres (return stack). Většina matematických operací je prováděna buď s jedním operandem (uloženým na vrcholu zásobníku operandů, což je místo označované zkratkou TOS neboli Top Of Stack) nebo s dvojicí operandů (první je uložený v TOS, druhý těsně pod prvním operandem). Funkce zásobníku návratových adres je zřejmá – obsahuje adresy, na které se má řízení programu vrátit při opuštění právě prováděné funkce (a jak uvidíme dále, ukládají se sem i počitadla smyček atd.).
Obrázek 5: Zásobník je struktura typu LIFO, což je patrné z toho, že nejdříve je vypsána naposledy uložená hodnota.
Infixová vs. postfixová notace
Výše zmíněné programovací jazyky taktéž používají prakticky totožnou syntaxi pro vytváření nových slov (funkcí) i postfixovou notaci (RPN – Reverse Polish Notation) pro zápis matematických a logických výrazů.
Už na základní škole se však každý člověk učí infixovou notaci zápisu, ve které se operátory zapisují mezi operandy. Vzhledem k prioritě operátorů je však nutné v infixové notaci používat závorky. Rozdíl mezi následujícími dvěma výrazy uvedenými v infixové notaci je snad zřejmý:
a+b*c (a+b)*c
Při použití postfixové notace nejsou závorky zapotřebí, protože se priorita operací vyjadřuje přímo posloupností operátorů. Výše uvedené výrazy lze tedy do postfixové notace přepsat následovně:
a b c * + nebo též b c * a + a b + c * nebo též c a b + *
Následuje několik příkladů zápisu aritmetických výrazů v postfixové notaci, jenž je oběma jazyky používána (a nejenom jimi – viz například tradiční prastará a stále existující a využívaná Unixová utilita dc nebo jazyk pro popis tiskových stran PostScript):
| Zápis výrazu v RPN | Infixový ekvivalent | Výsledek |
|---|---|---|
| 1 2 + | 1 + 2 | 3 |
| 1 2 3 * – | 1 – 2 * 3 | –5 |
| 1 2 * 3 – | 1 * 2 – 3 | –1 |
| 1 2 + 3 4 + * | (1 + 2) * (3 + 4) | 21 |
| 4 3 2 1 + + * | (1 + 2 + 3) * 4 | 24 |
Otestujme si RPN zápis ve fig-FORThu (výsledky jsem obarvil v grafickém editoru, aby se v textu neztratily):
Obrázek 6: Interaktivní výpočty založené na RPN.
Přednosti a zápory RPN oproti infixové notaci
Jaké jsou však výhody postfixového zápisu výrazů oproti zápisu infixovému? Mezi základní přednost patří absence závorek, pomocí nichž se v infixové notaci mění priority operací (a které zde hrají nezastupitelnou roli). Priorita je totiž v postfixové notaci velmi intuitivně určena pozicí operátoru či funkce ve výrazu.
Mezi druhou výhodu patří, možná poněkud překvapivě, konzistence zápisu. Ve skutečnosti se v běžně používané infixové notaci zapisují pouze některé základní matematické operace, mezi než patří součet, součin, rozdíl a podíl. Další operace se zapisují pomocí funkcí v de facto prefixové notaci (například sinus, odmocnina, logaritmus, minimum) a některé dokonce v notaci postfixové (například faktoriál).
S využitím postfixové notace je možné zapisovat všechny operace i funkce, dokonce ani nezáleží na počtu operandů (stírá se rozdíl mezi unárními, binárními, ternárními apod. operacemi). Ve skutečnosti není v postfixové notaci prakticky žádný rozdíl mezi operacemi a funkcemi, takže pro ně není nutné zavádět nějaká zvláštní syntaktická pravidla.
Důsledkem výše uvedených skutečností je fakt, že znaky běžně používané pro operátory je možné použít pro jiné účely, podobně jako například v jazycích LISP nebo Scheme (což jsou mimochodem jazyky používající prefixovou notaci).
Aritmetické operace se ve Forthu zapisují přesně podle infixové notace s tou podmínkou, že jednotlivé operátory od sebe musí být odděleny mezerou, znakem tabelátoru či znakem pro konec řádku. Příklad zápisu některých aritmetických operací a jejich kombinací:
10 20 + 10 20 * 10 20 - 10 20 + 30 * 5 4 3 2 1 * / + -
Význam výše uvedených operací ve Forthu je následující: samotný zápis čísla znamená, že se toto číslo uloží na zásobník operandů. Zápis operátoru způsobí, že se operandy vyberou ze zásobníku, provede se s nimi požadovaná operace a výsledek se uloží zpět na zásobník. Vzhledem k tomu, že všechny zmíněné operace jsou binární (akceptují dva operandy), vyberou se ze zásobníku dvě hodnoty a zpět se zapíše pouze jediná hodnota, tj. počet položek na zásobníku se o jednu sníží. (Malé cvičení – jaký je výsledek poslední sekvence operací?).
To si můžeme ilustrovat na následujícím diagramu, kde na levé straně od pomlček jsou naznačeny významné položky na vrcholu zásobníku před provedením operace a na pravé straně od pomlček je uveden stav zásobníku po provedení operace. Tento diagram se nazývá stack diagram a hojně se vyskytuje ve zdrojových textech programů psaných ve Forthu, v manuálech Forthu atd. (do určité míry nahrazuje hlavičky funkcí):
(x y -- x+y)
Výpis numerické hodnoty uložené na vrcholu zásobníku operandů
Po spuštění některého interpretru Forthu, v našem případě fig-FORTHu, je možné ihned (podobně jako u klasických RPN kalkulaček společnosti HP) zapisovat aritmetické operace v postfixové notaci s využitím známých operátorů + - * a /. Pouze potřebujeme znát příkaz, kterým je možné vypsat hodnotu na vrcholu zásobníku. Tento příkaz je velmi jednoduchý a už jsme jej použili na screenshotech – jedná se o prostou tečku: ., kterou je však nutné od ostatních příkazů oddělit alespoň jednou mezerou nebo jiným „bílým“ znakem.
Zásobníkový diagram tohoto příkazu je velmi jednoduchý, protože dochází k vyjmutí prvku uloženého na vrcholu zásobníku:
(n -- )
Po zadání příkazu tečka se přečte hodnota uložená na vrcholu zásobníku a zapíše se na standardní výstup. Současně je hodnota ze zásobníku odebrána, takže se počet uložených položek o jednotku sníží. Pokud je tento příkaz zavolán na prázdný zásobník, znamená to chybu, kterou by měl interpretr ohlásit (fig-FORTH ovšem reaguje poněkud chaoticky). Příklady použití:
10 . 10 20 + . 10 20 30 * + . 10 20 * 30 + .
Všimněte si, že všechny výše zmíněné operace pracují se zásobníkem korektně, tj. po jejich provedení je zásobník zcela vyprázdněn. Při programování ve Forthu je důležité, aby na zásobníku nezůstala žádná zbytečná data, neboť to ve většině případů značí nesprávně napsanou operaci či funkci. Kód je možné upravit libovolným způsobem, vždy se však musí dodržet podmínka, že operandy a operátory musí být odděleny „bílým“ znakem:
10 20 + . 10 20 + . 10 20 + . 10 20 + .
Základní operace prováděné s hodnotami uloženými na zásobníku operandů
Vzhledem k tomu, že zásobník operandů tvoří ve Forthu ústřední místo veškerého dění, je zapotřebí mít k dispozici i další operace, které mohou manipulovat s datovými položkami na zásobníku uloženými. V některých případech nám totiž nemusí vyhovovat pořadí položek uložených na zásobníku, položky je nutné kopírovat (duplikovat), mazat apod. Z tohoto důvodu má jazyk Forth implementovány následující základní operace (slova) nad zásobníkem, resp. nad jeho obsahem:
| Slovo | Popis manipulace se zásobníkem | Stručný popis |
|---|---|---|
| SWAP | ( n1 n2 — n2 n1 ) | prohození dvou prvků na vrcholu zásobníku a těsně pod vrcholem zásobníku |
| DUP | ( n — n n ) | duplikace obsahu prvku na vrcholu zásobníku |
| DROP | ( n — ) | odstranění prvku z vrcholu zásobníku |
| OVER | ( n1 n2 — n1 n2 n1 ) | duplikace obsahu prvku POD vrcholem zásobníku |
| ROT | ( n1 n2 n3 — n2 n3 n1 ) | rotace tří prvků umístěných na nejvyšších třech místech zásobníku |
Slovo SWAP
S využitím tohoto slova se provede prohození nejvyšší a druhé nejvyšší datové položky (což jsou nejčastěji celočíselné hodnoty) uložené na zásobníku. Pokud byly na zásobníku operandů například uložena čísla 1 a 2, je po provedení tohoto slova na nejvyšších dvou pozicích zásobníku uložena posloupnost 2 1. Následuje jednoduchý příklad použití tohoto slova.
Uložení dvou čísel na zásobník a jejich následný výpis na obrazovku, spolu s odřádkováním pomocí slova cr:
1 2 . . cr
Uložení dvou čísel na zásobník, provedení slova swap a následný výpis čísel na obrazovku:
1 2 swap . . cr
Vše si samozřejmě můžeme ověřit na reálném osmibitovém mikropočítači Atari s fig-FORTHem:
Obrázek 7: Slovo SWAP prohodí dva nejvyšší prvky na zásobníku operandů.
1 SWAP . .
Slovo DUP
S využitím vestavěného slova dup se provede kopie (duplikace) hodnoty uložené na vrcholu zásobníku. Velikost zásobníku se tedy o jednotku zvětší. Toto slovo se využívá v mnoha případech, například pro přípravu na matematickou operaci násobení dvěma, umocnění, předání parametru na zásobník návratových adres apod. Opět následuje ilustrační příklad použití této operace:
1 dup . . cr
A pochopitelně si vyzkoušejme, jak se toto slovo chová ve fig-FORTHu:
Obrázek 8: Slovo DUP na zásobník uloží kopii prvku z původního vrcholu zásobníku operandů.
Slovo DROP
Logickým opakem standardního slova dup je slovo drop, pomocí něhož se odstraní položka z vrcholu zásobníku. Toto slovo, jež se často používá při „úklidu“ po nějaké složitější operaci, je podobné slovu . (tečka), avšak s tím rozdílem, že neprovádí výpis hodnoty odstraňované položky. Příklad použití:
1 2 drop . cr
Ověření funkcionality ve fig-FORTHu je snadné:
Obrázek 9: Slovo DROP odstraní prvek z vrcholu zásobníku operandů.
V případě, že je zásobník prázdný, mohou slova DROP nebo . způsobit problémy (jejich chování není v takovém případě definováno; problém ve skutečnosti vznikne až po spuštění slova .):
Obrázek 10: Pokus o tisk prvku, který neexistuje, nedopadne dobře.
Slovo OVER
Další standardní slovo určené pro manipulaci s prvky na zásobníku se jmenuje over. Toto slovo se podobá výše popsanému slovu dup, tj. provádí se kopie hodnoty uložené na zásobníku. V tomto případě se však jedná o hodnotu uloženou pod vrcholem zásobníku, nikoli o hodnotu uloženou přímo na vrcholu zásobníku. Chování tohoto slova se nejlépe předvede na jednoduchém příkladu, který porovná význam operací over a dup. Na zásobník je nejdříve uložena hodnota 1 a poté hodnota 2 (ta je tedy uložena na vrcholu zásobníku):
1 2 dup . . . cr 1 2 over . . . cr
2 2 1 1 2 1
Ověření funkcionality tohoto standardního slova ve fig-FORTHu ve variantě pro osmibitové domácí mikropočítače Atari:
Obrázek 11: Interaktivní ověření operace prováděné slovem OVER. Hodnota 2 je přečtena z druhého místa na zásobníku a zduplikována na jeho vrcholu.
Slovo ROT
Další standardní slovo se jmenuje rot. To je zvláštní tím, že manipuluje hned se třemi položkami uloženými na zásobníku. Jak již název tohoto slova napovídá, provádí se rotace položek a to tak, že datová položka na třetí nejvyšší pozici v zásobníku operandů je vyjmuta a uložena na jeho vrchol. Opět je vhodné si vyzkoušet jednoduchý příklad, nejprve výpis tří položek bez rotace:
1 2 3 . . . cr
A následně s rotací:
1 2 3 rot . . . cr
Výsledky by měly vypadat následovně:
3 2 1 1 3 2
Obrázek 12: Operace prováděná slovem ROT.
Pro manipulaci s datovými položkami, které jsou na zásobníku uloženy ve větší hloubce než tři, je možné ve většině implementací Forthu (ovšem nikoli ve fig-FORTHu bez načtení příslušné obrazovky) použít slova nazvaná pick a roll. Jedná se v podstatě o selektory podobné indexům do polí u jiných programovacích jazyků – pokud se ovšem na zásobník díváme jako na dynamicky alokované pole s proměnnou velikostí. V reálných programech se však tato slova nevyskytují a jejich použití ani není doporučováno, protože neodpovídá programovacímu stylu používanému ve Forthu. Pokud je zapotřebí získat či uložit informace do dalších míst na zásobníku, je možné využít zásobník návratových adres (return stack) nebo použít proměnných pro uložení dočasných hodnot. Většinou však potřeba zásahu do hloubky zásobníku vychází ze špatného návrhu programu.
Obrázek 13: Vícenásobné zavolání slova ROT.
Definice nových slov
V programovacím jazyku FORTH se namísto funkcí, aritmetických, logických, relačních atd. operací a řídicích struktur používají pouze takzvaná slova. Ta mohou manipulovat s obsahem obou zásobníků a popř. i zapisovat či číst data do/z paměti (typicky přes proměnné). Slova se při jejich definici zadávají z klávesnice nebo ze vstupního souboru a jsou určena svým jménem (v tomto ohledu se podobají běžným funkcím). Jméno slova může ve FORTHu obsahovat libovolný řetězec znaků, který je oddělen (ukončen) mezerou nebo v novějších verzích libovolným „bílým znakem“. Každé volání slova je ve forthovském programu nahrazeno jménem slova bez dalších znaků (závorek apod.), protože veškeré parametry slova i případná návratová hodnota nebo hodnoty jsou uloženy na zásobníku operandů.
Obrázek 14: SWAP, DUP, DROP, OVER i ROT lze zavolat i nad prázdným zásobníkem, ovšem výsledek není obecně definován.
Ve FORTHu jsou rozeznávány tři typy slov: definovaná slova, nedefinovaná slova a číselné konstanty. Základní (řekněme vestavěná) slova, například operace se zásobníkem popsané v předcházejících kapitolách, jsou většinou vytvořena přímo s využitím operací napsaných v assembleru.
Uživatelem resp. programátorem definovaná slova jsou ukládána do slovníku (dictionary), který je většinou implementován formou lineárního seznamu nebo zásobníku (spíše ale seznamu). V multiuživatelských systémech má každý uživatel k dispozici svůj slovník, přičemž existuje ještě slovník společný. To však není případ fig-FORTHu, který je interně mnohem jednodušší.
První krok, který se před spuštěním Forthovských aplikací provádí, je rozklad řetězců, které jsou zadané uživatelem nebo načtené z datového zařízení (na PC z pevného disku, paměti EPROM apod., u Atari z diskety), do jednotlivých slov, což je operace triviální (na rozdíl od prakticky všech ostatních programovacích jazyků, které mají složitější syntaxi), protože za slova je považován souvislý řetězec oddělený bílými znaky. Tomu, kdo psal lexikální analyzátory pro jazyky podobné C-čku či Pascalu, je zřejmé že napsání základní lexikální analýzy pro Forth je otázka několika řádků kódu (resp. doslova několika desítek strojových instrukcí).
Každé slovo v řetězcové podobě je následně vyhledáno ve slovníku. Pokud je nalezeno, je proveden (spuštěn) jeho kód (slovo je v paměti uloženo jako seznam ukazatelů na další slova nebo primitivní operace). Pokud slovo ve slovníku nalezeno není, je považováno za číslo, které je po převodu do binární podoby uloženo na zásobník. V případě, že převod na číselnou konstantu z nějakého důvodu selže, znamená to, že jde o neznámé slovo, a proto interpret nahlásí chybu. Zde je opět vidět syntaktická jednoduchost jazyka, který rozeznává pouze slova a numerické hodnoty (operandy a řídicí struktury jsou také slova).
Pro vytváření nových slov se používají pouze dvě zabudovaná slova. Prvním slovem je : (dvojtečka) a druhým slovem je ; (středník). Po zadání dvojtečky se interpretr Forthu přepne z režimu Execute (přímého vykonávání zadávaných příkazů) do režimu Compile (překlad nového slova). Naopak, po zadání středníku se interpretr přepne z režimu Compile do režimu Execute (samotný středník se přitom překládá jako return). Za slovem dvojtečka musí následovat jméno nového slova (což si hlídá část interpretru pracující v režimu Compile).
Nově vytvořená slova se chovají stejným způsobem jako slova zabudovaná, tj. jejich parametry se vybírají ze zásobníku operandů a výsledek je taktéž uložen na zásobník operandů. V tom spočívá jedna z elegantních vlastností Forthu, kdy je vytváření a volání slov velmi jednoduché a rychlé. Ukažme si vytvoření nového slova print, které vytiskne hodnotu uloženou na vrcholu zásobníku a potom kurzor přesune na nový řádek:
: print . cr ;
Slovo print, které musí být od slova dvojtečky odděleno bílým znakem, tedy vytiskne hodnotu uloženou na vrcholu zásobníku (to zajistí volání zabudovaného slova tečka) a potom provede odřádkování pomocí interního slova cr. Středník ukončí kompilaci nového slova a vrátí řízení zpátky do režimu Execute. Můžeme ihned provést několik interaktivních testů s nově vytvořeným slovem:
10 print 1 2 + print 1 2 3 * - print
Vzhledem k tomu, že je tělo slova print velmi krátké, můžeme ho zapsat i na jeden řádek (což ušetří cenné bajty na disketě):
: print . cr ;
Příkladem složitějšího slova může být například mocnina. Toto slovo vezme ze zásobníku hodnotu a na zásobník vrátí její druhou mocninu. Slovo může vypadat následovně:
: mocnina dup * ;
Nejdříve se tedy provede duplikace hodnoty na vrcholu zásobníku. Poté se obě (shodné) hodnoty ze zásobníku vyjmou, vynásobí a na zásobník se uloží výsledek operace násobení. Použití tohoto slova je opět velmi jednoduché:
2 mocnina . cr 10 mocnina print
(na druhém programovém řádku používáme dříve vytvořené slovo print)
Příklad definice a otestování nového slova ve fig-FORTHu
Vyzkoušejme si nyní definici i otestování nového slova ve fig-FORTHu. Opět si připomeňme, že FORTH je plně interaktivní prostředí (podobně jako BASIC), ve kterém lze nově definovaná slova ihned otestovat, volat tato slova z jiných slov atd. atd. Uvedeme si velmi jednoduchý příklad – slovo, které vynásobí předanou hodnotu dvěma. Jak parametr, tak i výsledek, se předávají implicitně přes zásobník:
Obrázek 15: Definice nového slova pro vynásobení hodnoty na vrcholu zásobníku dvěma.
Obrázek 17: Ve skutečnosti lze vynásobení dvěma nahradit součtem, což je minimálně v případě mikroprocesoru MOS 6502 mnohem efektivnější operace. Povšimněte si, jak se jednotlivá slova spouští postupně.
Obrázek 18: Otestování nové varianty slova DOUBLE.
Programové smyčky
Programovací jazyk FORTH patří v mnoha ohledech mezi nízkoúrovňové programovací jazyky. Tyto programovací jazyky jsou mimo jiné charakteristické častým používáním počítaných a nepočítaných programových smyček. U jazyků vyšší úrovně, zejména jazyků funkcionálních, se spíše setkáváme s použitím rekurze a konstrukcí typu foreach (tj. vlastně skrytých programových smyček).
Jedním ze základních typů cyklů ve Forthu je smyčka typu do-loop. Jedná se o počítanou programovou smyčku, která zhruba odpovídá smyčce for známé například z Pascalu, Fortranu či Basicu. Podobnost klíčových slov pro smyčku do-loop ve Forthu a C-čku sice svádí k jejich záměně, ale v céčku se jedná o obecnější nepočítanou smyčku s podmínkou, která se hodí pro poněkud jiné operace než její Forthovská příbuzná.
Inicializace smyčky do-loop je jednoduchá. Na zásobník operandů se nejprve uloží dvě hodnoty. První hodnotou se specifikuje mezní hodnota, jejíž překročení (při zvýšení nebo snížení počitadla) vede opakování smyčky, druhou hodnotou (tj. hodnotou uloženou na vrcholu zásobníku) pak počáteční hodnota.
Příkazy, které se mají ve smyčce opakovat, jsou umístěny uvnitř „příkazových závorek“ specifikovaných slovy do a loop. Smyčka probíhá tak, že se aktuální hodnota počitadla ukládá na zásobník návratových adres (return stack), na konci smyčky je pak tato hodnota přesunuta na zásobník operandů, kde je počitadlo porovnáno s koncovou hodnotou. Z toho vyplývá, že smyčka proběhne alespoň jednou, podobně jako smyčka typu do-while v céčku nebo repeat-until v Pascalu.
Nejjednodušší forma smyčky do-loop, která se má opakovat devětkrát, vypadá následovně:
10 1 do loop
Jak je z předchozího úryvku kódu patrné, bude se smyčka provádět devětkrát, přičemž první hodnota počitadla bude rovna jednotce.
Uvnitř smyčky je možné používat speciální klíčové slovo i (nejedná se o název proměnné, ale o skutečné slovo), pomocí kterého se na zásobník operandů uloží aktuální hodnota počitadla smyčky. Pokud by tedy měla smyčka proběhnout devětkrát a postupně vypisovat hodnotu počitadla, může celý kód vypadat následovně:
: smycka1
10 1 do
i . cr
loop
;
Jak je z předchozího programu patrné, vytvořili jsme nové slovo smycka1, po jehož zavolání se smyčka devětkrát provede a vypíše všechny hodnoty počitadla. Připomínám, že slovo . (tečka) slouží k výpisu hodnoty uložené na vrcholu zásobníku a slovo cr provede přechod na nový řádek.
Výše vytvořené slovo smycka1 však není příliš flexibilní, výhodnější by bylo vytvořit slovo, které provede smyčku n-krát s různou počáteční hodnotou. To je možné provést jednoduchou úpravou kódu:
: smycka2
do
i . cr
loop
;
Před provedením nově vytvořeného slova smycka2 je nutné na zásobník vložit počet opakování smyčky a počáteční hodnotu. Celé volání může vypadat například takto:
10 1 smycka2
Všimněte si velké jednoduchosti vytvoření nového slova a způsobu předávání parametrů přes zásobník. Nikde není zapotřebí pojmenovávat parametry, vytvářet lokální proměnné ani používat závorky. Tento způsob předávání parametrů pracuje samozřejmě pouze v případě, že se využívají čísla typu integer. V případě použití jiných datových typů (například reálných čísel) je nutné pracovat se zásobníkem nepřímo pomocí slov pro zpracování dalších datových typů (a to původně velmi elegantní kód může znepřehlednit).
Příklad realizace programové smyčky ve fig-FORTHu
Opět si vyzkoušíme zápis programové smyčky typu do-loop ve fig-FORTHu. Smyčky budou definovány uvnitř (nových) slov, což zjednoduší jejich spouštění. To se pochopitelně provede zavoláním příslušného slova a popř. předáním parametrů přes zásobník operandů:
Obrázek 19: Slovo, které spustí počítanou programovou smyčku.
Obrázek 20: Otestování programové smyčky.
Obrázek 21: Slovo, kterému je nutné předat počáteční a koncovou hodnotu počitadla smyčky.
Obrázek 22: Slovo, které přesune počitadlo ze zásobníku návratových adres a poté vytiskne jeho hodnotu.
Obrázek 23: Otestování třetí varianty počítané programové smyčky.
Obrázek 24: Odřádkování je realizováno slovem CR.
Další typy programových smyček
Místo slova do je možné v některých dialektech FORThu použít i slovo ?do, při jehož vyvolání se nejprve provede test, zda se nerovná hodnota indexu a počáteční hodnoty. Pokud dojte k rovnosti, smyčka se neprovede a běh programu pokračuje až za slovem loop. Následující dva řádky tedy budou mít zcela odlišný efekt:
10 10 do i . cr loop 10 10 ?do i . cr loop
Ve Forthu je však možné použít i nepočítané smyčky, tj. smyčky, u kterých není předem známý počet opakování. V takové smyčce proto musí být při každé iteraci testována nějaká podmínka a na základě jejího výsledku musí být rozhodnuto, zda se má smyčka opakovat či ukončit.
Pro tvorbu prvního typu nepočítaných smyček, kdy se podmínka pro ukončení smyčky testuje ještě před první iterací, se používají slova begin, while a repeat. Způsob jejich použití ilustruje následující kód:
begin
podmínka
while
tělo smyčky
repeat
Kde podmínka značí hodnotu uloženou na vrcholu zásobníku. Při každé iteraci se podmínka vyhodnotí a na základě výsledku vyhodnocení (tj. hodnoty true či false) se smyčka buď provede, nebo se z ní vyskočí. Následuje jednoduchý příklad použití, kdy vytvořený program vypíše čísla od 1 do 10:
: pocitadlo
0
begin
dup 10 <
while
1 +
dup . cr
repeat
drop
;
Obrázek 25: Definice slova POCITADLO.
Obrázek 26: Zavolání slova POCITADLO.
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.atari800xl.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/800xl-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
https://www.atarimania.com/documents/atari-action-reference-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! - Deep Blue C Compiler
https://www.atarimania.com/games/atari-400-800-xl-xe-utilities-deep-blue-c-compiler-12478 - DEEP BLUE C Manual
https://www.atariarchives.org/APX/showdocs.php?cat=20166 - C/65
https://www.atarimania.com/games/atari-400-800-xl-xe-utilities-c-65-19204 - Getting Started Programming in C: Coding a Retro Game with C Part 2
https://retrogamecoders.com/getting-started-with-c-cc65/ - CC65 Advanced optimizations
https://github.com/ilmenit/CC65-Advanced-Optimizations/tree/master/04-get%20rid%20of%20C%20stack - Bubble sort
https://en.wikipedia.org/wiki/Bubble_sort - Repositář projektu Fast Basic
https://github.com/dmsc/fastbasic - Fast Basic manual
https://github.com/dmsc/fastbasic/blob/master/manual.md - Fast Basic Cross Compiler
https://github.com/dmsc/fastbasic/blob/master/compiler/USAGE.md - Short description of all Atari Basic instructions
https://blog.3b2.sk/igi/Data/Atari/Basic/abasic.html - Revisiting a 1994 paper: When and why is RPN superior to algebraic? Hoffman et al.
https://www.youtube.com/watch?v=PBu7tpyttNY - What Happened to the HP-48? Why It Lost the Classroom to a Simpler TI
https://www.youtube.com/watch?v=05IupxOjwak - Why Does Wall Street Still Use the HP-12C? HP Has Sold It Since 1981
https://www.youtube.com/watch?v=2qUUKc2YFEA - Reverse Polish Notation: Types of Mathematical Notations & Using A Stack To Solve RPN Expressions
https://www.youtube.com/watch?v=qN8LPIcY6K4 - Stack manipulation operators
https://www.forth.com/starting-forth/2-stack-manipulation-operators-arithmetic/
