Au moment où j'attaque le dernier gros morceau de l'émulateur, ce qui n'est pas la moindre des tâches puisqu'il s'agit rien de moins que d'émuler le moteur qui le fait tourner, à savoir le Zilog Z80A, il s'est déjà écoulé pas moins 2 ans de développement...Deux années pour apprendre un langage, à développer dans un environnement Windows, à apprivoiser ses API, à chercher et compiler toutes les documentations techniques pour émuler chacun des composants constituant le CPC. Deux années laborieuses mais finalement très enrichissantes intellectuellement qui mon permis de mieux comprendre le fonctionnement intime d'un ordinateur.
Au moment où je m'attèle donc à l''émulation du processeur, il me semble avoir fait le plus compliqué puisque dans ce cas, il n'y a pas de nouvelles API à découvrir, il me suffit "juste" de retranscrire informatiquement les opcodes telles que décrites dans les nombreux ouvrages traitant du Z80. En vérité, comme toujours dans le monde de l'émulation, ce n'est pas si simple et je vais passer encore de longs mois de développement sur ce gros moteur...
Sur le papier, un processeur n'est pas compliqué à émuler. C'est une puce un peu plus élaborée que les autres qui exécute des opérations arithmétiques et logiques en mettant à jour ses registres internes à chaque cycle d'horloge en fonction des opérations qu'on lui demande de faire.
Mais quand on rentre dans le détail, ça devient une habitude, c'est beaucoup beaucoup moins simple...
Premier point, le Z80A malgré le fait qu'il soit un ancien processeur 8/16 bits est en réalité d'une conception très complexe : Plusieurs centaines d'instructions à émuler, avec des instructions à décoder sur 1 , 2 octets (CBxx, DDxx, FDxx, EDxx..), voire 3 octets (DDCBxx, FDCBxx), 3 modes d'interruptions à gérer, une gestion de cycle d'attente, de nombreux registres internes (8, 8/16, 16 bits) et une certaine part de mystère puisque certaines instructions et certains registres internes, ne sont pas ou mal documentés.
Fort heureusement, sur ce dernier point, ce processeur est désormais très connu et on trouve sur internet de nombreuses sources d'informations dont le très précieux "The Undocumented Z80 Documented" regroupant l'ensemble des informations non transcrites officiellement sur ce processeur.
Deuxième point, j'ai choisi de travailler en T-States et cela va se payer cash avec un temps de développement accru, un code beaucoup plus complexe puisque, ne voulant décidément pas faire simple, j'ai poussé le vice à traiter les cycles d'horloges HAUT et BAS comme un vrai Z80. C'est là que je me suis plongé dans la découverte des cycles de décodage d'une instruction, le cycle M1 (le fetch) suivi des cycles de lecture/d'écriture, de l'insertion de cycles TWait à des endroits très précis de la séquence de décodage, la gestion des interruptions, avec ses règles... et ses exceptions. Bref, encore un chantier de longue haleine.
Comme toujours, outre la documentation technique disponible, ce chantier a été grandement facilité par le travail réalisé par certains passionnés dont Bathasarstudio qui a complètement séquencé la phase de décodage de toutes les instructions du Z80. Une vraie mine d'or qui m'a fait gagner pas mal de temps en tests et mieux fait comprendre le fonctionnement du Z80.
https://baltazarstudios.com/zilog-z80-u ... -behavior/
Cette phase de développement, même si elle n'est pas techniquement compliquée, a donc été extrêmement laborieuse. D'ailleurs très vite au cours du développement, je me suis aperçu qu'il fallait que je teste très en amont chacune des instructions que j'émulais. Un processeur mal émulé peut très vite être une source infinie d'erreurs lors de son exécution qui se paieront cash lors de la mise en route de l'émulateur et de son débogage. Il suffit d'une simple erreur sur la valeur d'un indicateur ou d'un registre pour faire planter un programme. Autant donc minimiser ces erreurs dès le départ.
Autant il est facile de vérifier à la main que l'instruction NOP fonctionne correctement (c'est la plus simple, elle ne fait rien en fait

Vous l'aurez compris, n'ayant pas d'outils de tests à ma disposition... j'ai dû en créer un de toute pièce.

Cet outil réalisé sur mesure m'a permis durant la phase de développement de tester l'exécution de chaque instruction, avec une visualisation des registres avant/après exécution, des timings de l'instruction en T-Stats et en situation "réelle" en la faisant tourner en boucle plusieurs milliers de fois à la vitesse de 4 MHz afin d'en mesurer le temps moyen d'exécution, que j'ai comparé à la valeur "catalogue", hors Twait bien entendu.
Dans certains cas cependant, ces tests unitaires ne suffisaient pas à m'assurer de la bonne exécution de certaines instructions, notamment celles arithmétiques, pour lesquelles les valeurs du registre F (Flag) peuvent beaucoup varier (ADD, ADC, SUB, SBC..). Pour ces cas, je me suis donc résolu à extraire les résultats attendus à partir d'un vrai CPC !. Je me suis donc bâti un petit programme pour simuler ces instructions sur un vrai CPC (un petit code assembleur fait à la main et appelé en BASIC) avec une sortie des résultats sur un fichier que je rapatriais sur mon PC pour l'intégrer à mon émulateur...

Rien de tel qu'une vraie machine pour tester... (PS : oui je sais, mon petit bureau est un peu ... bordélique


La fameuse instruction DAA assez compliquée à tester => Elle est bien conforme au résultat d'un vrai Z80. Ouf !
Au final, cette seule partie m'a encore pris 6 mois de travail mais ce gros investissement sur les tests unitaires m'aura permis au final de limiter les erreurs sur la partie émulation du processeur. Il restera des coquilles bien sûr qui seront corrigées un peu plus tard lors de la première mise en marche de l'émulateur (5 ou 6 instructions mal codées de mémoire) mais cela restera très correct au regard de la dizaine de milliers de lignes de code (12.612 pour être précis) composant cette partie de l'émulation.
Le but de ces tests n'était pas de faire du 100% sans erreur mais de rendre l'émulation du Z80 suffisamment fiable (à 99%) pour pouvoir ensuite lancer sur mon émulateur des programmes tests plus rigoureux et complet encore pour avoir une émulation CPU parfaite à 100%. J'en parlerai un peu plus tard...
Voilà pour cette dernière grosse partie. Si vous avez suivi attentivement mes posts, vous avez dû noter que je n'ai pas abordé l'émulation du PPI Intel mais c'est sans regret car ça ne présente pas d'intérêt : il s'agit grossièrement d'un "Hub" centralisant les IO provenant du clavier/son/cassette...
En résumé : la partie vidéo étant codée (couple Gate Array/CRTC), la partie son également (AY), le PPI et enfin le processeur (Z80), tout est en place pour le grand moment attendu : le lancement d'un émulateur Amstrad CPC 464 fonctionnel...et la question cruciale qui me tenaille à ce moment là : N'ai-je pas fait fausse route à un moment ? Est-ce que cet ensemble d'engrenages assemblés séparément puis imbriqués les uns aux autres au dernier moment va fonctionner ? Car en 2 ans et demi, il n'a jamais été lancé une seule fois au complet !
Je lui mets sa ou plutôt ses 2 ROM d'origines sous le capot et je lance le moteur...
La suite sera pour un prochain post et sans spoiler...ça va tousser un peu et il va falloir donner quelques coups de manivelle quand même pour réussir à faire faire tourner le bouzin...

Merci pour votre intérêt à ce post, bonne lecture et très bonne année à vous tous...
