7.4. CHIP-8

Roky 70. a 80. boli zlatou érou počítačov. Dobou, kedy sa inšpirovalo úspechmi iných a učilo z chýb tých druhých. Dobou, kedy ešte autorské práva nikto nebral tak vážne ako dnes, keď utečenci utekali z Československa (aj do Afriky) a auto vo svojich útrobách neukrývalo 7 km káblov. Dobou, kedy sa počítačovým odborníkom nemohol nazývať každý, kto dokáže z internetu nainštalovať Minecraft. Dobou, kedy programátori ovládali konštrukciu počítačov do posledného detailu, vedeli jeho silné stránky i slabiny, a oboje dokázali využiť pre dobré programy. Dobou, keď malý kúsok kódu vedel urobiť neuveruteľné veci. Dobou, kedy nikto neveril, že raz budú procesory taktované v GHz a pamäť sa bude merať v terabajtoch. A práve niekedy v týchto časoch navrhol Joseph A. Weisbecker (1932-1990) programovací jazyk CHIP-8 na jednoduchšie písanie programov pre videokonzoly.

CHIP-8 vznikol v 70. rokoch a bol určený takmer výlučne pre písanie hier. Po spustení na virtuálnom stroji dokáže bežať na akomkoľvek počítači, dokonca na akomkoľvek zariadení, ktoré spĺňa jednoduché podmienky, rozlíšenie zobrazenia 64x32 bodov a 16 kláves (v dnešnej dobe by mohli programy bežať na takmer každej kalkulačke ale aj na displeji kopírky či v každom televízore). Je to teda multiplatformný jazyk, akási predhistorická Java. Ak sa dnes chváli Java, že beží na 6 či 8 miliardách zariadení, tak CHIP-8 by tento počet dnes určite predbehol. Nielen, že beží na Jave samotnej, ale nepohrdne webovým Flashom, počítačmi s Windowsom či Linuxom, funguje na ZX Spectre či iných historických počítačoch, na kalkulačkách HP, ale je možné nájsť implementácie pre mikroporcesory PIC či x51.

Pri prvom pohľade sa CHIP-8 bude zdať ľahko podobný architektúre RISC. Minimum inštrukcií s pevnou dvojbajtovou dĺžkou, 16 osembitových registrov V0 až VF, jeden šestnásťbitový ukazovateľ I. Spolu 35 inštrukcií na priraďovanie, porovnávanie, vetvenie, čítanie klávesnice či zobrazovanie. (Ktovie, kto sa kým inšpiroval).

Inštrukcie sú väčšinou jednoduché a ľahko sa interpretujú. Výnimkou sú inštrukcie, ktoré emulujú zobrazovací hardvér, teda inštrukcie na čítanie stavu klávesnice a najmä inštrukcia zobrazovania. V základnej verzii CHIP-8 je grafické rozlíšenie 64x32 pixelov, v nadstavbe SuperCHIP-8 je to 128x64. Aby to nebolo také jednoduché, tak zobrazenie preteká zo strany na stranu (túto vlastnosť však veľa interpreterov ignoruje a napr. hra Squash vyzerá inak, keďže hracia plocha je vykreslená tak, že celkom vpravo sú vykreslené tri pixely, avšak tretí má už pretiecť na ľavú stranu a vykresliť ľavý okraj).

Pre počítač Ondra vznikla verzia interpretera zahrňujúca inštrukcie CHIP-8 aj SuperCHIP. Rešpektuje v čo najväčšej miere zobrazovanie a snaží sa o čo najväčší komfort. Má nahrádzať nedostatok programov pre tento počítač aspoň takýmto spôsobom. Mnohé hry sú jednoduché, priam primitívne, treba sa na ne však pozerať optikou 70. rokov. Ondra tak má k dispozícii nejakú stovku programov naviac.

Aby zobrazenie bolo dobre viditeľné, je každý bod zväčšený 2x, teda má 2x2 px. Zobrazenie je teda 128x64 resp. 256x128. Je dodržané pretekanie znakov na opačnú stranu, celkom rýchly je i posun obrazu v troch smeroch.

Vzhľadom na rozloženie klávesnice  na počítači Ondra (chýbajúce numerické klávesy, len tri riadky znakových kláves) bolo na rozdiel od iných interpretácií zvolené mapovanie kláves na vrchný riadok (1, 2, 3,... 0) a na riadok pod ním (A, B, C, D, E, F). Smerové klávesy sú mapované podľa potreby hier.

Jednotlivé programy sa načítavajú z SD karty cez interface Ondra SD. Keďže aktuálny firmware neumožňuje vyčítanie adresára s inými typmi súborov ako BIN a TAP, musí byť zoznam programov uložený v konfiguračnom súbore CHIP8.CFG. Okrem zoznamu programov je pre každý program možné definovať mapovanie smerových kláves a medzery.

Interpreter prešiel niekoľkými testami funkčnosti inštrukcií (SCTest12, SQRTest, SCSierpinski), neznamená to však, že sa tam nemôže nájsť nejaká nezrovnalosť s originálom, napr. pri inštrukciách rotácie bitov nie je jednoznačné, či sa dejú nad premenou X alebo Y. Alebo či pri ukladaní a obnovovaní registrov dôjde aj k zmene registra I (ako vo väčšine interpreterov, vtedy napr. nejde demo SCSierpinski), alebo má zostať nezmenený. Tak či onak sa dá s týmito nezrovnalosťami pri písaní programov vysporiadať.  Možno by pravdu dokázal potvrdiť test na originálnom hardvéri COSMAC VIP, kde bola prvá implementácia CHIP-8. Niektoré programy, čo nebežia na iných interpreteroch, idú na Ondrovi bez problémov.

Pre potenciálny vývoj je v interpreteri zabudované aj krokovanie programu s výpisom registrov po každej inštrukcii.

Dekódovanie jednotlivých inštrukcií je riešené pomocou tabuliek skokov, nie hlúpym vetvením podmienok, ako je možno nájsť v jednom nemenovanom interpreteri. Pre dosiahnutie maximálnej rýchlosti nie je pozícia v tabuľke vypočítavaná súčtom, ale je iba zmenou nižšieho bajtu adresy, čo však vyžaduje umiestnenie tabuľky na vhodné miesto (nižší bajt musí byť nulový). Je použitých menej inštrukcií a kód je rýchlejší. Rovnako sú dekódované inštrukcie s prefixom 8 (aritmetické a logické operácie) a s prefixom F (zmes rôznych inštrukcií). Až ostatné inštrukcie sú vetvené podmienkami, keďže je to vzhľadom na ich počet jednoduchšie (tabuľky by zaberali veľa miesta).

Interpreter bol napísaný modulárne, jadro (interpretácia kódu CHIP-8) je cielene písané bez použitia špeciálnych inštrukcií Z80 a je jednoducho prevoditeľné do I8080, ak by bol záujem portovať kód do iných československých počítačov. Interpreter kontroluje pri behu správnosť kódu a na nesprávne alebo neočakávané príkazy reaguje chybovými správami. Najväčšiu časť programu zaberá rutina zobrazovania. Sprite (teda nie tá umelá citronáda s divnou chuťou) môže byť zobrazený na ktoromkoľvek mieste s presnosťou na bit, môže mať šírku max. 8 bitov a výšku až 15 bitov (v SuperCHIP je ešte jeden špeciálny rozmer 16x16). Výškové umiestnenie je vzhľadom na spôsob zobrazovania na Ondrovi vcelku jednoduché, polohovanie na šírku je však naopak veľmi komlikované, keďže riadky sú bajtovo orientované. Pre správnu pozíciu treba sprite rotovať tak, aby zodpovedal danému umiestneniu. CHIP-8 pozná iba zápis cez funkciu XOR, teda treba vždy zohľadniť obrazové dáta zapísané predtým. Takže po poriadku: dáta z matrice sa musia zdvojnásobiť (keďže jeden pixel je zobrazený ako 2x2), potom odrotovať na správnu pozíciu, potom XORovať s predošlými dátami a nakoniec ešte nastaviť flag, či došlo k zmene svietiaceho bodu na vymazaný, ako to vyžaduje CHIP-8. A to všetko urobiť v dvoch riadkoch naraz (práve kvôli tomu zväčšeniu). No, a skúste toto napísať tak, aby to bolo jednoduché, krátke a rýchle. Nemožné! Alebo predsa? Zobrazovacia rutina načítaný bajt z matrice zdvojí do registrov D, E. Následne sa odrotujú podľa cieľovej pozície tak, že výsledok je v registroch D, E, B. Teraz sa vyberú bajty z VideoRAM, na ktoré ukazuje HL, vykoná sa XOR a bajt sa vloží naspäť. A to všetko trikrát, pre každý bajt zvlášť. Ale ako zistiť, či sa niečo zmazalo, keď ovplyvnených mohlo byť len niekoľko bitov z tohto bajtu? Otázka za milión! Ale niekedy prvotný i keď šialený nápad môže byť ten najlepší. Vezmime teraz výsledný bajt, urobíme AND  a ešte raz XOR. A ak je výsledkom nula, tak k mazaniu nedošlo. Komplikované? Skúste vymyslieť niečo lepšie, jednoduchšie, rýchlejšie. Takže ešte raz a pomaly:

LD    A, (HL)    ; načítaj pôvodné obrazové dáta

XOR   D          ; XOR s novými dátami

LD    (HL), A    ; zapíš dáta späť

AND   D          ; ale ešte aj AND

XOR   D          ; a XOR s novými dátami

LD    D, A       ; výsledok ulož do registra na neskorší test

To isté pre ďalšie dva bajty (E, B). Následne ich stačí otestovať na nulovú hodnotu, všetky tri súčastne. Neboli potrebné žiadne ďalšie registre (už aj tak zostali len tieňové), žiadne predrotované masky. Ale keďže je potrebné aj testovať, či bol dosiahnutý pravý okraj, je vzhľadom na rýchlosť kód zobrazenia naklonovaný trikrát (podľa toho, ktorý z troch bajtov prechádza na druhú stranu). Pre sprite 16x16 je navyše zobrazenie rozdelené na ľavú a pravú polovicu.

Možno zarazí, že jadro CHIP-8 využíva dva ukazovatele adresy. Ukazovateľ ADDR je na začiatku každého inštrukčného cyklu naplnený hodnotou PC a zostáva nemenný počas celého cyklu. Druhý ukazovateľ PC sa hneď po načítaní kódu inštrukcie zvýši o dva. Následne môže byť zmenený inštrukciou skoku, volania rutiny, alebo zvýšený znovu o dva pri podmienkach. Jedine pri inštrukcii Fx0A sa hodnota vráti o dva späť, ak nedošlo k stlačeniu klávesy, čím je dosiahnuté, že sa inštrukcia opakuje. Pri krokovaní je výpis registrov zobrazený na konci inštrukčného cyklu, teda už obsahuje všetky zmeny, ktoré inštrukcia vyvolala (na rozdiel od iných interpreterov, kde je potrebné na premietnutie zmien čakať ďalší cyklus). Práve v tomto prípade, ale aj v prípade zobrazenia chybovej správy, je využitá hodnota ADDR, ktorá ukazuje na správnu adresu práve vykonanej inštrukcie.

CHIP-8 má dva časovače, jeden na sledovanie času v programe (napr. čakania v slučkách) a druhý na dĺžku zvuku. Oba časovače majú svoju hodnotu znížiť každú 1/60 sekundy (podľa počtu TV snímkov v USA). Keďže na Ondrovi vzniká prerušenie len 50x za sekundu, sú počas každého piateho prerušenia znížené časovače dvakrát, čím je dosiahnuté, že časovač dodrží predpísanú hodnotu 1/60. Počas krokovania je stav časovačov znižovaný po každej 10 inštrukcii, o čo sa stará doplnkový časovač T-MICRO. Zvuk má trvať aj počas vykonávania ďalších inštruckií (multitasking :-) ), a je to snáď jediný prípad, kedy možno poďakovať Ing. Smutnému za to, že Ondra má zvukový výstup nezávislý od CPU (pri generovaní tónov rôznych frekvencií a hlasovom výstupe je to naopak veľká prekážka).

V základnej obrazovke je možné vybrať súbor s programom CHIP-8 alebo SCHIP-8 pomocou kurzorových šípok. Načítanie programu sa spustí klávesou Enter. Ukončenie interpretera je cez Q(uit). Po načítaní programu sa tento ovldáda pomocou kláves 1, 2, 3 až 0 a ASDFGH (spolu 16 kláves zodpovedajúci 0-F hex.). Klávesa 5 sa často používa ako akronym pre Start pre vzhľadovú podobnosť s písmenom "S". Kurzorové klávesy sú mapované nasledovne:

vľavo - 4, vpravo - 6, hore - 2, dole 8, medzera - 5. Kurzorové klávesy a medzeru je možné premapovať definíciou v konfiguračnom súbore.

Počas behu je možné program ukončiť  klávesou N(ew), reštartovať klávesou M(ove to start) alebo pozastaviť B(reak) a zmeniť rýchlosť interpretera. Krokovanie programu po inštrukciách je možné klávesou CTRL (SHIFT ukončí krokovanie). Znovuspustenie nenačítava program, ale iba spustí načítaný program od začiatku. Dáta programu už však mohli byť modifikované a beh programu sa môže líšiť (napr. Sierpinski zobrazí úplne inú grafiku).

Štruktúra konfiguračného súboru CHIP8.CFG:

meno súboru (8.3), ";", ovládanie (vľavo, vpravo, hore, dole, medzera, rýchlosť)

maximálna rýchlosť je F, minimálna 0

príklad

BRIX.CH8;4628AF

Jednotlivé záznamy musia byť oddelené znakom CR. Znak LF je nepovnný, ale može byť použitý.

Z konfiguračného súboru sú načítané len správne záznamy, ak záznam začína napr. znakom ";", bude ignorovaný.

Súbory sú načítané rýchlosťou 9600 Bd. Väčšia rýchlosť nebola možná, lebo keďže nie je známa veľkosť súboru, je počas čakania na start-bit zo sériovej linky (z OndraSD) odpočítavaný čas, ktorý keď vyprší je súbor považovaný za kompletný. Pri rýchlosti 57600 Bd je to už nemožné pre malú rýchlosť procesora (na rozdiel od ZBerry, ktorý beží na 10MHz). Vzhľadom na malú veľkosť súborov (max. 3,5 kB) však čas prenosu nie je príliš dlhý, cca 4 sekundy.

Súbory CHIP-8 a SCHIP-8 možno nájsť na internete, väčšinou sa jedná o hry a demá. Súbory pre kalkulačky HP obsahujú nejaké dáta navyše a treba sa im vyhnúť.

Veľké poďakovanie si zaslúži Nobomi za jeho emulátor počítača Ondra, bez ktorého by tento interpreter pravdepodobne nikdy nevznikol.