Emulujeme osmibit JavaScriptem, díl druhý

V prvním dílu jsem psal o emulování procesoru. Procesor je hezká věc, ale moc neoslní. Co takhle emulátor celého počítače?

Jako první krok jsem si vybral legendární jednodeskový PMI-80. Má jednoduchou maticovou klávesnici a displej z devíti sedmisegmentovek. Jako první jsem udělal ty sedmisegmentovky.

Neřešil jsem canvas ani nic podobného a segmenty jsem otrocky nasimuloval pomocí tabulky. Takové řešení není zcela věrné, pokud bych chtěl opravdu věrný displej PMIčka, musel bych sáhnout k tomu canvasu, ale upřímně – displej PMI nebyl žádná sláva, znaky měly asi půl centimetru na výšku a pracovat s tím nebyl žádný med. V tomhle jsem zastánce přístupu „netřeba plnou věrnost, raději použitelnost“, tak jsem se smířil s tím, že emulace nebude úplně pünktlich, zato na displej pořádně uvidím.

Displej je u PMI připojen na dva porty obvodu 8255. Jedním se vybírá konkrétní sedmisegmentovka k rozsvícení, druhým se určuje, které segmenty v ní mají svítit. PMI používá dynamické občerstvování displeje, tzn. procesor v pravidelných intervalech posílá stále dokola hodnoty pro jednotlivé sedmisegmentovky. Když se zastaví, displej zhasne. Bohužel monitor PMI má taky tu vlastnost, že nejdřív pošle 00 a teprve pak rozsvítí segmenty. Ve výsledku se to projevovalo šíleným blikáním, tak jsem do algoritmu sedmisegmentovek přidal „dosvit“ (když je segment nastaven na 0, tak ještě chvilku svítí…)

Připojení je vyřešeno tak, že mám „hook“ na vstupně-výstupní operace (psal jsem o tom v prvním dílu) a kontoluju si, jestli procesor náhodou nepřistupuje na porty 8255. Zatím jsem vůbec neřešil všechny módy 8255 ani speciální řídicí slova pro nastavení / nulování bitů portu C, jen jednoduché přiřazení portu adresám.

Klávesnici jsem vytvořil taky HTML tabulkou, odchytávám události mousedown a mouseup a v paměti si držím pole, kde mám informace o tom, jaká klávesa je aktuálně stisknutá. Přidal jsem i obsluhu událostí keydown a keyup, takže jsem si mohl namapovat klávesy PC na klávesnici PMI a nezadávat programy klikáním myší na virtuální klávesnici.

PMI při výše zmíněném občerstvování displeje taky periodicky prochází jednotlivé sloupce klávesnice. Používá k tomu stejný signál, tj. když je aktivována první sedmisegmentovka, tak se zároveň čte první sloupec klávesnice. V JavaScriptu jsem to vyřešil jednoduchým testem, jestli do daného sloupce náhodou nespadají některé stisknuté klávesy, a podle toho jsem nastavil hodnotu pro vstupní port.

Trošku problém byl s magnetofonem. PMI na to nemá žádný speciální USART, ale hezky poctivě klepe bitama na výstupním portu. Jedním generuje nosnou frekvenci, druhým ji strobuje. Při čtení se pomocí RC členů vyhlazuje průběh zpátky na ten strobovací signál, takže jsem nakonec zvolil řešení takové, že si do pole poznamenávám, kolik T uplynulo od poslední změny strobovacího pulsu (pokud je tedy spuštěné nahrávání). Při čtení dělám obdobný postup – čekám daný počet T, a pak změním informaci na vstupním bitu.

Zájemci si teď odskočí pohrát s emulátorem PMI-80, a já mezitím popíšu, jak se emuluje grafický displej a zvuk.

Druhý počítač, který jsem se rozhodl emulovat, nebylo ani Spectrum, ani ZX80/81, pro ty je JS emulátorů dost, a skvělých. Já sáhl po další české klasice, po počítači, s nímž jsem strávil krásná léta – totiž po PMD 85.

Jako první jsem zase připravil displej. Tentokrát to už je canvas 288×256 bodů. PMD mělo obsah displeje uložené v RAMce od adresy 0xC000. Každý bajt udával hodnoty šestice bodů. Nejvyšší dva bity určovaly, jestli bude šestice blikat nebo jestli bude zobrazena se zvýšeným jasem. Každý řádek zabíral 64 byte… ano, počítáte dobře! 288 / 6 = 48! Těch chybějících 16 bajtů se nezobrazovalo (ale šlo s nimi pracovat a použít je jako prostor pro proměnné apod.) a paprsek se v tu chvíli vracel na začátek dalšího řádku. takže stačilo jen tenhle algoritmus převést do JavaScriptu, který prostě sáhne do „pole RAM[]“ a zobrazí celý snímek.

Tentokrát jsem zavrhl requestAnimFrame a zvolil jsem „prostý Timeout“, nastavený na 50 Hz, protože 50 Hz je obnovovací frekvence obrazu v originálním PMD. Do pole RAM[] jsem umístil monitor, emulátor jsem spustil – a výsledek mě příjemně překvapil. Vše fungovalo na první zapojení.

Pak jsem připravil mapování klávesnice (opět dva porty 8255) a mohl jsem začít zkoušet. Neobešlo se to bez peripetií, kdy jsem zjistil, že mám špatně připravené jádro 8080, kde se objevují chyby ve výpočtu parity a v nastavení příznaků u instrukcí DAA a DAD, ale když jsem to opravil, všechno fungovalo, jak mělo.

Jako další krok mě napadlo udělat audiovýstup. S tím je trošku problém, protože WebAudio je opravdu hodně nová technologie a má svoje omezení. Například můžete připravit audioprocesor, který vám umožní sahat na jednotlivé hodnoty samplů, ale délka jeho bufferu není volitelná, stejně jako samplovací frekvece. Ta byla na mém pokusném stroji vždy 48kHz. K tomu délka bufferu buď 512, nebo 1024. Zvolil jsem 1024, čímž jsem dostal frekvenci 46.875Hz. Tolikrát za sekundu je potřeba naplnit buffer, jinak podteče nebo přeteče. Pro začátek jsem tedy vzal tuto frekvenci jako hlavní, rezignoval jsem na 50Hz obnovování displeje (je o něco nižší), ale zvuk funguje tak, jak bych si to představoval.

Displej byl ale opravdu malý, tak jsem ho chtěl zvětšit na dvojnásobek. Prosté roztažení pomocí CSS je možné, ale prohlížeč pak vytváří děsivé blur efekty, takže hezky otrocky mapuju každý bit na čtyři pixely. Bohužel ve Firefoxu není práce s canvasem z nejrychlejších, takže ve FF se to celé vleče (budu se muset zamyslet, jak to zrychlit), ale Opera i Chrome hrají jak mají. A když se po spuštění emulátoru ozvalo známé PÍÍÍ – PI – PI, věděl jsem, že jsem na dobré cestě.

Můžete si vyzkoušet emulátor sami. Nezbytný návod a odkaz najdete zde: Hrajeme si s emulátorem PMD 85.

Líbil se vám článek? Podpořte autora na Patreonu

3 Comments

Got Something To Say:

Vaše emailová adresa nebude zveřejněna.

Problem s rozmazanim zvetsovanych obrazku jsem uz take resil (kdyz jsem si generoval QR kody tak aby jeden bod odpovidal jednomu pixelu a potom to teprve zvetsoval pres CSS). Me nakonec pomohlo: image-rendering:-moz-crisp-edges;image-rendering:-o-crisp-edges;image-rendering:-webkit-optimize-contrast;-ms-interpolation-mode:nearest-neighbor
Vim ze canvas je neco jineho nez obrazek, a ze to asi nepomuze, ale kdyby snad nahodou…

banner

Copyright © 2017. Powered by WordPress & Romangie Theme.

banner