ASMtrad CPC

Apprenez l'assembleur Z80

Intérruption Raster et Intérruptions DMA.

Notre gx4000 et notre cpc+ disposent de 4 interruptions DMA différentes.

- Une interruption raster
- 3 interruptions DMA son

Pour les utiliser comme toujours, n'oubliez pas de délocker l'ASIC et de connecter la page I/O ASIC avant d'envoyer votre valeur.

L'interruption DMA raster:

En mode normal, la seule interruption ayant court est l'interruption envoyée par le Gate Array. Celle-ci est envoyée 300 fois par seconde.
L’inconvénient de cette interruption est principalement que vous ne pouvez choisir le moment où elle a lieu avec précision.
Aussi, pour se caler dessus, vous n'aurez le choix qu'entre l'un des 6 moments ou elle a lieu par VBL.

Les interruptions raster corrigent le tir. Avec elles,vous pourrez choisir à la ligne prêt quand elles seront envoyées.

Pour décider de la ligne à laquelle vous voulez une interruption, vous devez envoyer au PRI en #6800 le numéro de la ligne à laquelle vous voulez cette interruption.
En envoyant 2 dans PRI, vous aurez donc une interruption raster en ligne 2.
Les interruptions raster sont prises en compte pendant la HBL. Aussi vous serez donc précis à la ligne.

Lorsqu'une interruption raster est mise, les interruptions GA sont annulées: il n'y en aura plus.
Ainsi, si vous mettez une seule interruption raster par écran, il n'y aura que cette interruption et aucune interruption GA.

Si PRI=0 alors il n'y aura pas d'int raster et le GA rétablit ses interruptions.

Vous vous demandez sans doute comment avoir plusieurs int raster par écran ?

Rien de plus simple: vous devez les programmer les unes après les autres.

ex:

                            LD        A,2
                            LD        (#6800),A        ;interruption ligne 2
                            HALT                       ;on attend l'interruption. Au HALT nous sommes donc à la ligne 2
                            LD        A,10
                            LD        (#6800),A        ;interruption ligne 10
                            HALT                       ;vous êtes à la ligne 10
                            ...

Comme vous l'avez remarqué, PRI est sur 8 bits. Ceci signifie que vous ne pouvez mettre un numéro de ligne supérieur à 255.
Hors sur un moniteur de CPC+ chaud on voit un peu plus de 280 lignes...
Comment faire pour avoir une int raster après 255 lignes ?
Et bien là encore c'est simple: PRI boucle à 0 après avoir atteins 255 !!!

Ainsi, si après avoir dépassé la ligne 10, vous demandez une int raster ligne 8, vous aurez donc une int raster à la ligne 255+8=263.

Dernier petit point à aborder: PRI est fonction des registres du CRTC.
Aussi, celui-ci bouclera à 0 au bouclage de C4 du CRTC.
Attention donc !!! Ceci est valable aussi pour les interruptions DMA.
Ainsi si vous faites de la rupture d'écran (splitscreen) avec le CRTC, n'oubliez pas que les int pourront se répéter.

Les interruptions DMA son:

Nous disposons de 3 DMA son.
Ceux-ci n'ayant rien à voir avec les 3 voix son du cpc.
Chaque DMA peut exécuter du son sur chaque voix.

Mais chaque DMA dispose d'une int DMA son.
Aussi nous avons 3 DMA pouvant chacun provoquer une int.

Comment ça se passe ?

Il vous faudra lire l'article sur les DMA son pour bien comprendre le fonctionnement.
Mais je vais ici exposer juste ce qu'il faut pour mettre en place les int DMA son.

Chaque DMA son peut lire une DMA-list.

Une DMA list c'est en gros une liste (forcément en RAM centrale) qui comprend des instructions dans un langage spécifique.

Pour déterminer l'adr d'une DMA-list voici un tableau vous donnant les adresses ou les poker:

Définition des adresses des DMA-list
DMA n°ADRESSE (SAR)
0#6C00-#6C01
1#6C04-#6C05
2#6C08-#6C09

Vous donnerez donc à ces adresses, l'adresse de votre DMA list (si vous n'utilisez qu'une DMA list, vous n'avez pas besoin de préciser les autres).

Pour provoquer une interruption DMA vous devrez utiliser l'instruction INT qui a pour valeur #4010.
A chaque fois que cette valeur sera présente dans votre DMA-list, une interruption sera générée.

Notez que toutes les instructions DMA sont sur 2 octets et qu'une DMA-list commence TOUJOURS sur un octet pair et le poids faible de votre instruction doit être en tête (donc sur l'octet pair).

A chaque HBL, une instruction est lue pour chaque DMA list. Ce qui nous fait une instruction par ligne et par DMA.

L’intérêt de ces int DMA peut être par exemple de synchroniser quelque chose avec la musique ou... de générer une liste d'interruptions DMA par écran.
Je vous ai concocté un petit exemple afin de vous montrer comment générer une liste d’interruptions.

Le programme est simple et très commenté afin que tous s'y retrouvent.
Il fait appel à quelques autres chapitres comme par exemple comment changer les couleurs avec le GA ou utiliser la pile.

En lui même voici ce que fait se programme:

nous aurons une interruption raster, qui, quand elle arrivera, sautera à une routine qui lancera une DMA-list et l'initialisera (donc la remettra à 0 à chaque int raster).
Cette int raster fera un raster bleu afin de voir ou elle a lieu sur l'écran.

D'autre part nous aurons une routine de raster rouge, dans laquelle sauteront toutes les interruptions DMA son 1.

Enfin notre DMAlist contiendra uniquement des int DMA.

Ainsi, quand l'int raster sera rencontrée, notre DMAlist sera lancée depuis son début.
La DMAlist génèrera des int DMA son 1.
Chaque fois qu'une int DMA son 1 aura lieu vous aurez un raster rouge.

Vous obtiendrez à l'écran ceci:

Exemple_DMA_son_INT

Et voici le programme d'exemple:

                        ORG     #8000               ;on se met en #8000
            DMALIST     DS      100*2,0             ;on remplis 100 fois 2 octets de valeur 0
                                                    ;ceci nous sert a préparer notre DMA liste en la remplissant de 0

            ;********************************************************************************
            ;***************************** ROUTINE PRINCIPALE *******************************
            ;********************************************************************************
                        ORG     #9000               ;notre code lui sera en #9000
                        nolist                      ;le nolist est une instruction pour l'assembleur et permet de ne pas voir le source défiler à l'assemblage
                        CALL    delock              ;l'ASIC est delockée

            ;maintenant on va remplir notre DMA liste avec des int

                        LD      HL,#4010            ;#4010 correspond a l'instruction INT pour les DMAlist
                        LD      (DMALIST+60),HL     ;on place notre instruction INT en #8000+60 octets.
                        LD      (DMALIST+80),HL     ;une autre int
                        LD      (DMALIST+150),HL    ;une autre
                        LD      (DMALIST+180),HL    ;une petite dernière
                        LD      HL,#4020            ;instruction STOP    
                        LD      (DMALIST+200),HL    ;Notre DMAlist s’arrêtera ici

            ;attention c'est là que tout se passe maintenant

                        DI                          ;on coupe les interruptions car on va les modifier
                        CALL    ASICON
                        LD      A,1
                        LD      (#6800),A           ;on met une interruption raster a la ligne 1
                        CALL    ASICOFF             ;on déconnecte la page I/O ASIC pour le moment

            ;cette interruption raster va nous permettre de lancer la DMAlist...
            ;on passera en IM 2 pour que tout se gère tout seul
            ;on va donc faire une routine qui lancera la DMAlist et dans laquelle l'int raster sautera
            ;voir la sous routine INIT_DMA_LIST
            ;notre routine sera en #2000
            ;on la recopie donc là

                        LD      HL,INIT_DMA_LIST    ;notre routine est là
                        LD      DE,#2000            ;on l'enverra en #2000
                        LD      BC,100              ;elle fait 100 octets de longueur
                        LDIR                        ;on recopie

            ;notre routine pour les int raster est prête
            ;on s'occupe maintenant de celle pour les DMA son

                        LD      HL,DMA_INT          ;notre routine est la
                        LD      DE,#3000            ;on la mettra en #3000
                        LD      BC,83               ;elle fait 60 octet de long
                        LDIR                        ;on recopie

            ;maintenant que nos routines sont prêtes, on va donner l'adresse de celle-ci pour chaque DMA.

                        CALL    ASICON              ;on connecte la page I/O ASIC
                        LD      A,#10               ;le poids fort de la table des vecteurs d'interruption
                        LD      I,A                 ;on le met dans I
                        LD      A,0
                        LD      (#6805),A           ;on met 0 dans IVR. Notre table des vecteurs d'interruption sera donc en #1000
                                                    ;les acquittements seront universels car le bit 0 est a 0
                        LD      HL,#3000            ;adresse de notre routine pour le DMA son 1
                        LD      (#1002),HL          ;on met cette adresse pour le DMA son 1
                        LD      HL,#2000            ;adresse de notre routine pour le DMA raster
                        LD      (#1006),HL          ;on met cette adresse pour le DMA raster
                        CALL    ASICOFF             ;on a termine et on déconnecte la page I/O ASIC
                        IM      2                   ;on passe en IM2
                        EI                          ;on rétablis les int

            BOUCLE      JP      BOUCLE              ;boucle sans fin

            ;***********************************************************************************
            ;*************************** ROUTINE POUR L'INT DMA RASTER *************************
            ;***********************************************************************************

            INIT_DMA_LIST
                        PUSH    BC                  ;on sauvegarde BC et AF car on va s'en servir
                        PUSH    AF
                        CALL    ASICON
                        LD      HL,DMALIST          ;Adresse de notre DMA list
                        LD      (#6C04),HL          ;on donne l'adresse de la DMA list pour le DMA1
                        LD      A,%00000010         ;on va allumer le DMA1
                        LD      (#6C0F),A           ;voila qui est fait
                        CALL    ASICOFF
                        ;on en profite pour faire un raster bleu
                        LD      BC,#7F10            ;sélection du border
                        OUT     (C),C
                        LD      A,85                ;bleu vif
                        OUT     (C),A               ;on envois
                        DS      64,0                ;on patiente
                        LD      A,84                ;du noir
                        OUT     (C),A               ;on envois
                        POP     AF                  ;on récupère AF et BC
                        POP     BC
                        EI                          ;on remet les interruptions
                        RET

            ;***********************************************************************************
            ;***************************   ROUTINE POUR L'INT DMA SON   ************************
            ;***********************************************************************************

            DMA_INT
                        PUSH    BC                  ;on sauvegarde BC
                        PUSH    AF                  ;on sauvegarde AF car on va s'en servir
                        LD      BC,#7F10            ;sélection du BORDER
                        OUT     (C),C        
                        LD      A,76                ;couleur rouge
                        OUT     (C),A               ;on envois
                        DS      64,0                ;on ajoute des NOPs histoire que ce soit visible
                        LD      A,84                ;du noir
                        OUT     (C),A               ;on envois
                        POP     AF
                        POP     BC
                        EI                          ;on rétablis les interruptions
                        RET                         ;fin

            ;*****************************************************************************
            ;***************************** ROUTINES ANNEXES ******************************
            ;*****************************************************************************

            DELOCK      LD      HL,TASIC
                        LD      D,17

            DELOCKK     LD      BC,#BC00
                        LD      A,(HL)
                        OUT     (C),A
                        INC     HL
                        DEC     D
                        JP      NZ,DELOCKK
                        RET

            TASIC       DB      255,0,255,119,179,81,168,212,98,57,156,70,43,21,138,205,238

            ASICON      LD      BC,#7FB8
                        OUT     (C),C               ;on connecte la page I/O ASIC
                        RET

            ASICOFF     LD      BC,#7FA0            ;on déconnecte la page I/O ASIC
                        OUT     (C),C
                        RET

Surtout faites bien attention, la routine se lance en #9000 !!!

Bien entendu, les DMA-list n'ont pas pour fonction première de générer ce genre de chose.
Les int DMA son ont plutôt pour but de vous aider à synchroniser des effets avec la musique par exemple.
Mais c'est un cas assez pratique pour générer des effets sans avoir à s'en occuper, comme par exemple un dégradé grossier en raster ou pour déplacer automatiquement des sprites hard sans avoir recourt à la rupture à coup de CRTC.