Dans le milieu Amstrad, j'ai constaté qu'ils étaient friands de termes propres à l'Amstrad mais ils n'étaient pas en mesure de m'expliquer comment leur NOP se calculait. Je n'aime pas devoir utiliser un terme qui n'est pas parfaitement clair.
Voici un sortie des signaux que l'on peut trouver sur un CPC 464 (l'image provient d'ici) :
Ce qui nous intéresse, ce sont les signaux 4MHz et surtout WAITn !
On voit que le signal 4MHz est régulier donc aucune surprise de ce côté-là, le Z80 devrait se comporter normalement.
Les signaux MREQn, RDn/WRn sont actifs sur cinq types de M-cycle : OPCODE FETCH (M1 : 4 T-states), MEMORY READ/WRITE (Mx : 3 T-states), I/O READ/WRITE (Mx : 4 T-states).
La particularité de ces M-cycles, c'est qu'ils peuvent allonger leur nombre de T-states (correspond à un cycle de 4MHz ici) en interrogeant à la fin du T-state T2 si le signal WAITn est à 0.
Regardez le signal WAITn : c'est un motif répété de quatre cycles de 1 WAITn à 1 suivi de 3 WAITn à 0. Cela va avoir une incidence sur les M-cycles ci-dessus.
Soit une instruction NOP mal alignée :
Code : Tout sélectionner
: M1R:T1 | M1R:T2 | M1R:Tw | M1R:Tw | M1R:Tw | M1R:T3 | M1R:T4 :
:____ |____ |____ |____ |____ |____ |____ :
4MHz / \____/ \____/ \____/ \____/ \____/ \____/ \____/
: | | | | | ________|_________:
/M1 :\__________________wwwwwwwwwwwwwwwwwwwwwwwwwwwwww_/ | :
:_____ | | | | | ____ | ___:
/MREQ : \_____________wwwwwwwwwwwwwwwwwwwwwwwwwwwwww_/ \_________/ :
:_____ | | | | | __________________:
/RD : \_____________wwwwwwwwwwwwwwwwwwwwwwwwwwwwww_/ | :
: _|_______ | | | _|_______ | :
/WAIT :_______/ \_X___________________________/ * \___________:
Là on a 7 cycles pour ce NOP et non 4 cycles !
Et le NOP suivant ?
Code : Tout sélectionner
: M1R:T1 | M1R:T2 | M1R:T3 | M1R:T4 :
:____ |____ |____ |____ :
4MHz / \____/ \____/ \____/ \____/
: | | __________________:
/M1 :\___________________/ :
:_____ | | ____ | ___:
/MREQ : \______________/ \_________/ :
:_____ | | __________________:
/RD : \______________/ | :
: | __|_______ | :
/WAIT :________________/ * \___________:
En fait toutes les instructions de 4 cycles présentent le même effet : elles s'auto-alignent sur 4 cycles avec ce motif du WAITn et s'exécuteront en 4 cycles.
Les instructions de 8 cycles ont le même effet car il s'agit de deux opcodes fetches (ED xx par exemple) et s'autoalignent au même titre que deux NOP.
Mais est-ce que toutes les instructions sont auto-alignantes ?
Prenons le cas de LD I,A (9 cycles) suivi d'un NOP :
Code : Tout sélectionner
/ LD I,A \ / NOP \
/ M1R:ED | M1R:47 \ / M1R:00 \
: T1 | T2 | T3 | T4 : T1 | T2 | T3 | T4 | T5 : T1 | T2 | Tw | Tw | Tw | T3 | T4 :
:__ |__ |__ |__ :__ |__ |__ |__ |__ :__ |__ |__ |__ |__ |__ |__ :
4MHz / \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/
Add Tw ------------------------------------------------------------------wwwwwwwwwwwwwwwwww-------------
: | _|____ | 2 : 3 | 4 _|____ | 6 | 7 : 8 _|____ | 10 | 11 : _|____ | :
/WAIT :_________/ * \________________/ * \________________/ \X_______________/ * \______:
\______________________________ 12 cyles _____________________________/
Et bam ! le NOP qui suit prend 7 cycles au lieu de 4 cycles !
Maintenant regardons le nombre de cycles entre les * de LD I,A et NOP : 12 cycles, soit l'équivalent de 3 NOP. Tiens ça correspond au nombre de NOP CPCistes pour LD I,A !
Donc effectivement, le nombre de cycles passés entre chaque T2->T3 réussi du M1 des instrutions est multiple de 4 cycles, soit un NOP CPCiste.
Mais les choses deviennent un peu plus complexe quand se suivent des M-cycles pour les accès mémoires ou port I/O à la suite du M-cycle M1 : ceux-là ont aussi une transistion T2->T3 sensible au WAITn qui peuvent provoquer un désalignement sur le M-cycle sensible. Cela explique pourquoi certaines instructions ne s'arondissent pas de la même manière en nombre de NOP CPCiste.
Ainsi LD BC,(nnnn) va prendre 6 NOP, soit 24 cycles au lieu de 20 cycles habituels car la lecture de l'adresse nnnn puis de ses deux octets de contenu doit se faire en 4 M-cycles de 3 T-states qui ne sont pas des multiples de 4 cycles donc des insertions de Tw à la clé.
Code : Tout sélectionner
/ LD BC,(nn'nn) \ / NOP \
/ M1R:ED | M1R:4B | MRD:nn | MRD:nn' | MRD:(nn'nn) | MRD:(nn'nn+1) \ / M1R:00 \
: T1 | T2 | T3 | T4 : T1 | T2 | T3 | T4 : T1 | T2 | T3 : T1 | T2 | Tw | T3 : T1 | T2 | Tw | T3 : T1 | T2 | Tw | T3 : T1 | T2 | Tw | T3 | T4 :
:__ |__ |__ |__ :__ |__ |__ |__ :__ |__ |__ :__ |__ |__ |__ :__ |__ |__ |__ |__ |__ |__ |__ :__ |__ :__ |__ |__ :
4MHz / \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__:
Add Tw ------------------------------------------------------------------------------wwwwww------------------wwwwww------------------wwwwww------------------wwwwwww------------
: | _|____ | 2 : 3 | _|____ | 6 : 7 | 8 _|____ : 10 | 11 | _|____ : 14 | 15 | _|____ : 18 | 19 | _|____ | 22 : 23 | __|___ | :
/WAIT :_________/ * \________________/ * \________________/ * \____________x___/ * \____________x___/ * \____________x___/ * \____________x___/ * \______:
\_________________________________________________________________ 24 cyles ___________________________________________________________________/
J'ai envie de dire que le comptage en NOP doit être suffisant dans la très grande majorité des cas. Là où ça peut être compliqué, c'est quand la précision en cycle est demandée par rapport à un périphérique qui demanderait un timing plus précis.