Jak vyzkoušet emulátor procesoru? Nejlépe programem, který používá všechny instrukce. A co když vám zatvrzele padá?

Ti, co sledují můj Twitter, to už vědí: V pátek v noci jsem napsal emulátor pro BOB-85, v sobotu pak PMD. S PMD bylo trošku problémů, a po odpoledni stráveném s debuggerem a výpisy ROMky i BASICu padlo moje podezření na emulační jádro procesoru 8080. Pravděpodobně tam nějaká instrukce nefunguje jak má.

Jak ji najít? Nejlepší je použít nějaký „instrukční pangram“:

Pangram (z řeckého pan gramma, „každé písmeno“) je věta či úsek textu obsahující všechna písmena abecedy. Jedná se zpravidla o slovní hříčku, cílem je zpravidla vytvořit co nejkratší, popř. vtipný či jinak zajímavý text s touto vlastností.

Tedy kód, který obsahuje všechny instrukce a otestuje, jestli dělají co mají a jestli jsou příznaky nastavené tak jak by měly být apod. Pro procesor 8080 je takových testů několik, já použil takzvaný Kelly Smith Test (Microcosm test). Po pár krocích bylo jasno: špatně se počítá paritní bit! Upravil jsem tedy emulační jádro, a test začal fungovat…

… a fungoval až skoro na konec, kde se testuje instrukce DAA, tedy dekadické zarovnání po aritmetické operaci. Tam sveřepě padal.

Podíval jsem se, jak je instrukce DAA napsána, nevykazovala chybu. Podíval jsem se, jak je definováno její chování:

Instrukce DAA (decimal adjust accumulator) dekadicky koriguje součet kladných čísel v kódu BCD a při tom jediná využívá indikátor AC. Korekce probíhá podle tohoto algoritmu: je-li číslo v dolní tetrádě střadače A větší než 9 nebo AC=1, přičte se ke střadači 6; obsahuje-li pak horní tetráda střadače číslo větší než 9 nebo je-li CY=1, přičte se ke střadači ještě 60H.

Tak. Takhle by to mělo fungovat, a takhle je to taky implementované. Což je v pořádku, ale test na tom havaroval. On totiž téhle instrukci zlomyslně předhazoval hodnoty, které by normálně dostávat neměla, a testoval, že se zachová jako opravdová 8080.

Například – v A je hodnota 55H a AC je nastavený. Podle výše uvedeného algoritmu by měl být výsledek 5BH. Logicky. Ale stejně tak je to (logicky) nesmysl – výsledkem DAA přeci nemůže být 5BH!

Chvíli jsem pátral a přemýšlel. Oněch 55H + AC nastavený na vstupu je nesmysl – jaká dvě čísla by se musela sčítat, aby došlo k přetečení u nejnižší tetrády (čtveřice bitů), a zároveň byl výsledek 5? Inu, musely by se sčítat čísla mimo rozsah 0-9, protože 9+9 dá dohromady 12H, víc ani ťuk. Takže 55 a AC na vstupu je chyba, hurá, příčina odhalena, matematik si může jít odpočinout, ale programátorovi to není nic platné, protože mu test neběží.

A tak jsem se dal do googlení, a nejpodrobnější informaci, co jsem sehnal, je ta, že DAA je „správně“ implementovaná třeba v Z80, ale v 8080 se chová „trochu“ jinak pro nestandardní vstupní data. Mnoho autorů „emulátoru 8080“ s tímhle skončilo a často jsem četl prohlášení: „DAA prostě nefunguje úplně stejně, ale on to stejně nikdo příčetný nepoužívá“. Hm, to sice je řešení, ale test stejně neběží. Co teď?

Vypadá to (ale fakt jen vypadá!), že chování DAA by se mohlo řídit o něco složitějším algoritmem. Nějak takhle:

Je-li číslo dolního nibble >9 nebo příznak AC nastaven, přičítá se 6. Je-li příznak AC nastaven a zároveň je dolní nibble v rozsahu [3..9], jedná se o chybná vstupní data a šestka se nepřičítá.

Mno, bylo by fajn to ještě pořádně ověřit na skutečném, křemíkovém procesoru, ale bohužel, moje PMI ještě není provozuschopné. Každopádně když jsem to takto napsal, tak celý test prošel bez problémů.

Jo a taky se „zázračně“ rozběhalo PMD.

Odkazy: