6502 – Ahoj, světe…

Nastala chvíle, kdy křemík ožije a provede, co po něm chceme. Tedy aspoň ten virtuální…

U 8080 to bylo prosté – nabídnul jsem PMD-85, k němu mám i emulátor, takže nebyl problém. U 6502 by šlo využít třeba Atari nebo Commodore C64, problém je, že k nim emulátor nemám. Zato mám emulátor jednodeskového počítače SBC6502 od Granta Searla. Jeho počítač je extrémně jednoduchý, tvoří ho, včetně procesoru, sedm integrovaných obvodů a můžete si ho poskládat na nepájivém kontaktním poli, když na to přijde.

Grantův počítač obsahuje procesor 6502, u něho je generátor hodin, logika pro dekódování adres a sériový komunikační obvod ACIA 6850. Od adresy 0000h do adresy 7FFFh je 32 kB RAM. ROM má 16 kB a je na adresách C000h až FFFFh. V prostoru A000h – BFFFh je namapován sériový komunikační obvod, k němuž se ještě dostanu.

Grant do svého počítače použil Microsoft BASIC 6502 (od adresy C000h) a k němu přidal rutiny pro komunikaci přes sériový port. Počítač je tak možné připojit k sériovému portu u PC (třeba i pomocí převodníku RS232-USB) a komunikovat s ním pomocí terminálu (Hyperterminal, PuTTY atd.) Já jsem do emulátoru napsal i emulaci terminálu, takže nemusíte nic s ničím spojovat a všechno funguje v prohlížeči. Můžete si vyzkoušet emulátor SBC6502 se zabudovaným BASICem.

Ale co když nebude BASIC? Jak oživit takový holý počítač? Začneme výpisem obligátního HELLO WORLD. K tomu ale budeme muset nějak ovládat ten komunikační obvod… Naštěstí to není složité, a tak si aspoň ukážeme, jak v takových chvílích postupovat.

Co máme? Máme typ obvodu – 6850. ACIA je zkratka (Asynchronous Communications Interface Adapter), která říká, že se jedná o komunikační rozhraní. Výrobce je Motorola (a další), obvod je z rodiny podpůrných obvodů procesoru 6800. Chvilku poGooglíme a najdeme takzvaný datasheet. Datasheet je materiál, dodávaný výrobcem čipu, kde jsou popsány veškeré důležité skutečnosti – od napájecího napětí přes popis vývodů a pouzdra až k programátorskému rozhraní. naštěstí ho nemusíte číst, přečetl jsem ho za vás, a tady jsou shrnuty základní informace – vynechám to, co je pro nás nepodstatné (řízení spojení pomocí signálů RTS, CTS apod. nebo přerušení)

ACIA 6850

Obvod 6850 je sériový komunikační obvod. (Datasheet, programátorský popis) Je připojen k procesoru a jeho hlavním úkolem je převést zaslaný bajt na sériový signál standardu RS-232 (tj. správně odvysílat start bit, datové bity, případně paritní bit, a nakonec stop bit) a opačně, tj. načíst správně časovaný sériový signál a připravit ho k předání procesoru.

Asynchronní v popisu znamená, že spolu s daty není přenášen hodinový signál ani není činnost přesně časována – když přijde bajt, je vyslán, když přijdou vstupní sériová data, jsou načtena. Synchronizace, tj. to, že bude načteno opravdu to, co načteno být má, zajišťují právě start a stop bity – podle jejich správného průběhu pozná obvod, že jsou data v pořádku.

Vysílání dat po výstupu TXDATA (Tx = transmit) a příjem na vstupu RXDATA (Rx = receive) je časován pomocí systémových hodin. U Grantova počítače je systémový kmitočet roven 1,8432 MHz. Tento kmitočet je v ACIA vnitřně dělen, dělitel je programově nastavitelný. Grant používá dělení šestnácti, což znamená, že komunikační rychlost je 1843200 / 16 = 115200 bitů za sekundu (baud). Pokud jste někdy používali sériové rozhraní, víte, že 115200 je jedna z používaných komunikačních rychlostí.

Obvod 6850 s procesorem komunikuje pomocí osmibitové datové sběrnice (D0-D7), několika CS vstupů (CS = Chip Select), které určují, kdy se s obvodem komunikuje (CS0 = 1, CS1 = 1, CS2 = 0 – ve všech ostatních případech je datová sběrnice odpojena), vstupu E (Enable, obvod komunikuje jen pokud je E=1), vstupu R/W, který udává, zda se z obvodu čte (1) nebo se do něj zapisuje (0) a vstupu RS, který udává, jestli se čtou/zapisují data (1), nebo řídicí hodnoty (0).

Přístup k obvodu má pak určitá pravidla toho, jak mají a mohou po sobě jednotlivé signály následovat, za jak dlouho po přivedení signálu jsou připravená data apod. Z hlediska programátora jsou tyto informace většinou (ne vždy!) irelevantní, protože o časování signálů se stará vnější logika. Někdy se ale nepostará, a pak je potřeba, aby např. programátor mezi posláním dvou hodnot nějakou chvíli počkal, ale to návrhář systému většinou zmíní.

Z hlediska programátora se tedy obvod 6502 jeví jako dva registry (vybrané pomocí vstupu RS), z nichž jeden je datový, druhý „systémový“. Funkci osvětlí tabulka:

Vstupy Registry
RS R/W Typ registru Funkce
0 0 Zápis Řídicí registr (Control Register, CR)
0 1 Čtení Stavový registr (Status Register, SR)
1 0 Zápis Data k vyslání (Transmit Data Register, TDR)
1 1 Čtení Přijatá data (Receive Data Register, RDR)

Grant Searle svůj počítač zapojil tak, že na adrese A000h je řídicí / stavový registr (CR/SR, podle toho, jestli se čte nebo zapisuje), na adrese A001h jsou datové registry. Vzhledem k tomu, že použil jen jednoduchý dekodér, tak se CR/SR objevuje i na adresách A002h, A004h, … až do BFFEh, datový pak na adresách o 1 vyšší (A001h, A003h, … BFFFh). Podobné „nedokonalé“ dekódování je poměrně časté – šetří to totiž „drahé“ součástky a nezbytnou logiku.

Všimněte si, že do řídicího registru je možné pouze zapisovat, nelze z něj číst, naopak stavový registr lze pouze číst, nelze do něj zapisovat. Není to totiž potřeba. Totéž s datovými registry – při čtení se čte to, co obvod přijal (a nezajímá nás to, co jsme odeslali). Při zápisu je jasné, že chceme data vyslat, nedávalo by smysl zapisovat do přijatých dat.

Řídicí registr CR

Osmibitový registr CR řídí čtyři funkce obvodu:

  • Bity 0 a 1 nastavují dělicí poměr hodin, viz výše.
    CR1 CR0 Dělitel
    0 0 1
    0 1 16
    1 0 64
    1 1 RESET

    Poslední kombinace nenastavuje dělitele, ale celý obvod resetuje do výchozího nastavení, tj. vyprázdní registry a nuluje příznaky. Grant používá kombinaci 01, tj. dělení 16. Kdyby použil kombinaci 10, tj. dělení 64, komunikoval by obvod rychlostí 28800 Bd.

  • Bity 2, 3 a 4 nastavují délku vysílaných a přijímaných dat (sedmibitové nebo osmibitové), zda se pracuje s paritou a kolik je stop bitů. Tyto informace najdete např. i v nastavení Hyperterminálu, když půjdete hledat detaily připojení. Pro naše účely použijeme kombinaci 101, tj. osmibitový přenos, bez parity, 1 stop bit.
  • Bity 5 a 6 určují, jestli vysílač po odvysílaném bajtu bude žádat o přerušení a v jakém stavu bude výstup RTS
  • Bit 7 určuje, jestli přijímač bude vyvolávat přerušení v případě chyby.

Pro bližší popis odkazuju zájemce opět k datasheetu, my použijeme hodnotu 15h, tj. osmibitový přenos, bez parity, přerušení zakázané a přenosová rychlost 115200 Baud (Baud je jednotka „bitů za sekundu“ – včetně start a stop bitů).

Stavový registr SR

Svět není dokonalý, život není fér a asynchronní sériové přenosy nejsou nijak sladěné s biorytmy našeho procesoru. Pokud pošlu bajt do 6850, začne ho obvod vysílat. Ovšem předtím je dobré podívat se, jestli už dokončil vysílání toho předchozího. Při příjmu je zase dobré se podívat, jestli nějaký bajt už načetl, a pokud ho načetl, tak ho zpracovat, aby se uvolnilo místo pro další bajt. Popřípadě získat informaci o tom, jestli nedošlo k chybě. Tyhle informace jako když najdete ve stavovém registru SR.

Pokud načtete bajt ze SR, tak vás jednotlivé bity informují o následujícím:

  • Bit 0 – Receiver Data Register Full (RDRF). Pokud je nastaven na 1, znamená to, že obvod načetl bajt po sériové lince do přijímače a bylo by záhodno ho zpracovat. Jakmile procesor přečte stav datového registru, je bit RDRF nastaven na 0. Nula znamená, že žádný nový bajt nepřišel.
  • Bit 1 – Transmitter Data Register Empty (TDRE). Jakmile zapíšete do datového registru bajt, nastaví se TDRE na 0 a obvod začne bajt vysílat po sériové lince. Jakmile ho vyšle, nastaví tento bit na 1. Programátor by se měl před tím, než nějaký bajt pošle, zkontrolovat, že může – tedy že bit TDRE = 1.
  • Bity 2, 3 pracují s řídicími signály CTS, DCD, a já je tady s klidným svědomím opomenu.
  • Bit 4 – Framing Error (FE) znamená, že přijatá data byla špatně časována, např. že nepřišel požadovaný STOP bit.
  • Bit 5 – Receiver Overrun (OVRN). Overrun, neboli hezky česky přeběh, je stav, kdy přijímač přijal bajt, ale procesor ještě nezpracoval předchozí přijatý. Ten nově přijatý je tedy zahozený (protože jej není kam dát, žádný vnitřní buffer není) a nastaví se OVRN na 1, aby bylo jasné, že došlo k chybě.
  • Bit 6 – Parity Error (PE). Pokud využíváme přenos s paritou, zkontroluje 6850 paritní bit. Pokud byl chybný, nastaví příznak PE.
  • Bit 7 – Interrupt Request (IRQ) říká, že obvod požádal o přerušení z nějakého závažného důvodu. Buď byl přijat bajt a je povolené přerušení při přijetí dat, nebo byl odeslán bajt a je povoleno přerušení při odeslání, nebo vypadla nosná (DCD).

Jak pracovat s 6850?

Na začátku musíme nastavit řídicí registr tak, jak potřebujeme. Už jsme si řekli, že to bude hodnota 15h. Tím je obvod nastaven a připraven k přijímání a vysílání dat.

Na začátku jsou pojmenované adresy ACIA (bázová adresa obvodu 6850 v Grantově počítači), ACIAControl, ACIAStatus a ACIAData. Vyhneme se tak programátorskému moru, „magickým konstantám“. (Syntaxe „návěští = hodnota“ je ekvivalentní zápisu „návěští EQU hodnota“, který jsme používali u 8080. Funkčně je to totéž, jen u asesemblerů 8080 je zvykem zápis s EQU, u 6502 zápis s rovnítkem.)

Do registru A uložím požadované řídicí slovo (15h) a instrukcí STA ho zapíšu na adresu ACIAControl (tj. A000h). Vzpomeňte si, že procesor 6502 nerozlišuje mezi pamětí a porty, obojí má v jednom adresním prostoru, takže používáme normální ibnstrukci pro zápis do paměti. Vnější logika Grantova počítače se postará o to, že data neskončí v paměti, ale tam, kde mají, tj. v obvodu 6850.

Co dál? Obvod je nastaven, teď je zapotřebí vypsat ono obligátní HELLO WORLD. Někde v paměti tedy bude tenhle řetězec a my ho budeme bajt po bajtu procházet a vysílat na sériový výstup.

Když se řekne „vysílat“, tak si na to uděláme podprogram. Bude se jmenovat třeba SEROUT (jako že SERial OUTput) a jeho funkce bude, že vyšle hodnotu v registru A. Předtím si ale zkontroluje, jestli je vysílač volný. Musí si tedy načíst hodnotu stavového registru SR a zkontrolovat bit 1. Pokud je nulový, musí počkat, až bude 1.

Na začátku si uložím obsah registru A. Mám v něm ten bajt, co chci vyslat, ale budu ten registr potřebovat, protože si do něj načtu hodnotu stavového registru. Takže si jeho hodnotu uložím na zásobník.

Na dalším řádku načtu hodnotu stavového registru do registru A (LDA). Pak provedu logický součin (AND) s hodnotou 2. Hodnota 2 totiž binárně vypadá takto: 00000010 – jsou to tedy samé nuly, jen na pozici bitu 1, který potřebuju testovat, je jednička. Výsledkem logického součinu bude buď hodnota 2, pokud je bit 1 nastaven, nebo 0, pokud je nulový.

Připomeňme si: pokud je bit 1 stavového registru nulový, znamená to, že obvod 6850 ještě vysílá předchozí data a my musíme počkat, dokud to nedokončí. Tedy pokud je (hodnota stavového registru AND 02) rovna nule, čekáme. A přesně to zajišťuje další instrukce BEQ. Vzpomeňte si – pokud je příznak Z=1 (tedy předchozí operace skončila s výsledkem 0), tak BEQ skáče. Tady se skáče opět na načtení stavového bajtu a vše se opakuje, dokud není výsledek nenulový. V tu chvíli už víme, že má 6850 volno a můžeme vysílat.

Pokud je tedy volno, přečteme si ze zásobníku zpět hodnotu, co byla původně v registru A a pomocí STA ji zapíšeme do datového registru 6850 – ACIAData.

Správná otázka je: Co se stane, když náhodou bude obvod 6850 vadný, nebo nebude zapojený správně a bude vracet pořád hodnotu 0? V takovém případě, ano, tušíte správně, jste právě vygenerovali nekonečnou smyčku, ve které se bude procesor točit do skonání věků – pardon, do vypnutí napájení, do RESETu nebo do přerušení.

Ještě to dát dohromady…

Už zbývá vlastně jen drobnost – vzít jednotlivé znaky onoho slavného nápisu a jeden po druhém vyslat po sériové lince ven.

Znaky zapíšeme do paměti pomocí pseudoinstrukce DB, která uloží hodnotu jednotlivých znaků jako jejich ASCII kód. Řetězec ukončíme hodnotou 0. Tím smyčka pozná, že je konec a že už je všechno vysláno. K adresaci použijeme indexový registr Y. Na počátku bude jeho hodnota 0 a po každém znaku se hodnota zvýší o 1. Pomocí adresního módu ABY (absolutní adresa, indexovaná s registrem Y) budeme načítat do registru A postupně jednotlivé znaky Slavného Nápisu a pak budeme volat SEROUT, aby je odeslal po sériové lince – tedy do terminálu, který je zobrazí.

Po načtení znaku je jednoduchý test: je-li načtený znak roven 0, tak instrukce LDA nastavila příznak Z na jedničku. Instrukce BEQ v takovém případě skočí na návěští DONE. Následuje volání podprogramu (JSR), zvýšení ukazatele (indexového registru Y) a pokud ještě není 0 (což by znamenalo, že se vyslalo 256 bajtů a jedeme znovu od začátku), tak se skáče na návěští LOOP, tedy na načtení bajtu z adresy (Message+Y).

Na návěští DONE je pak nekonečná smyčka, která de facto zastaví procesor. V reálném nasazení to asi nebude žádoucí, ale pro nás je dobré, aby procesor udělal, co udělat má, a pak nikde netrajdal a nedělal něco, co dělat nemá.

A to je všechno?

Ano, to je všechno. Celá ta nádhera vypadá takhle:

Krásné, že?

Možná vás zarazily dvě věci. Jednak že hexadecimální čísla zapisuju ne jako 0C000h, ale jako $C000. Je to ekvivalentní zápis, ale byl jsem, po právu, upozorněn, že zápis s $ na začátku je „klasičtější“ a snáze rozpoznatelný.

Druhá věc, co vás mohla zarazit, jsou kódy $0c, $0d a $0a u řetězce k výpisu. Jedná se o řídicí znaky pro terminál. 0C smaže celou obrazovku, 0D přesune kurzor na začátek řádku, 0A přesune kurzor na nový řádek.

Jak to otestovat? Nejjednodušší bude použít moje IDE ASM80.com, kde je k dispozici překladač i emulátor. Zkopírujte si výše uvedený zdrojový kód do okna editoru, uložte jej (vpravo tlačítko Save file as…) pod názvem „strojak1.a65“ (přípona .a65 říká překladači, že je použitý procesor 6502) a zkuste kliknout na Compile (nebo stisknout F9). Pokud je vše OK, vypíše se zpráva o úspěšném překladu a vlevo, v seznamu souborů, přibudou dva soubory strojak1.a65.hex a strojak1.a65.lst. Těch si teď všímat nemusíte a vesele můžete stisknout F10 (nebo kliknout na Emulator). Díky direktivě „.engine“, kterou jsme použili v kódu, se nespustí debugger, na jaký jsme zvyklí z ukázek kódu, ale rovnou emulátor počítače SBC6502, do paměti se uloží náš přeložený kód a spustí se.

(Místo kopírování do editoru můžete kliknout na tento odkaz: Přidat strojak1.a65 do workspace ASM80.com – tím se objeví v seznamu souborů. Pak ho můžete jednoduše otevřít kliknutím na jeho název v levém sloupci.)

A pokud vše fungovalo i u vás na jedničku, bude výsledkem něco takového:

sbcgoTak. Děkuju za pozornost u zatím snad nejdelšího článku, případné dotazy a připomínky prosím jako vždy do komentářů.

 

Líbil se vám článek? Podpořte autora na Patreonu
Příspěvek byl publikován v rubrice 6502. Můžete si uložit jeho odkaz mezi své oblíbené záložky.

7 komentáře u 6502 – Ahoj, světe…

  1. odpad napsal:

    Děkuji, líbí 😉

  2. Viktor Čech napsal:

    ahoj..sledujem, citam.. dobra stranka 🙂

  3. Noname napsal:

    Jak jsou řízeny vstupy RS a R/W ?

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *