[TZZ80] Z80 avec une gestion des co-routines en hardware ?

Couvre tous les domaines de l'émulation logicielle 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 : 3507
Inscription : 29 nov. 2017 10:23

[TZZ80] Z80 avec une gestion des co-routines en hardware ?

Message par hlide »

Si on étend la file de registre du Z80 à 8 exemplaires, il serait possible de faire des co-routines avec gestion des priorités et simplification de la gestion des interruptions au niveau hardware.

Je m'explique.

Une file de registre du Z80 contient BC/BC', DE/DE', HL/HL', AF/AF', IX, IY, WZ, SP et PC. Il y aura donc 8 files avec un ordre de priorité fixe pour chacune, que l'on va désigner comme des tâches. Le Z80 bootera avec la tâche la plus prioritaire. Si on n'active pas le mode multitâche coopératif, le fonctionnement général du Z80 sera normal comme si il n'y avait aucune tâche. Les registres IR, IM, IFF1 et IFF2 sont communs aux tâches.

Partant du principe que le mode d'interruption IM 0 est un vestige du 8080 qui n'est quasiment jamais utilisé par les systèmes Z80 (IM 1, voire IM 2), il pourrait servir à activer le mode multitâche coopératif (IM 1 et IM 2 désactiveraient ce mode). Il faut également des instructions qui permettent d'installer une tâche, d'activer une tâche ou de céder l'exécution à une autre tâche.

Attention, je précise qu'il n'y a bien qu'un seul processeur Z80 et un seul cœur d'exécution.

LDPC n,HL : modifie le registre PC de la tâche n. On présume que le PC pointe sur un prologue qui se charge d'installer la pile pour cette tâche et de faire l'initialisation nécessaire pour la routine qui suit dans le code.

Code : Tout sélectionner

	LD HL, MyTaskSetup; PC to setup task #3 
	LDPC 3,HL ; setup task #3
	... ; do whatever
Loop:
	... ; do whatever
	RAISE 3 ; active task #3 (this task is supposedly to be more prioritized than the current one)
	... ; do whatever
	JR/JP Loop
	...	
MyTaskSetup: ; call through the first RAISE 3
	LD SP, MyTaskStack ; setup a stack for task #3
	... ; do your necessary initialization
MyTaskRoutine: ; call through the rest of RAISE 3
	... ; do your routine service
	YIELD
	JR/JP MyTaskRoutine
RAISE n : marque la tâche n comme étant active puis ordonne au Z80 de continuer l'exécution sur la tâche active la plus prioritaire. C'est un équivalent à un CALL mais qui ne prend que 4 cycles, voire moins.

YIELD : marque la tâche courante comme étant inactive puis ordonne au Z80 de continuer l'exécution sur la tâche active la plus prioritaire. C'est comme l'équivalent d'un RET mais qui ne prend que 4 cycles, voire moins.

Reste les interruptions.

/RESET : à ce signal, on active la tâche 0 (la plus prioritaire). Elle sera toujours exécutée par RAISE 0. Faut-il que RST 00h en fasse de même ? je me le demande.

/NMI : à ce signal, on active la tâche 1. Elle sera toujours exécutée immédiatement sauf si la tâche 0 est active (elle reprend après un YIELD de la tâche 0). La routine n'a pas besoin de faire de la sauvegarde/restauration des registres en pile puisqu'elle dispose de ses propres registres, d'où un gain d'exécution de l'interruption non négligeable.

/INT : à ce signal, on active la tâche 2. Elle sera toujours exécutée immédiatement sauf si la tâche 0 ou 1 est active (elle reprend après un YIELD des deux tâches 0 et 1). La routine n'a pas besoin de faire de la sauvegarde/restauration des registres en pile puisqu'elle dispose de ses propres registres, d'où un gain d'exécution de l'interruption non négligeable.

RST 00h et 38h : Devrait-on les exécuter respectivement comme un RAISE 0 et RAISE 2 ? ces instructions ont des adresses fixes alors que les tâches 0, 1 et 2 ne sont pas tributaires de ces adresses donc ces instructions peuvent fonctionner indépendamment des tâches sur l'usage que voudra en faire le code système (très souvent le cas sur les machines).

Le registre R étant utilisé pour le rafraichissement et I pouvant être détourné à un usage spécifique (on pense au ZX81 par exemple), il vaut mieux les garder en commun pour toutes les tâches. Le registre IM devant contenir 0, il est logique qu'il soit aussi commun. Et enfin IFF1 et IFF2 ne devrait pas servir à grand chose en mode multi-tâche coopératif.

C'est tout... pour le moment.
panoramic
Messages : 27
Inscription : 19 mai 2010 23:32

Re: [TZZ80] Z80 avec une gestion des co-routines en hardware ?

Message par panoramic »

Qu'est-ce que tu veux faire ?
Un système multitaches à base de Z80 ?
Comment penses-tu coder ces nouvelles instructions LDPC, RAISE, YIELD ?
Tout seul, on va plus vite. Ensemble, on va plus loin.
https://panoramic.1fr1.net/
Avatar de l’utilisateur
hlide
Messages : 3507
Inscription : 29 nov. 2017 10:23

Re: [TZZ80] Z80 avec une gestion des co-routines en hardware ?

Message par hlide »

Je ne me souvenais plus d'avoir posté ici.

TZZ80 est en pause.

Il s'agit de co-routinage, pas du multi-threading préemptif.

Une interruption normale, ça bouffe énormément des cycles pour :
- l'enclencher selon le mode IM
- un prologue doit être exécuté pour push-er les registres à sauvegarder
- un épilogue doit être exécuté pour pop-er les registres à restaurer
- de plus l'interruption exige un SP valide pour sauver l'adresse de retour

Dans ce mode co-routine, il y aura 0 cycles :
- l'interruption est exécutée à l'instruction suivante.
- l'interruption étant dans son propre "thread", le prologue et épilogue disparaissent.
- l'interruption a sa propre pile et son propre SP. Du coup, le thread interrompu peut avoir un SP qui ne pointe pas sur une vraie pile : l'interruption ne bousillera pas le contenu de cette fausse pile.

Prenons un exemple :
- j'ai un thread GAM de jeu qui gère la logique du jeu,
- j'ai un thread BGM de musique plus prioritaire qui peut s'enclencher sur un timer ou sur un signal READY de la puce sonore.

Le thread BGM se contente de fournir à la puce sonore les notes à jouer puis préparer les nouvelles avant de redonner la main à la routine interrompue. La routine a sa propre file de registres, et sera juste une boucle de générateur de notes à jouer qui YIELD-e pour rendre la main au thread GAMP là où il était.

Les instructions peuvent être encodés dans les espaces non-utilisés, genre DDxx, FDxx, DDEDxx ou FDEDxx là où il n'y pas d'encodage H, L, HL ou (HL).

Mais pour être honnête, je ne sais pas si je le ferais un jour.
Répondre