Cesta k Flexi Card nebyla vůbec přímočará. Zpočátku jsem vůbec netušil a hlavně neplánoval, že nějakou Flexi Card vyrobím. Nenapadlo by mě, co všechno se budu muset naučit, a že něco takového vůbec budu schopen.

Začalo to vlastně nevinně…


Motivace

11.8.2020

Tenkrát mě inspiroval Michael Obsieger se svými porty her ze SG1000 na Sorda. To se mi líbilo, protože vlastně již od dob, kdy jsem se o Sorda začal zajímat, bylo pro něj žalostně málo her. Zkušenější uživatelé již v 80. letech portovali hry z MSX pro jeho HW podobnost. Takže jsem si to chtěl nyní zkusit na vlastní pěst (tehdy mi bylo 13 a neměl jsem na to znalosti). Nemusel jsem zůstat pouze u MSX, ale sáhnout po hře z počítače Colecovision, již zmíněné SG1000, Sinclair nebo dalších.


Portace

Já začal s Coleco, kde podobně jako u MSX musíte změnit pár portů a dalších maličkostí, ale nechci zabíhat do podrobnosti, možná o tom později napíši samostatný příspěvek. Poté, co jsem měl upravenou hru, otestoval jsem ji v emulátoru MAME, tam se totiž dobře debuguje a úprava hry je o dost jednodušší. Když hra chodila, teprve pak jsem začal s testováním na Sordu. Jenže nahrávání z WAVu pořád dokola mě nebavilo. Pro emulaci Coleco her je potřeba alespoň 32 KB RAM. No a jelikož se mi tou dobou porouchala paměť EM-64 (další z náhod, která pomohla vzniku Flexi Card), byl s testováním šmitec. Párkrát jsem hru poslal na otestování na Sord FB skupinu, ale test na reálném Sordu stále nefungoval. Nechtěl jsem svými pokusy obtěžovat ostatní členy, potřeboval jsem to testovat sám! Přestože brácha udělal novou 64 KB RAM postavenou na VHDSL a já znovu mohl testovat na Sordu, nebylo to stále ono. Chtěl jsem dosáhnout úplného převodu hry, tak aby fungovala jako originální cartridge do Sorda, bez přídavné paměti. Říkal jsem si tehdy, jak k sakru udělat ROM bez nutnosti neustálého přeprogramování. Začal jsem googlit, jak emulovat ROM se spojením s SD kartou. Narazil jsem tehdy na několik slibných projektů…


Crash vlastně KernelCrash!

…tehdy 9.1.2022 jsem poslal na FB skupinu odkaz na jeden slibný projekt s vírou, že by snad někdo zkušenější z členů vyrobil modifikaci pro Sorda. Bohužel se toho nikdo neujal a tak jsem se do toho pustil já. KernelCrash1 měl naštěstí dobrou dokumentaci i se zdrojovými kódy a tak se dalo “okoukat”, jak to dělá a jak to funguje.


Realizace

Projekt začínal mít jasné obrysy, ale jak začít? Budu potřebovat prototyp desky, na kterou nasadím STM32 dev kit. Hmm, ale jak sehnat vyhovující prototyp desku? Univerzální děrná deska sice existovala, ale byla docela malá a vůbec nevyhovující. No nic, slyšeli jste již o EasyEda2? Pokud hledáte online “out of the box” řešení od schématu po návrh desky, velmi doporučuji. Výhodou totiž je, že návrhy zde vyrobené splňují všechny podmínky/předpoklady pro výrobu samotné desky. Fakt to mají zmáknuté! Minimální odběr je sice 5 ks, ale co, za srandu to stojí. Za cca 10 $ (a to mají dost často slevové akce) dostanete něco, co byste v domácích podmínkách těžko vyrobili.

Vše jak má být. Pájecí maska, postříbřené kontakty, prokovení děr, potisk, no paráda! Vše si můžete nakonfigurovat podle svých představ. Navíc, za úplatu nabízejí i napájení součástek, které jste při návrhu použili z jejich katalogu.

Prvním krok byla zábava, následujícím krokem bylo sehnat čínský klon tzv. Black Board s STM32F407vet63 (vgt6) dev. kit. Bohužel, v době, kdy jsem ji začal shánět, celý svět stále prahnul po čipech a tak se z $10 za desku stalo téměř $20. Nejprve jsem si pořídil větší variantu, která paradoxně vyšla levněji, a teprve poté tu mini verzi4, která bude lepší pro finální produkt a vejde se do krabičky od cartridge. Bohužel se ukázalo, že součástky musí být naletovány přímo na PCB aby se do krabičky vešla.

Proč vlastně STM32F407? Tento procesor (a nejen tenhle) má několik výhod, většina pinů je 5V tolerantních, procesor je dostatečně rychlý pro odbavování paměti, má integrovanou SD čtečku a konečně, nemusíte mít k ní programátor, ten je součástí desky. Stačí ji jen připojit přes USB k počítači a nabootovat ji do tzv. DFU módu, kde ji již pomocí volně dostupného programku flashnete.

Nyní se musím rozhodnout, v jakém vývojovém prostředí budu pracovat. Pro STM32 existují komerční, ale i bezplatné programy jako Keil, Cube, CubeMX, IAR. Výhodou by byla 100% podpora procesoru s pěkným grafickým rozhraním s debuggerem a vším, co k tomu patří. Na druhou stranu projekt od KernelCrash byl postaven na linuxovém prostředí a ke kompilaci používal make. Líbilo se mi, že takovýto projekt prostě zkompilujete všude i bez IDE, stačí mít jen nainstalovaný Arm toolchain. Rozhodl jsem se pokračovat ve stejném stylu. Jako IDE volím univerzální VS Code, který s pár doplňky umí i debugging. Protože vlastním Windows, ale vývojové prostředí je lepší na Linuxu, používám WSL s Ubuntu distribucí. Můj bratr zvolil kombinaci VS Code + PlatformIO5 a WSL nepotřeboval.

Projekt je koncipován tak, že časově kritický kód je napsaný v assembleru, hlavně rutiny pro přístup do paměti, které se volají pomocí přerušení STM32. Zbytek programu je již v C a využívá low-level knihovny CMSIS6. Je zde malá abstrakce kódu, což uživatel pocítí v nutnosti nastavovat hardware přímo přes registry. Na oplátku je kód rychlý a hubený.

Kód jsem vytvářel postupně. Nejdříve jsem se zaměřil na zápis do paměti RAM, který nevyžaduje posílání nic na sběrnici, ale jen její čtení. Poté jsem se věnoval čtení RAM a emulaci ROM. Zprvu jsem emuloval na Flexi Card 64KBI RAM modul, což je vlastně původní EM-64 + Basic I. Později jsem se rozhodl, že ho nahradím 64KBF, který poskytuje více režimů paměti a má stejnou SW podporu jako EM-64. Práce postupovala víceméně bez problémů, vše fungovalo správně, až na MSX (a pár dalších mnou zkoušených programů), kde to vždy vytuhlo. Čučel jsem do kódu hodiny a stále neměl ponětí co je špatně.

Je třeba si uvědomit, že každá změna vyžaduje re-flash firmware a zápisů také není nekonečně. Bylo třeba začít hledat chybu jinak.


Debugging

K debugování firmware jsem používal několik metod. Jelikož jsem měl pramálo zkušeností s ARM assemblerem, občas jsem ověřoval funkčnost kódu v online emulátoru CPUlator7. K testování časování jsem používal 4 GPIO piny připojené na logický analyzátor. Tuto metodu používal i KernelCrash ve svých projektech. Nicméně toto nestačilo na složitější testování funkčnosti programu. Proto jsem se rozhodl pořídit STLINK dongle, konkrétně neoriginální kopii STM programátoru.

To je zařízení, které jednak slouží jako programátor a druhak jako debugger sonda, pomocí které můžete v reálném čase krokovat běžící program. On vlastně ten dongle zastane i napájení. Ukázalo se ale, že to nebude jen tak. Jde o to, že jakmile stopnete Arm procesor, procesor Z80 nepočká, ten běží dál, a většinou Sord crashne nebo pustí nahrávání z kazety. Nikdy jsem nedořešil, aby STLINK ovládl i běh Sorda. Tuto nedokonalost jsem chtěl vyřešit tisknutím různých stavových zpráv do konzole. A to pomocí SWV a tzv. ITM (Instrumentation Trace Macrocell) obdoba Semihostingu nebo UARTu, který má být ale rychlejší, což jsem potřeboval kvůli přerušení. Nejprve ale musíte upravit8 STLINK dongle, který nemá standardně vyveden SWO signál, potřebný k dříve popisovanému tisknutí. Z nějakého důvodu to neběhalo stabilně. Toto vše sloužilo pro ladění kódu na STM. To ale nestačilo, jelikož jsem neovládal běh Z80 (viz. výše), potřeboval jsem také kontrolu běhu Z80 kódu. Proto jsem si pro Sorda napsal “Odepínač”, testovací program paměťových režimů nezávislý na MONITORU ROM. Uměl také zapisovat a číst paměť, skákat do libovolného místa v paměti. Boužel ani s pomocí “Odepínače” se nedařilo chybu odhalit. Vše chodilo správně. Proč tedy nechodí MSX?! Potřeboval jsem tomu přijít na kloub. Nenapadlo mě nic lepšího než zjistit, jak funguje MSX loader. Dalo se to provést tak, že zkompilovaný program disassembluji, ale věděl jsem, že na Romanově google drive je i zdroják k MSX boot. Ten obsahoval i komentáře, které posloužily ke snadnějšímu pochopení funkčnosti. Zádrhel byl ale v tom, že se kýžený program vyskytoval na záznamu kazety někde uprostřed a moje dřívější programy na převod wav do cas formátu nefungovaly úplně stoprocentně. Ano, mohl jsem pomoci wav editoru vystřihnout pouze konkrétní program, ale jelikož jsem si stejně potřeboval odpočinout od Flexi Card, tak jsem se jednou večer rozhodl přepsat původní programy pro konverzi, tehdy napsané v C, do Pythonu, který mi v dnešní době přijde flexibilnější.


Převodník WAV2CAS oprášen 

No a tak jsem strávil několik večerů nad úkolem, jak nejlépe zpracovat BFSK modulaci a převést ji na jedničky a nuly. Ne že by mě to nebavilo, ale když víte, že vám jde o úplně něco jiného, a že toto je jen jeden z podúkolů, naprogramoval jsem to tak z 80 %, abych extrahoval potřebná data, a vrátil jsem se k původnímu projektu. Zatím Tape Doctor, jak jsem převodník nazval, není uplně bez chyb 😉


Hledání bugu pokračuje

Nyní vyzbrojen několika novými programy a s vidinou snadného odhalení nefunkčnosti MSX pokračuji v pátrání. Pochopení funkce MSX bootu nebylo složité. V kostce šlo o toto: otestuje typ paměti a způsob odepínání ROM, pak spustí nahrávání jednotlivých bloků, které jsou na páskách uloženy víceméně pozpátku kvůli efektivitě a rychlosti dohrání poškozených bloků paměti po resetu.

Ve finále se přesune poslední blok, kde má Sord systémovou RAM, odepne se ROM a skočí se do MSX BIOSu. Abych přesně izoloval, kde dochází k chybě, postupně jsem v bootu umísťoval “breakpoint”, který skočil do mého “Odepínače”, kde jsem zkontroloval, zda je v paměti vše, jak má. Postupně jsem došel k závěru, že v rámci MSX Bootu je vše v pořádku. Chyba nastala tedy až v MSX BIOSu. Nebudu to protahovat, nalezl jsem místo, které mazalo část paměti pomocí instrukce LDIR. Zaměřil jsem se tedy na zápis paměti a konečně odhalil bug, který mě trápil několik měsíců!

Šlo o to, že zápis do paměti jsem rozeznával tak, že jsem testoval signály MREQ a MRD. Pokud nebylo aktivní MRD, předpokládal jsem, že se tedy jedná o MWR. Ale to byla začátečnická chyba, která byla dobře zjevná i na logickém analyzátoru. Uniklo mě totiž, že MREQ může být aktivní i bez MRD a MWR v případě, kdy se refreshuje DRAM a já v tomto okamžiku zapisoval do paměti nesmysly. Stačilo tedy důsledně testovat pro zápis MREQ a MWR a zapisovat jen tehdy, kdy oba signály byly aktivní.

Další nemalý zásek byl pro mne objev, že i když pracujete s portem, který je namapován jako byte, neznamená to automaticky, že horní byte je nulový! Bylo tedy pošetilé testovat adresu portu, aniž byste horní byte adresové sběrnice nezANDovali.


Komunikace Sord <-> Flexi Card

Pak již to šlo docela svižně. O podporu práce s SD kartou se stará open-source knihovna FatFs a na mě zbylo pouze, jak data přesouvat do RAM. Tady jsem se koncepčně lišil od KernelCrashe, který data z karty zapisoval do části RAM, kterou kontroloval. To jsem sice mohl také, ale přišlo mě šikovnější využít na komunikaci porty, ale uvidíme třebas pozdeji změním názor. Proto jsem vyhradil port 80 a 81 (ty nejsou na Sordu využity) pro komunikaci mezi STM32 a Sordem. Na port 81 pošlete příkaz a pak data čtete nebo zapisujete, to podle typu příkazu na portu 80.

Pak bylo potřeba ještě napsat program na Sorda, který zobrazí programy uložené na SD kartě a umožní uživateli jejich spuštění. Podporuji několik typů programu: ROM, které operují jako program z kartridge, pak jednodílné CAS, obsahující program ve strojovém kódu s autostartem, a pak MSX, což jsou programy v CAS formátu, ale pro MSX, který před vlastním spuštěním zavede MSX. Obslužný program jsem napsal přímo v assembleru Z80 a není to nic světoborného. Abych jej napsal co nejrychleji, dodělal jsem do MAME jakous takous emulaci tohoto protokolu simulující práci Flexi Card. Při té příležitosti jsem opravil pár ošklivých bugů a odkomentoval své úpravy Sord driveru, které z neznámého důvodu ve starší verzi MAME učinili. Až budu mít čas, tak kód dočistím a pushnu na MAME remote server.


Finále

No a co bude dál, možností je spousta na rozdíl od volného času. Nejdříve se budu snažit zbavit Flexi Card všech bugů. Později bych určitě rád dodělal emulaci CP/M, ale ta bude samozřejmě fungovat jen majitelům upraveného Sorda. Více zde. Pak snad podporu nahrávání Basic programů uložených v CAS formátu. To může být ale docela komplikované pro různé multi-part programy, tak to ještě zvažím. Zatímco u MSX programů můžete nejdříve zavést program a teprve až pak MSX, u Basicu je to problém. On totiž Basic při své inicializaci důsledně resetuje a maže předchozí program, takže tady je třeba zavolat nahrání programu až po startu Basicu, to ale zatím nemám rozchozené. Můj bratr již má také pár nápadů na vylepšení, vytvořil třebas verzi, ve které pomocí modifikace MONITORU ROM, používá místo čtení souboru z kazeťáku, Flexi Card. Tak uvidíme, kam to společně posuneme 🙂

V tomto článku popisuji fungování Flexi Card a uvádím všechny zdrojové kódy, aby si i ostatní mohli postavit vlastní Flexi Card klony a rozvíjet její dovednosti, které jsem v původní verzi neměl.

  1. https://www.kernelcrash.com/ ↩︎
  2. https://easyeda.com/ ↩︎
  3. https://os.mbed.com/users/hudakz/code/STM32F407VET6_Hello/shortlog/ ↩︎
  4. https://github.com/mcauser/MCUDEV_DEVEBOX_F407VET6 ↩︎
  5. https://platformio.org/ ↩︎
  6. https://www.keil.arm.com/cmsis ↩︎
  7. https://cpulator.01xz.net/?sys=arm ↩︎
  8. https://www.codeinsideout.com/blog/stm32/swv/#st-linkv2-schematic ↩︎