[EMULATION AMSTRAD CPC] AMSpiriT - work in Progress

Couvre tous les domaines de l'émulation ou de la virtualisation ainsi que les discussions sur les divers outils associés.

Modérateurs : Papy.G, fneck, Carl

Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: [EMULATION AMSTRAD CPC] work in Progress

Message par hlide »

Il faut voir le Z80 comme une machine d'état :

1) un T-state correspond tout simplement à un cycle d'horloge. Il commence avec le front montant de l'horloge du Z80 et se termine avec le front montant suivant.

2) une instruction est découpée en cycles machine (M-cycle). Chaque cycle machine détermine une étape de la machine d'état : opcode fetching, memory read, write read, I/O port read, I/O port write, internal operation, etc. qui prennent un nombre déterminé ou variables de T-states pour s'exécuter.

3) une instruction commence toujours avec le cycle machine M1 (il y a d'ailleurs un signal /M1 de même nom qui passe à l'état bas au moins sur les deux premiers cycles d'horloge (2 T-states) pour indiquer une nouvelle instruction en cours d'exécution) : c'est le opcode fetching qui prend généralement 4 T-states pour s'exécuter. Les deux premiers pour accéder à l'octet en mémoire représentant l'opcode, le troisième et le quatrième pour exécuter l'instruction et faire le rafraichissement de DRAM. C'est le cas de NOP, de LD A,r, de LD r,A, etc. Ils prennent 4 cycles d'horloge (4-states) pour un seul M-cycle (M1). A noter que lors de l'accès mémoire (entre le deuxième et troisième T-state), il peut y avoir des "wait states" de rajoutés pour laisser le temps à la mémoire de répondre qui augmentent le nombre de cycles d'horloges consommés par l'instruction. Les MSX par exemple rajoute toujours 1 cycle à l'accès de l'opcode, ce qui fait qu'un NOP prendra 5 cycles au lieu du 4 habituel.

4) des instructions plus complexes peuvent prendre plus de T-state : LD A,I/R ou LD I/R,A comptent un ou deux T-states supplémentaires sur le deuxième M1 (ces instructions là se font en deux opcodes - le premier pour indiquer une instruction spéciale et le deuxième pour exécuter la fonction spéciale).

5) des instructions faisant des accès lecture/écriture rajoutent des cycles machines supplémentaires. Ainsi, LD A,(HL), aura un M1 (opcode fetching de 4 T-states), suivi d'un M2 (memory read de 3 T-states - pour lire l'octet se trouvant à l'adresse indiquée par HL), soit 7 cycles d'horloge au minimum en sachant que là aussi des wait-states peuvent être insérés pour laisser à la mémoire de répondre. Donc si on veut lire une DRAM un peut lente qui exige d'attendre un cycle d'horloge supplémentaire, Le LD A,(HL) prendra 7 + 2 = 9 t-states, soit 9 cycles d'horloge en deux cycles machine (M1 et M2).

Les amstradiens parlent de cycles NOP plutôt que de T-states ou M-cycle en raison de la manière comment le GA cadence le nombre de T-states par instruction qui donne l'impression que chaque instruction est exécutée en un multiple de 4 T-states (soit l'équivalent d'une instruction NOP d'où le nom). J'explique ici comment se passe ce glissement de T-states vers le cycle "NOP" en jouant sur l'insertion de wait-states via /WAIT = 0 avec des diagrammes : viewtopic.php?f=1&t=11589.
Lone
Messages : 16
Inscription : 26 nov. 2020 09:53

Re: [EMULATION AMSTRAD CPC] work in Progress

Message par Lone »

Hello,

J'ai lu avec beaucoup d'intérêt ce récit, pour la simple et bonne raison que j'ai eu un parcours étrangement semblable il y a quelques années :
Volonté d'écrire un émulateur CPC, "from scratch", pour le challenge plus qu'autre chose d'ailleurs, avec les docs techniques.

Bon courage pour la suite, parce qu'effectivement, le plus facile est fait (façon de parler... !)
Dmanu78
Messages : 268
Inscription : 20 juin 2020 14:28
Localisation : Yvelines

Re: [EMULATION AMSTRAD CPC] work in Progress

Message par Dmanu78 »

Merci pour vos encouragements. :)
@lone : c’est très intéressant. Tu as travaillé sur l’émulation de quelle machine ?
@ Sebiohazard: c’est normal de ne pas tout comprendre. A force de lire et relire les docs techniques, de parcourir de forums, le jargon devient du plus en plus compréhensible. Je comprends les explications de @hlide parce que j’ai développé de À à Z le décodage des instructions du Z80 en mode T-States (les étapes du fetching, cycles M1, cycles Wait, Read... me parlent donc parfaitement) mais ça m’a pris plusieurs semaines/mois pour bien comprendre les différentes étapes de décodage.
Il y a une phase préliminaire de lecture à ne pas négliger pour développer un émulateur. Il faut en quelque sorte être un rat de bibliothèque dans un premier temps afin de compiler toutes les docs techniques dispo .
Par contre il faut rester persévérant car il y a de grosses phases de frustration, de tâtonnements, surtout au début. A mon sens, il n’y a pas un problème qui ne trouve sa solution. Chaque obstacle franchi est vécu comme une petite victoire. Et plus on avance, plus on on se prend au jeu et plus on a envie de franchir la prochaine étape... ces derniers temps, le confinement aidant, j’y ai consacré pas mal de mon temps libre, une saine occupation qui en vaut une autre :D et l’émulateur a sensiblement évolué depuis ce premier post...ça commence à devenir intéressant. J’y reviendrai un peu plus tard.
Zebulon
Messages : 2787
Inscription : 02 nov. 2020 14:03

Re: [EMULATION AMSTRAD CPC] work in Progress

Message par Zebulon »

Oui sacré courage et sacré boulot ! Je me dis en voyant le premier écran "vert" de ce topic que les concepteurs du premier Amstrad ont peut-être également vu de telles choses sur les prototypes, et ça c'est beau ! :D
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: [EMULATION AMSTRAD CPC] work in Progress

Message par hlide »

Entièrement d'accord avec @Dmanu78, j'ai mis du temps à comprendre ce qu'était ces M-cycle et T-state d'autant que la majorité des documents n'explique pas grand chose et se contente d'indiquer le nombre de M-cycle et le total de T-state sans aucun détail. Il a fallu que je tombe sur https://baltazarstudios.com/ pour y trouver tous les détails qui me manquaient.
Dernière modification par hlide le 27 nov. 2020 14:12, modifié 3 fois.
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: [EMULATION AMSTRAD CPC] work in Progress

Message par hlide »

Et pour Lone, j'imagine que son émulateur est SugarBox :). Pour la V2, il tente d'intégrer le nécessaire pour permettre d'utiliser le débogueur depuis Visual Studio Code. La V2 supporte toute la famille, y compris le CPC 464+, le CPC 6128+ et le GX4000.
Dmanu78
Messages : 268
Inscription : 20 juin 2020 14:28
Localisation : Yvelines

Re: [EMULATION AMSTRAD CPC] work in Progress

Message par Dmanu78 »

:idea: Exactement, bathasarstudio a été une référence pour moi pour le développement de l’émulateur z80 en full T-state. Son travail de décomposition en T-state de chacune des instructions du z80 est admirable. Une vrai mine ce site.
Oh, un autre amateur d’Amstrad alors :) J’ai entendu parler de SugarBox. Je ne l’ai pas testé (comme aucun autre émulateur pour l’instant) mais je le ferai volontiers. Pour l’instant je vais essayer d’émuler aussi parfaitement que possible le 464, 664 et 6128...les versions + ont la réputation d’être plus complexes à émuler à cause de l’Asic propriétaire d’Amstrad peu documenté.
Lone
Messages : 16
Inscription : 26 nov. 2020 09:53

Re: [EMULATION AMSTRAD CPC] work in Progress

Message par Lone »

Effectivement, j'ai développé Sugarbox (et ses variantes).

Mon approche a été beaucoup plus empirique, par contre : Les premières versions était très rudimentaires (les instructions z80 étaient traitées en une fois, l'affichage ne tenait compte d'aucun paramètre CRTC, etc), mais l'avantage est que j'ai pu avoir très vite des résultats visible (quelques semaines pour afficher le basic).

Après, effectivement, chaque partie a du être recodée entièrement plusieurs fois, au fur et à mesure ou je voulais apporter de la précision, rendre plus efficace le fonctionnement, etc.
Par exemple, puisque vous en parlez, passer d'une exécution Z80 brute, à une exécution en T-states (ce qui permet d'avoir des timings corrects sur les écritures mémoires ou IO, par exemple).

Ca reste tout de même une aventure passionnante, et, osons le dire, très enrichissant sur un plan personnel : Arriver à exécuter des programmes prévus pour une autre machine, sur sa propre réalisation, est une expérience très satisfaisante.
Dmanu78
Messages : 268
Inscription : 20 juin 2020 14:28
Localisation : Yvelines

Re: [EMULATION AMSTRAD CPC] work in Progress

Message par Dmanu78 »

@lone
Merci pour l’intérêt que tu portes à ce post. Je suis honoré. Nous avons en effet les mêmes motivations initiales. J’ai été voir ton site. Ton émulateur semble fabuleux. Le mien n’en est qu’à ses balbutiements à côté. Je ne vais pas m’ennuyer les prochaines mois pour essayer d’atteindre l’émulation parfaite :D
Dmanu78
Messages : 268
Inscription : 20 juin 2020 14:28
Localisation : Yvelines

Re: [EMULATION AMSTRAD CPC] work in Progress

Message par Dmanu78 »

Suite de l’aventure...
On rentre dans le dur maintenant : le début de l’écriture de l’émulateur.
Fort de mes nombreuses prises de note et partant d’une feuille blanche, j’ai commencé par ce qui me semblait le plus compliqué à gérer : l’affichage vidéo de l’émulateur. C’est compliqué parce l’affichage d’un graphique dans une fenêtre Windows nécessite déjà de maîtriser quelques API dédiées. Au regard de mes vieux souvenirs, pour afficher un pixel, rien de plus facile. Il faut écrire dans la mémoire vidéo et c’est fini : Il y a un point à l’écran...Dans un CPC d’ailleurs, on fait un POKE &C000,255 et un beau trait rouge apparaît en haut à gauche de l’écran :D

Mais ça c’était avant... car sous Windows la mémoire vidéo n’est plus du tout accessible. Il faut en passer par ses fameuses API.
Ma première étape de construction a été de choisir l’API pour afficher une image : On sort des docs de l’émulateur pour découvrir le monde merveilleux des API Windows dédiées à l’affichage. J’ai commencé à regarder les tutoriaux sur GDI, GDI + mais au final, je me suis tourné vers Direct2D, l’API de Microsoft dérivé de DirectX qui bénéficie de l’accélération matériel de la carte graphique et avec un premier objectif très ambitieux : Réussir à afficher un pixel coloré à l’écran. :lol:

Car Direct2D est compliqué à gérer quand on débute et même si des nombreux tutoriels existent, il m’a fallu du temps pour que je commence à comprendre son fonctionnement. Au début, je me suis dit qu’il suffisait d’utiliser les instructions Direct2D dédiées pour afficher un point. Ça marche ... pour un point ... car pour afficher un écran complet il faut reproduire l’opération plusieurs dizaines de milliers de fois par seconde et ça rame alors sévère. Ce n’était pas la bonne solution... le CPC accède à la mémoire vidéo toutes les microsecondes et il n’est pas envisageable d’appeler les API Windows à cette fréquence sans dégrader les performances de l’émulateur. exit donc l’affichage des pixels en temps réel à l’écran.

Au final, à force de chercher une solution à ce problème, je suis tombé sur une fonction très intéressante de Direct2D : l’affichage d’un bitmap dans une fenêtre graphique à partir d’une zone mémoire, qui me servira donc de mémoire vidéo. Une fois cette zone mémoire définie au bon format vidéo RGB, vu de mon émulateur il me suffit d’y écrire toutes les microsecondes pour créer mon bitmap écran en temps réel, représentant les pixels du CPC. En parallèle j’ai créé un thread dédié contenant les instructions Direct2D qui va m’afficher 50 fois par seconde ce bitmap, à chaque signal VBL en vérité. Et ça marche, l’affichage reste très rapide et l’émulateur n’est pas ralenti outre mesure par l’opération.

Une fois ce problème technique réglé et il était de taille, j’ai commencé l’écriture de l’émulation du CRTC, une sorte de gros compteur, générant les signaux de synchro HBL, VBL, Raster ligne, adresse vidéo ... nécessaires à l’affichage d’une belle image à l’écran et ensuite du Gate Array qui va récupérer l'adresse vidéo à partir des signaux du CRTC pour générer l’affichage des pixels à la bonne couleur, les écrire dans la mémoire vidéo, générer l’interruption IM1 toutes les 52 lignes...et donner le top pour affichage de l’image d’un écran complet toutes les 1/50em de seconde.

Cette première étape m’a pris beaucoup de temps, plusieurs mois je pense et j’ai retravaillé à plusieurs reprises le code, au fur et à mesure que je gagnais en expertise. L’écriture n’est toujours pas terminée à ce jour, puisque le CPC compte plusieurs variantes de CRTC avec des subtiles différences que je n’ai pas encore implémentées.

En aparté, l’emploi de Direct2D, qui est une API très puissante, va me permettre à l’avenir, je pense d’appliquer des filtres à l’écran pour simuler notamment des scanlines... mais je verrai ça plus tard...ce n’est pas la priorité de l’émulateur.

Cette première grosse étape à peu près fonctionnelle, je m’attaque alors à un autre gros morceau ... l’exploitation des fichiers cassettes et le début de la création des outils de déboggage dédiés... mais ce sera au prochain épisode. :)
Dernière modification par Dmanu78 le 24 avr. 2022 09:58, modifié 3 fois.
Lone
Messages : 16
Inscription : 26 nov. 2020 09:53

Re: [EMULATION AMSTRAD CPC] work in Progress

Message par Lone »

J'aime toujours autant tes comptes rendus : A la fois parce que ça me rappelle des souvenirs pas si vieux, parce que c'est intéressant tout court, et parce que je me rends compte à quel point il existe bien des moyens d'arriver à ses fins.

Pour ma part, j'ai immédiatement mis en place un debugger assez simple, mon premier objectif étant de dérouler le firmware du CPC (au niveau Z80).
La partie FDC est sans doute celle qui m'a le plus passionné, par la suite : Arriver à comprendre le fonctionnement, et faire marcher toutes ces disquettes (surtout celles avec des protections) m'a occupé un bon moment, mais a été vraiment enrichissant.

Bon courage pour la suite !
Dmanu78
Messages : 268
Inscription : 20 juin 2020 14:28
Localisation : Yvelines

Re: [EMULATION AMSTRAD CPC] work in Progress

Message par Dmanu78 »

Merci Lone. Heureux que ces petits posts te plaisent. :) Ça m’encourage à continuer à narrer mes aventures CPCiennes.
Ce qui est intéressant effectivement, c’est que tu as dû te poser les mêmes questions mais que tu as certainement trouvé des solutions techniques différentes. Au final, le résultat semblera identique mais le moteur n’aura rien à voir. C’est fascinant ... comme dirait un célèbre personnage aux oreilles pointues. :wink:

Sans spoiler mes aventures, s’il y a des abonnés :D , j’ai paradoxalement écrit un débogguer très tardivement dans l’étape de développement de l’émulateur. En fait, il est naturellement venu juste après l’écriture de la routine d’émulation du Z80, que j’ai réalisé en tout dernier, après avoir préalablement codé l’émulation des autres puces spécialisées. Je suis parti à l’envers on dirait. :D

Je ne me suis que très récemment attaqué à l’émulation du FDC. C’est très intéressant effectivement de comprendre comment un drive fonctionne. J’ai acheté pour l’occasion le grand livre du lecteur de disquette de micro-application qui contient de nombreuses informations très intéressantes (et quelques coquilles aussi) mais c’est le listing de la ROM de l’AMSDOS qui m’intéresse et ..le schéma électronique de la carte DDI pour comprendre le décodage des adresses IO et les accès aux FDC...
Il me reste ainsi de nombreux épisodes à vous raconter...
Avatar de l’utilisateur
Sebiohazard
Messages : 425
Inscription : 30 avr. 2019 15:07

Re: [EMULATION AMSTRAD CPC] work in Progress

Message par Sebiohazard »

Hello Dmanu !

J'apprécie également tes comptes rendus même si la plupart des informations que je lis ne sont pas encore compréhensibles pour moi :) je prends conscience du travail & de la difficulté de celui-ci & reste fasciné par tout ce que l'on peut faire informatiquement parlant.

J'ai beaucoup de respect & d'admiration pour les programmeurs d'émulateurs BRAVO à eux & merci pour leur travail !

Salutations !
Image
Dmanu78
Messages : 268
Inscription : 20 juin 2020 14:28
Localisation : Yvelines

Re: [EMULATION AMSTRAD CPC] work in Progress

Message par Dmanu78 »

Suite de l'aventure...

Une fois le volet visuel de l'émulateur à peu près sous contrôle, j'ai décidé de m'attaquer à la partie fichier. C'est quand même la moindre des choses qu'un émulateur digne de ce nom puisse lire à minima les formats de fichier les plus répandus le concernant.

Souhaitant émuler un "simple" CPC 464 dans un premier temps, j'ai pris le parti de commencer à traiter les fichiers...Cassette. Le CPC 464 ayant un lecteur de cassette intégré, rendons lui un minimum hommage en permettant à l'émulateur de traiter dignement les fichiers le concernant.

Indépendamment de cela, j'ai toujours été fasciné par le fait qu'un enregistrement sonore sur une simple bande magnétique puisse être transformé en données numériques. Avant de commencer l'émulateur, je ne connaissais rien au fonctionnement qui permettait au CPC, à partir de la lecture de la bande sonore, de transformer le signal sonore en un flux de données qui lui permettraient de charger jeux et utilitaires...

Une recherche sur internet m'a permis de vite comprendre que les fichiers au format "Cassette" utilisés par les émulateurs CPC existants portaient une extension .CDT. Ce format est en fait une version compressée de fichiers PCM au format .WAV . Les premiers font quelques Ko, les seconds quelques Mo...On comprend vite l’intérêt. Dans un premier temps j'exploitais donc pour mes besoins les fichiers brutes au format WAV.

Cette compression est possible car le format d'enregistrement sur CPC est extrêmement simple : chaque "bit" correspond à un signal sonore carré composé de 2 "pulses" : 1 signal HIGH et 1 signal LOW de même période. La période d'un bit "zéro" est 2x plus courte que celle d'un bit "1". C'est très simple. Et voilà pour la théorie...

En pratique, ça devient plus compliqué, comme toujours sur un émulateur. Dans un premier temps, je voulais savoir comment à partir d'un fichier WAV je pouvais en extraire, comme pouvait le faire un vrai CPC, les données numériques qui y était contenues... Et là je mettais le doigt dans une grosse galère...

C'est à ce moment que j'ai commencé à mettre au point un outil d'analyse me permettant de tester mes routines de lectures des fichiers cassette. C’est certainement la partie la moins documentée du CPC : J'ai passé de nombreuses semaines à essayer de comprendre puis à gérer correctement le fonctionnement de la structure des fichiers du CPC : chaque fichier est composé de blocs eux même composé d'une entête, avec des bits de synchro puis de DATA, le tout vérifié par un code CRC. La moindre erreur dans l'interprétation des "pulse" et c'est la sanction..Erreur dans le comptage des bits, incohérence des périodes entre pulses...et fichier illisible.

Cet outil m'a été une aide très précieuse pour comprendre visuellement le fonctionnement d'un fichier puisque je pouvais visualiser les fameux bit 1 et 0 en comparant graphiquement les périodes des signaux sonores et m'arrêter précisément à l'adresse précise où une erreur était détectée afin de comprendre visuellement ce qui clochait.

Le pompon final a été d'arriver à trouver l'algorithme permettant de générer ce fameux code CRC qui est testé en fin de lecture des blocs de données de 256 octets. La littérature parle bien d'un CRC de type "CCITT polynomial en X^16+X^12+X^5+1" mais sans en dire plus. Pour l'implémenter en C, ça a été particulièrement coton. J'ai cherché dans des forums mathématiques comment implémenter cela, et à chaque fois, ça foirait, le CRC calculé était incorrect par rapport à celui lu ! C'est un des rares cas je crois où j'ai recopié par dépit un bout de code en C++ de 8 lignes (!!) trouvé sur un forum espagnol pour implémenter la routine de codage du CRC en question. Et miracle, ça a finalement marché. Un rare moment que l'on savoure à sa juste valeur. J'ai des plaisirs simples :D

Au final, à force de tâtonnement et d'essais, j'ai commencé à pouvoir lire les fichiers et à en extraire les précieuses données. Une sacrée victoire.

Image
Oh joie, l'enregistrement est lu correctement...

Une fois parti en si bon chemin, j'ai décidé d'aller un peu plus loin et de créer une sorte d'éditeur de fichier qui me permettrait de lire le contenu d'un bloc de fichier, puis de reconstituer le fichier dans sa totalité et de l'enregistrer au format désiré...
Image

Image

Le plus dur était terminé mais pour finaliser la gestion des fichiers cassette il me fallait également gérer le fameux format CDT évoqué au début.
Ce furent mes derniers développements sur le sujet (mais qui m'a pris pas mal de temps également le temps de m'approprier les caractéristiques de ce type de fichier).
Image

Au final, j'ai du passer 5-6 mois sur cette partie mais je ne suis pas mécontent du résultat final et j'ai beaucoup appris. Néanmoins, à ce stade du développement de l'émulateur, si mes outils me permettent désormais de lire et de modifier les fichiers cassette, l'émulateur reste bien incapable de lire le fichier à partir des routines de lecture natives situées dans la ROM du CPC...Mais chaque chose en son temps. ça fera partie d'un autre post.

Cette longue partie est enfin terminée... pour en commencer une nouvelle car j'avais un autre os à ronger après cela... La partie sonore...
Et ce sera pour un prochain post. :wink:
Dernière modification par Dmanu78 le 21 déc. 2020 22:45, modifié 2 fois.
yves
Messages : 464
Inscription : 12 sept. 2007 21:32

Re: [EMULATION AMSTRAD CPC] work in Progress

Message par yves »

Quel boulot ! Bravo, la ténacité est récompensée, surtout quand au bout de 6 mois ça se met à fonctionner comme on l'imaginait au départ.

Je suis impatient de lire la suite!

Yves
Répondre