[Amstrad CPC] Qu'est-ce qu'un "cycle" NOP ?

C'est la catégorie reine de l'ordinophile, 8 bits et pas un de plus!
Single board ou bus S-100 acceptés.

Modérateurs : Papy.G, fneck, Carl

Répondre
Avatar du membre
hlide
Messages : 1879
Enregistré le : 29 nov. 2017 10:23

[Amstrad CPC] Qu'est-ce qu'un "cycle" NOP ?

Message par hlide » 24 oct. 2020 15:53

Sujet du jour : comment passe-t-on du cycles M-cycle/T-state au "cycle" NOP cher aux Amstradiens ?

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) :
DRamTiming40010.png
DRamTiming40010.png (26.68 Kio) Vu 322 fois
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___________________________/ *       \___________:
Note : l'astérix indique le moment où l'on passe à T3 si WAITn = 1 et X où on insère un Tw si WAITn = 0.

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   :________________/  *       \___________:
Ô miracle, 4 cycles ! et ce n'est pas tout, le NOP est auto-alignant car les NOP qui suivent feront au final 4 cycles chacun.

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 _____________________________/
Note : l'astérix indique le moment où l'on passe à T3 si WAITn = 1 ou on insère un Tw si WAITn = 0.

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 ___________________________________________________________________/
Voilà : le NOP CPCiste d'une instruction correspond à la période nécessaire pour que celle-ci se termine avec le décodage de l'instruction suivante (on ne prend pas en compte les deux cycles de décodage de son opcode mais celui du suivant qui doit inclure des Tw qui vont permettre à cette période d'être un multiple de 4 cycles).

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.
Modifié en dernier par hlide le 26 nov. 2020 01:52, modifié 1 fois.

Avatar du membre
hlide
Messages : 1879
Enregistré le : 29 nov. 2017 10:23

Re: [Amstrad CPC] Qu'est-ce qu'un "cycle" NOP ?

Message par hlide » 25 oct. 2020 14:16

Supposons qu'il soit possible d'adresser tout l'ensemble des mémoires et des ports I/O à la fréquence 8 MHz (ce qui n'est pas le cas sinon le "fameux HACK de 6 MHz" ne se limiterait pas à 6 MHz). Il faudrait générer un /wait = 0 deux cycles 8 MHz (ou un cycle 4 MHz) après /M1 = 0, que l'on met en AND avec le signal READY pour avoir au minimum un Tw lors de l'opcode fetch. Il faudrait vérifier qu'il n'y ait aucun risque pour qu'un M-cycle MRD, MWR, IOR ou IOW n'ait pas au moins un Tw : ce qui suit tend à montrer que des Tw sont systématiquement insérés.

Quel apport apporterait uniquement le doublement de fréquence du CPU (doublé par un composant PLL à la sortie du GA et le reste étant à leur fréquence habituelle), sachant que le signal /WAITn gardera le même motif qu'à 4 MHz ?

Succession de NOP :

Code : Tout sélectionner

          /        NOP        \   /                    NOP                    \   /                    NOP                    \
         /       M1R:00        \ /                    1R:00                    \ /                    1R:00                    \
        :  T1 |  T2 |  T3 |  T4 :  T1 |  T2 |  Tw |  Tw |  Tw |  Tw |  T3 |  T4 :  T1 |  T2 |  Tw |  Tw |  Tw |  Tw |  T3 |  T4 :
        :_____      |_____      :_____      |_____      |_____      |_____      :_____      |_____      :_____      |_____      :
4MHz    /     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/
        :__   |__   |__   |__   :__   |__   |__   |__   |__   |__   |__   |__   :__   |__   |__   |__   :__   :__   |__   |__   :
8MHz    /  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/
Add Tw  ------------------------------------wwwwwwwwwwwwwwwwwwwwwwww------------------------wwwwwwwwwwwwwwwwwwwwwwww-------------  
        :          _|__________ :           |           |          _|__________ :           |           |          _|__________ :
/WAIT   :_________/ *          \_____________x____________________/ *          \____________x_____________________/ *          \:
                     \_____________ 4 cycles de 4 MHz _____________/ \_____________ 4 cycles de 4 MHz _____________/
L'instruction NOP fait toujours un NOP amstradien (~1ms, soit 4 cycles de 4 MHz) et non 1/2 NOP amstradien !
Il est "auto-alignant" mais avec un nombre de 4 Tw systématique - ce qui permettrait l'accès à la ROM et à la DRAM puisque ça laisserait le temps de lire l'opcode.

Voyons pour LD I,A :

Code : Tout sélectionner

          /                                          LD I,A                                                 \   /                 NOP                 \   /                    NOP                    \
         /                    M1R:ED                    |                       M1R:47                       \ /                M1R:00                 \ /                    1R:00                    \
        :  T1 |  T2 |  Tw |  Tw |  Tw |  Tw |  T3 |  T4 :  T1 |  T2 |  Tw |  Tw |  Tw |  Tw |  T3 |  T4 |  T5 :  T1 |  T2 |  Tw |  Tw |  Tw |  T3 |  T4 :  T1 |  T2 |  Tw |  Tw |  Tw |  Tw |  T3 |  T4 :
        :_____|     |_____|     :_____|     |_____|     |_____:     |_____|     |_____|     |_____|     |_____|     |_____|     :_____      |_____      :_____      |_____      :_____      |_____      :
4MHz    /     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/
        :__   |__   |__   |__   :__   |__   |__   |__   |__   :__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   :__   |__   |__   |__   :__   :__   |__   |__   :__   :__   |__   |__   :
8MHz    /  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/
Add Tw  ------------wwwwwwwwwwwwwwwwwwwwwwww------------------------wwwwwwwwwwwwwwwwwwwwwwww------------------------------wwwwwwwwwwwwwwwwww------------------------wwwwwwwwwwwwwwwwwwwwwwww------------- 
        :           |           |          _|__________ :           |           |          _|__________ :           |           |          _|__________ :           |           |          _|__________ :
/WAIT   :___________x_____________________/ *          \____________x_____________________/ *          \__________________x_______________/ *          \____________x_____________________/ *          \: 
                                             \____________________________________ 8 cycles de 4 MHz ______________________________________/ \_____________ 4 cycles de 4 MHz _____________/
L'instruction LD I,A passe à 2 NOP amstradien au lieu de 3.

Voyons pour LD BC,(nnnn) :

Code : Tout sélectionner

          /                                        LD BC,(nn'nn)                                   LD BC,(nn'nn)                             LD BC,(nn'nn)                                   LD BC,(nn'nn)                                   LD BC,(nn'nn)                                      \   /                        NOP                      \
         /                               M1R:ED         |                    M1R:4B                     |                  MRD:nn                 |                     MRD:nn'                   |                  MRD:(nn'nn)                  |                  MRD:(nn'nn+1)               \ /                       M1R:00                      \
        :  T1 |  T2 |  Tw |  Tw |  Tw |  Tw |  T3 |  T4 :  T1 |  T2 |  Tw |  Tw |  Tw |  Tw |  T3 |  T4 :  T1 |  T2 |  Tw |  Tw |  Tw |  Tw |  T3 :  T1 |  T2 |  Tw |  Tw |  Tw |  Tw |  Tw |  T3 :  T1 |  T2 |  Tw |  Tw |  Tw |  Tw |  Tw |  T3 :  T1 |  T2 |  Tw |  Tw |  Tw |  Tw |  Tw |  T3 :  T1 |  T2 |  Tw |  Tw |  Tw |  Tw |  Tw |  T3 |  T4 :
        :_____|     |_____|     |_____|     |_____|     :_____|     |_____|     |_____|     |_____|     |_____|     :_____|     |_____|     |_____:     |_____|     |_____|     |_____|     |_____|     |_____|     |_____|     |_____|     |_____|     |_____|     |_____|     |_____|     |_____|     |_____|     |_____|     |_____|     |_____|     :     
4MHz    /     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/     \_____/
        :__   |__   |__   |__   |__   |__   |__   |__   :__   |__   |__   |__   |__   |__   |__   |__   |__   |__   :__   |__   |__   |__   |__   :__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   |__   :
8MHz    /  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/
Add Tw  ------------wwwwwwwwwwwwwwwwwwwwwwww------------------------wwwwwwwwwwwwwwwwwwwwwwww------------------------wwwwwwwwwwwwwwwwwwwwwwww------------------wwwwwwwwwwwwwwwwwwwwwwwwwwwwww------------------wwwwwwwwwwwwwwwwwwwwwwwwwwwwww------------------wwwwwwwwwwwwwwwwwwwwwwwwwwwwww------------------wwwwwwwwwwwwwwwwwwwwwwwwwwwwww-------------  
        :           |           |          _|__________ :     2     |     3     |     4    _|__________ |     6     :     7     |     8    _|__________ |     10    |     11    |    12    _|__________ :     14    |     15    |    16    _|__________ :     18    |     19    |    20    _|__________ :     22    |     23    |     24   _|__________ :
/WAIT   :___________x_____________________/ *          \____________x_____________________/ *          \____________x_____________________/ *          \______x___________________________/ *          \:_____x___________________________/ *          \______x___________________________/ *          \______x___________________________/ *          \: 
                                             \___________________________________________________________________________________________________________________________________ 24 cycles de 4 MHz ______________________________________________________________________________________________________________________________________/
L'instruction LD BC,(nnnn) reste à 6 NOP amstradien.

Conclusion, la montée en fréquence bête et méchante ne profite pas vraiment au CPC.

Dmanu78
Messages : 35
Enregistré le : 20 juin 2020 14:28
Localisation : Yvelines

Re: [Amstrad CPC] Qu'est-ce qu'un "cycle" NOP ?

Message par Dmanu78 » 28 oct. 2020 00:12

Merci glide, c’est très intéressant.
Je ne me pose pas vraiment la question des cycles NOP car mon émulateur fonctionne en cycles T-states mais à la lecture des signaux, cela confirme bien que la finalité du signal TWait, en combinaison avec les signaux CAS et RAS, est de permettre au GA d’accéder à la mémoire vidéo à raison de 2 octets lus par cycle de 1Mhz. Le premier accès video se fait sur une adresse vidéo paire (signal CCLK low) et le 2em octet est lu à l’adresse suivante (impaire) juste après que signal CCLK devienne High...
Cela explique pourquoi le CPC ne pourra jamais commencer à afficher une image en partant d’une adresse vidéo impaire...

Répondre