J'ai donc commencé à piquer des mesures en cycles CPU avec un analyseur logique (ce dernier permet de compter des impulsions dans une intervalle) branché sur un vrai MZ-700 :
Code : Tout sélectionner
LINE : 227
Genuine MZ-700starts its LINE here
|
| EmuZ-700 starts its LINE here
| |
v v
BLNK : (1) 80 | (0) 147 -> TOTAL: 227
/HBLK : (0) 99 | (1) 128 -> TOTAL: 227
/HSY : (0) 32 | (1) 16 | (0) 179 -> TOTAL: 227
J'ai donc mis à jour le source à partir de ces informations. Donc du 91 cycles que j'avais calculé à partir du manuel, je me retrouve en fait avec 80 cycles maximum d'accès. Ah mais il y a un problème !? le programme 112.mzf qui dessine notre "Sailor Jupiter" fait du 81 cycles par ligne !
Il existe un programme appelé 'wt' qui permet de déterminer jusqu'à combien de cycles on peut écrire pendant le signal BLNK=1 :
- Exécuté sous le MZ-700 réel, l'image qu'il faut obtenir va jusqu'à 83 cycles :
( )
Sinon au-delà, on obtient une perturbation indiquant que le code de dessin ne peux plus dessiner par ligne de "rasterisation" :
( )
Et l'EmuZ-700 PAL ? 91 cycles !!!
Face à cette énigme, j'ai entrepris d'analyser comment ça se passe :
- sur un vrai MZ-700 :
Code : Tout sélectionner
Bloqué sur le T2 du M-cycle #2 (MRD) tant que BLANK est 0 ---> cette instruction a donc bien exécuté 7 cycles
avant d'être bloquée. 80 + 11 (coût total du PUSH) - 7, ça donne... 84 comme limite à ne pas franchir !
|
v
[PUSH:11][PUSH:11][PUSH:11][PUSH:11][...:n-44][PUSH:11]
Code : Tout sélectionner
BLANK est à 0 ---> Le premier PUSH est exécuté complètement et le /BUSREQ passe à 0
pour que l'instruction suivante soit bloquée jusqu'à ce que BLNK devienne 1
|
| Le deuxième est maintenant bloqué : 80 + 11 (1er PUSH) + 1, soit... 92 comme limite à ne pas franchir !
| |
v v
[PUSH:11][PUSH:11][PUSH:11][PUSH:11][...:n-44][PUSH:11]
Effectivement un programme qui affiche continuellement un certain nombre de fois avec LDIR au lieu de PUSH donné 11 secondes au lieu des 16 secondes attendues à cause de ce choix d'émulation.
J'ai galéré pour trouver un fichier exploitable programmatiquement et "générer" des tableau de cumul de T-state par M-cycle faisant accès à de la mémoire (insertion de /WAIT states potentiels sur le T2 du M-cycle de type M1R, MRD ou MWR). Avec ces tableaux, je peux obtenir plus finement les cycles CPU pour calculer le nombre de cycle /WAIT qui faut pour que l'instruction reprenne à l'instant où BLNK repasse à 1.
Et bingo ! EmuZ-700/PAL me fait bien 83 avec 'wt' (PUSH) et ~16 secondes avec le programme de test à base de LDIR comme le vrai MZ-700.
A noter que le cas d'une instruction exécutée dans la VRAM est maintenant bloquée plus finement aussi (premier opcode passe, le second ne passe pas --> pas le même nombre de cycles /WAIT que si ça avait été le premier opcode qui bloquait).
Conclusion : émuler avec des cycles par instruction ne suffit pas pour une bonne émulation de la partie hard extérieure au CPU, compter les T-states entre le M-cycles d'une instruction peut être crucial dans certain cas.