In-Circuit Emulator pour Z80 (ICE) ?

Cet espace concerne les composants électroniques, les techniques de réalisation, le soudage, la mesure et ses divers instruments, les programmateurs ou encore votre laboratoire. Recueille également les éventuelles ventes, achat, dons ou recherches.

Modérateurs : Papy.G, fneck, Carl

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

Re: In-Circuit Emulator pour Z80 (ICE) ?

Message par hlide »

Donc j'ai fait l'assemblage et j'utilise EMUZ80 en plaçant le MLCZ8 dans le socle Z80. J'ai purgé certaines choses spécifiques au TRS80 (adressage) pour le faire tourner en mode 0 comme un Z80 standard. EMUZ80 émule une ROM contenant un BASIC et une RAM de 4 Ko et une zone I/O ($E000-$FFFF) qui permet de lire/écrire via l'UART.
IMG_20230129_143735.jpg
IMG_20230129_143735.jpg (630.13 Kio) Consulté 3602 fois
Début prometteur :
323530521_1158727681682196_4317118681810356938_n.png
323530521_1158727681682196_4317118681810356938_n.png (21.17 Kio) Consulté 3602 fois
J'ai noté une bizarrerie de la part de l'auteur : il se sert du cycle machine M1 (4 T-state donc avec /M1 = 0 et REFRESH) au lieu du cycle MEMORY READ (3 T-state) pour récupérer les octets de valeurs immédiates ou de déplacement qui suivent l'opcode. Ça me fait douter à propos des timings supposés être "accurate". J'ai donc changé ça pour coller au plus près de l'attendu et je viens de lancer un ASCIIART pour vérifier que cela va bien jusqu'au bout.

EDIT : je viens à l'instant de voir qu'il a lu mon ticket GitHub et apporté la correction.
gotcha
Messages : 2758
Inscription : 30 mars 2017 11:39
Localisation : Isère
Contact :

Re: In-Circuit Emulator pour Z80 (ICE) ?

Message par gotcha »

Donc si j'ai bien compris, tu émules un Z80 dans un système qui lui même est émulé :lol:
EMUZ80 tourne à combien de Mhz ?
Amstrad CPC et Goupil power :mrgreen:
Bénévole à l'association pour un conservatoire de l’informatique et de la télématique (https://www.aconit.org)
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: In-Circuit Emulator pour Z80 (ICE) ?

Message par hlide »

Dans le firmware EMUZ80, on peut le configurer dans le source. Là j'ai mis 2MHz mais je devrais monter à 4MHz sans mal. Le défaut de ce EMUZ80, c'est qui lui manque une SRAM pour permettre des accès mémoire à plein régime car le PIC dans son émulation de la RAM/ROM est obligé de mettre un /WAIT=0 pour faire patienter le Z80 (genre 5 à 6 cycles quand même) donc c'est lent. Pour le moment, j'adapte le firmware Z80 pour un Z80 standard à tester sur un MZ-80 K pour une autre personne. Il me faudra rajouter la possibilité de lire/écrire un SD pour pouvoir lancer des programmes via un menu. A terme, on peut envisager plein de possibilité avec ce Z80 virtuel.
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: In-Circuit Emulator pour Z80 (ICE) ?

Message par hlide »

Alors, j'ai à nouveau jeté un coup d'œil sur IZE80 : au niveau PCB, ça n'a pas l'air trop mal mais malheureusement je n'ai pas l'impression que l'auteur ait publié les sources pour pouvoir le fabriquer. On n'a plus de nouvel depuis 2019 (date de la vidéo). Et tout se qui suit après est juste de l'ordre de la communication. C'est plus frustrant qu'autre chose.

Pour revenir au MLCZ8, vu le nombre de broches utilisées pour l'émulation Z80 (38 je crois), j'avais eu peur que le lecteur de carte SD ait des broches partagées avec celle du GPIO. Mais il en est rien :). Je peux accéder au SD, y lire et écrire. Plus ça va, plus j'apprécie ce Teensys 4.1 car il en a dans le ventre et il n'est pas avare en broche contrairement aux Arduino où il faut toujours faire un compromis au niveau des fonctionnalités (ajouter un lecteur SD condamne nécessairement des broches GPIO).

J'ai commandé deux 4.1 supplémentaires et quatre PSRAM (8Mo chacun, cumulables jusqu'à 16 Mo par Teensys) à souder sous les Teensys 4.1 pour voir si comme pour le lecteur SD, la fonctionnalité QSPI des PSRAM n'empiètent pas les broches GPIO utilisés : son utilisation pourrait ouvrir à de l'extension de mémoire sous différente forme pour une machine Z80 (ou le Teensys lui-même). D'autre part, j'ai noté que j'avais 4 autres GPIO libres qui pourront servir à implémenter le /BUSRQ et /BUSACK si besoin est. Ou d'autre fonctionnalité plus spécifique à une machine.

J'entrevois un tas de possibilité avec ce MLCZ8, c'est fou.

Par contre, le choix d'association des broches à dû se faire au détriment du logiciel pour "simplifier" le matériel. Résultat, il faut lire les données et l'adresse sur plusieurs registres et utiliser une table pour remettre leur bit dans l'ordre. Pour de l'émulation optimale, j'aurais plutôt chercher à caser les bits dans le bon ordre pour diminuer les opérations, voire éliminer la table. Mais bon, c'est mon heure grognon de l'instant.

Concernant l'émulation du Z80, j'ai repéré quelques bugs :
1) utiliser un cycle machine FETCH_OPCODE de 4 T-cycles au lieu du cycle READ_MEM de 3 T-cycles pour obtenir les valeurs immédiates encodés après l'opcode. A fait l'objet d'un ticket que l'auteur a corrigé.
2) Certaines instructions ont des cycles insérés au milieu dans la chaine des cycles machine or MLCZ8 les repoussent à la fin de l'instruction. Par exemple : DJNZ nn -> 10 nn -> Cycles : taken (5, 3*, 5). Le MLCZ8 va l'exécuter comme (4, 3*, 6). Ce qui veut dire que le déplacement nn va être lu un cycle trop tôt (*: cycle machine READ_MEM). Pour la majorité des machines, cela semble sans conséquence mais pour un Amstrad CPC qui se sert de /WAIT pour cadencer, cela peut influencer négativement sur les timing. J'ai crée un ticket, on verra ce qu'en pense l'auteur.

Voilà, voilà !
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: In-Circuit Emulator pour Z80 (ICE) ?

Message par hlide »

Bon petite photo montrant le lancement de DRAM TESTER sur mon MZ-80 K comme ROM virtuel à la place du MONITOR d'origine depuis le SD.

Mais il reste un bug qui semble venir de l'émulateur Z80 qui sous le feu du test de la DRAM (qu'elle soit réelle ou fictive venant de la RAM interne du Teensys) peut provoquer une alarme (led du MZ qui clignote entre vert et rouge avec le son), ce qui indiquerait que la comparaison d'un octet écrit puis lu ne donne pas la valeur identique. Donc, un peu douché après l'enthousiasme initial. Ma confiance envers l'émulation du Z80 présent dans ce Teensys en a pris un coup. Je sens que ça ne va pas être évident à déboguer...
IMG_20230205_204526 - Copy.jpg
IMG_20230205_204526 - Copy.jpg (748.07 Kio) Consulté 3389 fois
L'effet de neige est propre au MZ-80 K : le circuit vidéo récupère l'octet lu/écrit par le CPU au moment où il veut lire pour afficher, créant cet effet de neige qui disparait dès que le CPU arrête d'accèder à la RAM vidéo.
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: In-Circuit Emulator pour Z80 (ICE) ?

Message par hlide »

Et en fait, non. Il y a plusieurs bizarreries sur le comportement du MLCZ8 après avoir relu le source de DRAM TESTER :

1) L'alarme ne devrait se passer qu'au début du programme quand ce dernier vérifie la VRAM et qu'elle est en échec.

2) Le test de DRAM devrait afficher un symbole O pour chaque puce de la rangée quand elle passe le test associé ou le symbole X quand elle ne le passe pas, et les tests se font en boucle, sans arrêt jusqu'à pression de la barre d'espace pour revenir à l'intro. Or je ne vois aucun X et ce n'est pas normal que soudain je me trouve dans le code d'alarme.

3) Il ne devrait pas y avoir d'effet de neige lorsque je suis dans l'intro. En effet, il attend l'appui de la touche espace pour passer au test suivant et donc il ne redessine pas en permanence l'écran : durant l'attente de la touche, le CPU ne fait pas d'accès à la VRAM (c'est ce qui fait l'effet de neige).

Il faut dire que ça ressemble à un gros merdier la façon dont le firmware a de manipuler le bus Z80 via les GPIO. La gestion du bus d'adresse et des données me laisse un peu perplexe d'ailleurs. :shock:
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: In-Circuit Emulator pour Z80 (ICE) ?

Message par hlide »

Bon petit retour sur ce MCLZ8 et ce que j'en pense.

Tout d'abord, le MCU K64 qui embarque Teensys 4.1 est, je dois dire, une merveille. Le Teensys 4.1 aussi à sa façon :

1) Beaucoup de GPIO (une cinquantaine apparemment sans conflit avec les périphériques USB et µSD).
2) Le µSD est en SDIO (donc véloce) et a ses propres lignes (pas d'impact sur les GPIO dédiés au bus Z80).
3) L'USB en mode device a aussi ses propres lignes et on peut avoir plusieurs fonctions (par exemple 2 ou 3 séries).
4) On peut souder jusqu'à deux PSRAM en QSPI pour un total de 16 Mo. Ça peut ouvrir à des extensions de mémoires. Pour l'heure, je ne les ai pas encore rajouté sur mes Teensys 4.1 pour les tester.

Maintenant, il y a quand même beaucoup de frustrations :

1) le routage "paresseux ?" des lignes de bus Z80 fait que l'on complexifie la partie software au profit du hardware. Inutile de me dire que ça me choque. En effet, il faut faire 5 accès 32-bit à des tableaux de mémoire pour fabriquer les 16 bits d'adresse à sortir sur le bus Z80 !

Code : Tout sélectionner

	register uint8_t local_address_high = (local_address) >> 8;
	register uint8_t local_address_low = (0x00FF & local_address);

	register uint32_t gpio7_out = gpio7_high_array[local_address_high] | gpio7_low_array[local_address_low];
	register uint32_t gpio8_out = gpio8_high_array[local_address_high];
	register uint32_t gpio9_out = gpio9_high_array[local_address_high] | gpio9_low_array[local_address_low];
Résultat, un gâchis dans le cache des données ! oui parce que vu que l'ordre des bits An est dans un désordre, l'accès à une adresse contiguë ne se traduira pas un accès dans la même entrée du cache.
Si un effort avait été fait au niveau du routage, on aurait pu ordonner ces bits dans dans deux ou trois paquets et on ferait l'économie de ces accès de tableaux (sorte de LUT en somme).

Pareil pour le bus de données à l'écriture :

Code : Tout sélectionner

		digitalWriteFast(PIN_AD7_OUT, (local_data & 0x80));
		digitalWriteFast(PIN_AD6_OUT, (local_data & 0x40));
		digitalWriteFast(PIN_AD5_OUT, (local_data & 0x20));
		digitalWriteFast(PIN_AD4_OUT, (local_data & 0x10));
		digitalWriteFast(PIN_AD3_OUT, (local_data & 0x08));
		digitalWriteFast(PIN_AD2_OUT, (local_data & 0x04));
		digitalWriteFast(PIN_AD1_OUT, (local_data & 0x02));
		digitalWriteFast(PIN_AD0_OUT, (local_data & 0x01));
		digitalWriteFast(PIN_DATA_OE_n, 0);
Pas terrible non plus... alors oui je conçois que le choix de mapping des GPIO par le Teensys ne facilite pas les paquets. Mais là l'auteur MCLZ8 n'a pas simplifier les choses. Je mets ça sur le compte du prototypage qui ne souhaitait pas s'embarrasser d'un routage très complexe.

2) Le firmware Z80 est-il parfaitement exact et précis ? clairement pas au niveau timing. L'auteur indique avoir passé avec succès le test ZEXALL mais certainement pas celui du timing. J'ai ajouté dans le code qui lit le nombre de cycles ARM entre chaque opcode lu et l'enregistre dans un tableau séquentiel en nombre de cycles Z80 pour ensuite me le balancer sur la console USB.

Code : Tout sélectionner

0000-C3 : 10
004A-31 : 10
004D-ED : 4
004E-56 : 7  != 4  (+3 !) // IM 1 [ED56] -> 4, 4
004F-CD : 25 != 17 (+8 !) // CALL nn [CDxxxx] -> 4, 3, 4, 3, 3 (le firmware rajoute "clock_counter = clock_counter + 7;" !?)
0FC9-21 : 11 != 10 (+1 !) // LD HL,nnnn -> 4, 3, 3 (pas encore déterminé la dérive de +1)
0FCC-36 : 11 != 10 (+1 !) // ...
0FCE-36 : 11 != 10 (+1 !)
0FD0-36 : 11 != 10 (+2 !) // se pourrait-il que le +2 soit en fait +1 avec l'autre +1 à transférer sur 3E ?
0FD2-3E : 6  != 7  (-1 !) // LD A,n -> 4, 3 (hein ? plus rapide que son ombre ?)
0FD4-32 : 14 != 13 (+2 !)
...
Je veux bien admettre que le calcul de cycles peut avoir une dérive de 1 cycle au niveau calcul. Mais c'est inquiétant car difficile de déterminer les raisons quand on sait que je suis obligé d'utiliser l'Arduino IDE 1.8 et qu'il n'y a pas de débogueur.

Bref, je sens que je vais revoir de fond en comble le système de timing de ce firmware.

Conclusion : ce projet n'est pas encore prêt. Il a besoin d'être revu. Et ça va me donner plus de boulot.
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: In-Circuit Emulator pour Z80 (ICE) ?

Message par hlide »

Bon j'ai affiné le calcul des cycles :

1) je sors désormais directement sur la console USB ces cycles sur les OPCODE FETCH (les autres cycles M de l"instruction sont intégré magiquement dans le calcul). J'ai calculé que pour sortir en série, ça prenait environ 2 cycles de plus par instruction donc pas dramatique.

Code : Tout sélectionner

		...
		local_byte = bus_fetch_opcode(register_pc);
		// registre hardware qui donne le compte courant en cycles ARM (816 MHz)
		uint32_t cycles = ARM_DWT_CYCCNT;
		// nombre de cycles Z80 (2 MHz)
		Serial.printf("%04X-%02X : %d\n", tstates_address, tstates_opcode, uint8_t((tstates_cycles_new - tstates_cycles_old) * 2 / 816));
		tstates_address = register_pc;
		tstates_opcode = local_byte;
		// on retire les cycles ARM passé à envoyer en série pour ne garder que le compte de cycle Z80 réel de l'instruction suivante  
		tstates_cycles_new += ARM_DWT_CYCCNT - cycles;
		...
Sur le "M1 T1 Rising Edge", on fait :

Code : Tout sélectionner

	// T1
	bus_clk_rising_edge(); // T1 Rising Edge
	{
		tstates_cycles_old = tstates_cycles_new;
		tstates_cycles_new = ARM_DWT_CYCCNT;
		...
	}
	...
Pour le coup, j'obtiens des cycles Z80 réels plus juste (moins de dérive maintenant) qui montrent que MCLZ8 ne maîtrise pas bien le timing réel de certaines instructions Z80.

2) Les instructions avec le préfixe ED ont un timing foireux. En cause, une table de cycles qui ajoute des cycles de trop (correspond en fait aux cycles de l'opcode fetch du préfixe ED). Le CD (CALL nnnn) qui rajoute en dur 7 cycles dans le code et 6 cycles pour C9 (RET). Je n'ai pas encore rencontré les cas des préfixe CB, DD et FD mais j'imagine qu'ils doivent être revu aussi.

Code : Tout sélectionner

0000-C3 : 10
004A-31 : 10
004D-ED : 4
004E-56 : 7	KO (!= 4)
004F-CD : 24	KO (!= 17)
0FC9-21 : 10
0FCC-36 : 10
0FCE-36 : 10
0FD0-36 : 10
0FD2-3E : 7
0FD4-32 : 12	KO (!= 13)
0FD7-C9 : 16	KO (!= 10)
0052-3E : 7
0054-CD : 23	KO (!= 17)
0012-C3 : 10
0935-FE : 8	KO (!= 7)
0937-CA : 9	KO (!= 8)
093A-C5 : 10	KO (!= 11)
093B-4F : 4
093C-47 : 4
093D-CD : 23	KO (!= 17)
0DA6-F5 : 11
0DA7-3A : 13
0DAA-07 : 4
0DAB-30 : 7
0DAD-3A : 12
0DB0-07 : 4
0DB1-38 : 12
0DAD-3A : 13
0DB0-07 : 4
0DB1-38 : 12
0DAD-3A : 13
0DB0-07 : 4
0DB1-38 : 12
0DAD-3A : 13
0DB0-07 : 4
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: In-Circuit Emulator pour Z80 (ICE) ?

Message par hlide »

Purée, je me prends la tête...

d'un côté je continuais avec la version originale du firmware Z80 que je modifiais au fur à mesure et de l'autre j'écrivais un nouvel émulateur en partie basé sur celui de Chips de Floooh. Cependant, j'ai pris soin d'extirper la partie qui accède le bus Z80 et de le placer dans son propre source (MZ-80K-CPU.bus.h) afin de le partager entre ces deux firmwares. Au départ, j'avais l'intention de corriger les timings de cycles dans l'original mais c'est un tel foutoir que ça me dissuade d'y perdre mon temps. Donc une fois que j'ai pu constater que j'arrivais dans le prompt du monitor et que je passais bien la routine d'attente de la VSYNC (on attend le début du signal puis sa fin), je me suis décidé à passer au nouveau firmware et là bizarrement je reste bloqué sur l'attente de la VSYNC. C'est à se tirer les cheveux ! parce que la routine qui va lire l'octet contenant le bit VSYNC (bit 7) dans le bus Z80 est strictement la même en terme de source ! et pourtant elle donne un résultat différent - à savoir toujours $A0 au lieu d'une combinaison changeante de $0D/$8D/$AD. J'en perds mon latin ou toute autre langue que vous jugerez plus adéquate.

Evidemment, étant sous Arduino 1.8.x, impossible de déboguer le firmware comme l'on pourrait faire avec un binaire sous Windows/Linux/MacOS. J'en suis réduit à faire des traces dans le terminal USB et de récupérer un fichier pour analyser le comportement mais tout cela a un coût en terme de performance comme en neurone.

Je vous jure... si Arduino pouvait au moins me garder les fichiers assembleurs construits à partir du source, ça m'aiderait beaucoup... mais visiblement ça n'est pas possible sans touiller dans le tréfond de leurs scripts j'imagine.

EDIT:

Ce que je constate :

- si je compile via vMicro (extension Arduino sous Visual Studio C++), le résultat est pire car pas de trace des instructions exécutées. J'ai la possibilité de générer une vue désassemblée mais le processus de compilation devient trop long et la lecture de source désassemblé est contre-intuitive. Donc, il y a clairement un code généré non fonctionnel qui n'est pas identique à celui que je produis directement avec Arduino 1.8 et pourtant je pointe bien sur la même suite. Conclusion, ne pas passer par la compilation vMicro.

- si je compile directement via l'Arduino IDE, j'ai mes traces mais je ne sais pas comment ordonner de me garder les sources assembleurs générés. Pour un même source MZ-80K-CPU.bus.h (contenant la routine qui me devrait lire un octet sur le bus) et deux sources MZ-80K-CPU.z80.h différents, j'obtiens un octet différent sans explication rationnelle. Certes, mon source utilise la programmation générique par template pour me permettre de factoriser l'émulation des instructions par le triplet (X,Y,Z) que l'on trouve ici et déléguer le boulot d'optimisation au compilateur, mais je ne vois pas comment cette routine serait impactée.

- je me suis placé en "optimisation en taille" (-Os), ce qui réduit considérablement la taille du binaire. Il me reste donc à trouver le moyen de forcer les options "-save-temps=obj" et "-fverbose-asm" pour garder le source assembleur et comparer la routine mais je peine à trouver où.
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: In-Circuit Emulator pour Z80 (ICE) ?

Message par hlide »

Là je reviens sur le sujet principal du fil car je suis tombé par hasard sur un autre Z80 ICE : https://www.retrobrewcomputers.org/doku ... man:z80ice

Je ne sais pas ce qu'il vaut mais clairement on ne pourra pas en acheter un tout monté. Je n'ai pas trouvé les sources pour le PIC18 et le CPLD mais uniquement des binaires à téléverser - ce qui ne permet pas de choisir d'autres composants.

Et puisque c'est le PIC18 qui fait la partie ICE, je doute que le Z80 fonctionnera réellement à son plein régime. Il y a des chances que pour le PIC18 ait le temps de traiter, il fasse "patienter" le Z80 et donc la vitesse réelle du CPU sera bien en-dessous comme je l'avais expérimenté avec EMUZ80 (qui lui n'est même pas un ICE !). Enfin bon, comme je n'ai pas les détails, c'est difficile à dire.
Notator
Messages : 1286
Inscription : 09 août 2015 20:13

Re: In-Circuit Emulator pour Z80 (ICE) ?

Message par Notator »

Je ne sais pas, mais il semblerait qu'il calibre son montage pour pédaler jusqu'à 6 MHz, ce qui est largement suffisant pour émuler un Z80 (c'est moi qui ait mis en rouge le passage déterminant) :

"The most difficult part of this project is sourcing and programming the CPLD. The parts list calls for a 10ns part, but I have found that any parts from 5 to 15ns seem to work fine at least up to a 6mhz system (I did not test any higher clock speeds). Be warned that older XC9536 parts are unrecognized by the currently available programming software and are probably not usable. These older parts have codes ASJ. Parts with AEM and AMM codes seem to work fine. XC9536XL parts also cannot be used as they are for 3.3v. Lastly make sure to watch the format as some parts out there are in PLCC or BGA encapsulation which would require revising the circuit board design".

On n'a pas trop de détails (du moins sur cette page-là), mais il semblerait que le plus gros du travail soit fait par le CPLD, et le PIC jouerait un rôle de superviseur...
Notator est le nom d'un programme séquenceur Midi et notation musicale pour Atari ST(e) (puis Mac).
Avatar de l’utilisateur
hlide
Messages : 3469
Inscription : 29 nov. 2017 10:23

Re: In-Circuit Emulator pour Z80 (ICE) ?

Message par hlide »

Si tu vas par là, EMUZ80 peut monter à 6 MHz, voire beaucoup plus (mais il faut modifier une ligne dans le code qui gère l'accès d'écriture en mémoire). Le truc, c'est qu'il se sert de /WAIT = 0 pour laisser le temps au PIC18 de traiter la demande du Z80 : le Z80 tourne effectivement à la fréquence que l'on spécifie en MHz mais il se mange des cycles de /WAIT=0 qui font que l'opcode fetch et les accès mémoires ne se font plus respectivement à 4 et 3 cycles mais avec d'autant plus de cycles suite aux /WAIT=0 qu'il y a de fréquence. Dans le cas de EMUZ80 sans SRAM (on utilise alors la mémoire interne du PIC18), ça fait des fréquences équivalentes d'exécution par instruction Z80 qui avoisinent plutôt le demi MHz dans les faits (le gain est logarithmique par accroissement de fréquence). C'est pourquoi, je reste assez dubitatif car un PIC18, c'est du 64 MHz max et comme une instruction PIC, c'est 4 cycles minimum, ça fait du 16 MHz par instruction PIC. Tu n'imagines pas les arrachages de cheveux pour essayer de réduire au minimum ces foutus cycles de /WAIT=0.

Alors oui, il y a le CPLD qui peut aider à l'acquisition des signaux mais ça ne fera pas accélérer le programme en PIC. Pour du pas à pas, ç'est ok. Mais pour tracer en full speed, c'est mort à mon avis.
Répondre