27. 9. 2015

X, Y, W a Z aneb Záhadná Z80

Jak je mým zvykem, i k počítači Ondra jsem si vytvořil autonomní instruction exerciser, spouštěný tentokrát z ROM místo monitoru. Je-li čtenářům použité písmo povědomé, napovíme, že jsme font 8x8 převzali z jiného osmibitového počítače, toho, k jehož emulaci se stále nemůžeme odhodlat (ostatně i ten font je ošklivý: viz tlustá čárka a nepěkné proporce písmen). Nám se nicméně tento font hodil, protože dovoluje vměstnat na jednu obrazovku Ondry 31 řádků; celý exerciser arci nikoli, ten má v provedení pro Z80 celkem 67 dílčích testů; že i ty ostatní skončí výsledkem OK, mi tedy můžete než věřit.


U Cringlova exerciseru jsem si povšiml dvou zvláštností: jednak u několika testů, patrně nedopatřením, Cringlovi adresa přetekla mimo šestnáctibytové testovací pole MSBT/SPBT a vyžaduje se tedy, aby první dva byty na adrese START byly [0x22, 0x06], a dále, že ve svém, jinak vynikajícím a dodnes používaném, céčkovém emulátoru Z80 nemá Cringle správně ošetřeny registry W a Z.

To je přirozeným důsledkem stáří emulátoru, protože v r. 1994 nebylo o této idiosynkrasii procesoru Zilog Z80 ještě mnoho známo. Příběh je to ovšem zajímavý, a proto ho, dovolí-li, svým čtenářům ve stručnosti odvyprávím.

Registrový pár WZ převzal Zilog z architektury svého předchůdce, Intelu 8080A. Tam se tyto interní registry používaly v situaci, kdy bylo nutné přechodně uložit osmi- nebo šestnáctibitovou hodnotu, např. u instrukce JMP. Jak jistě každý příznivec osmibitů ví, tato instrukce je tříbytová a v paměti je uložena v pořadí kod instrukce (tj. 0xc3) : LSB cílové adresy : MSB cílové adresy. Procesor nemůže přečtený byte LSB zapsat ihned do LSB čítače programu PC, protože ten bude potřebovat ještě pro přečtení MSB, a proto tuto hodnotu dočasně ukládá do pracovního, interního registru Z. Podobná je situace i u dalších instrukcí, např. u šestnáctibitového sčítání (instrukce DAD). I tam se pracovní hodnota ukládá do pomocných registrů.

Registry W a Z programátor nemůže žádným způsobem přečíst a jejich stav činnost procesoru po skončení dané instrukce neovlivňuje, tedy v emulátoru nemusejí být součástí stavového slova a jejich existenci může emulátor s klidem ignorovat.

Tak to mělo být i u Z80, avšak vinou jistého nechtěného efektu, který záhy popíši, tomu tak není; každý emulátor, který aspiruje na absolutní věrnost originálu, tak musí s registry W a Z správně pracovat.

Nyní tedy k onomu zvláštnímu efektu. Stejně jako 8080A má i Zilog v bytu příznaků reservu v podobně dvou nedokumentovaných bitů. Ty se většinou označují X (bit 3) a Y (bit 5) a jejich chování lze u téměř všech instrukcí relativně snadno a přímočaře popsat: nejčastěji kopírují stejně položené bity určitého registru anebo operandu. Užitečné k ničemu nejsou, jen musejí být přesně odemulovány.

Existuje však jedna instrukce, která bity X a Y rovněž nastavuje, avšak dlouho nebylo reversním inženýrům známo, podle čeho: instrukce BIT n,(HL). Až před několika lety se zjistilo, že zdrojem těchto bitů je právě registr W.

Tím dvojice WZ přestává být interním registrem, stává se součástí stavového slova a je nutné změny jejího stavu zachycovat. Problém byl v tom, že nikdo dost dobře nevěděl, jaké ty změny jsou a které instrukce tento registrový pár mění. Z WZ se stále daly přečíst jen dva bity, což bylo pro racionální analysu jeho chování málo. Nakonec se podařilo i tuto potíž překonat: zjistilo se totiž, že instrukce CPI pár WZ inkrementuje o jedničku, bez ohledu na stav ostatních registrů, a CPD ho o jedničku dekrementuje. Protože, jak víme, instrukcí BIT n,(HL) lze bit 11 a 13 přečíst, dal se takto zjistit, až po bit 13, i obsah páru WZ. Dnes tedy víme zcela přesně, nebo to minimálně můžeme snadno zjistit, co se s registrovým párem WZ kdy děje, a umíme to i správně emulovat.

Cringle, jak řečeno, psal svůj emulátor v r. 1994 a nic z těchto informací k disposici neměl. Když nahlédneme do jeho shora odkazovaného emulátoru Z80, vidíme, že na řř. 167–8 u instrukce BIT n,(HL) oba flagy natvrdo nuluje.

To je zajisté chyba, ale překvapivě mu emulátor s exerciserem fungoval zcela stejně jako fysický procesor. Proč je to tak, zjistíme nahlédnutím do kodu exerciseru. Inkriminovaná instrukce je prováděna tak, že se zkopíruje do pole IUT (v mé versi na ř. 1139) a tam je vykonána. Jak vidíme, těsně před ní je vykonána instrukce LD SP,(SPBT). Ta nastaví WZ na hodnotu SPBT, a protože SPBT má v Cringlově testu, pokud ho nerelokujeme jinam, hodnotu 0x111, vycházejí mu vždy příznaky X i Y nulové. Ergo emulátor, ač flagrantně chybný, v exerciseru mohl fungovat. Kdyby ovšem exerciser začínal jinde, s pravděpodobností 75 % by Cringle shody s fysickým procesorem nedosáhl (a možná, protože to byl schopný programátor, by záhadu objasnil o 20 let dříve).

Žádné komentáře:

Okomentovat