La programmation du DMA (8237)

Le DMA (Direct Memory Access) permet de transférer des données de la mémoire vers un périphérique ou d'un périphérique vers la mémoire sans passer par le CPU (sauf pour sa programation).

Au début les PC (XT) n'avaient qu'un seul contrôleur DMA et permettaient de faire des transferts 8 bits.
De nos jours les PC (AT) ont 2 contrôleurs DMA qui, utilisés ensemble, permettent de faire des transferts 16 bits.
La taille du transfert maximum (en 1 seul fois) est de 64 KO (65536 octet) pour les transfert 8 bits et 128 KO pour les transferts 16 bits.
Remarque : il est impossible d'utiliser le DMA 2 pour faire des transfert 8 bits.

    Chaque DMA possede 4 caneaux :

DMA

CANEAUX

DESCRIPTION

DMA 1
(8 bits)

CANAL 0
CANAL 1
CANAL 2
CANAL 3

          Liber (Ram-refresh pour vieux PC)
          libre (souvent carte son)
          lecteur de disquette
          IMPRIMANTE (Disque Dur )

DMA 2
16 bits)

CANAL 4(0)
CANAL 5(1)
CANAL 6(2)
CANAL 7(3)

          Cascade DMA 1 => DMA 2
          libre (carte son-16 bits)
          libre
          libre

    Le DMA possède 27 registres :

CANAL

REGISTRE

port DMA
8 bits

port DMA
16 bits

RW

TAILLE
en bit

0 (4)0 (4)0 (4)0 (4)

        adresse de début
        adresse en cours
        longueur transfert -1
        longueur restante -1

00h00h01h01h

0C0h0C0h0C2h0C2h

WRWR

16161616

1 (5)1 (5)1 (5)1 (5)

        adresse de début
        adresse en cours
        longueur transfert -1
        longueur restante -1

02h02h03h03h

0C4h0C4h0C6h0C6h

WRWR

16161616

2 (6)2 (6)2 (6)2 (6)

        adresse de début
        adresse en cours
        longueur transfert -1
        longueur restante -1

04h04h05h05h

0C8h0C8h0CAh0CAh

WRWR

16161616

3 (7)3 (7)3 (7)3 (7)

        adresse de début
        adresse en cours
        longueur transfert -1
        longueur restante -1

06h06h07h07h

0CCh0CCh0CEh0CEh

WRWR

16161616

0 (4)1 (5)2 (6)3 (7)

        REGISTRE DE PAGE
        REGISTRE DE PAGE
        lREGISTRE DE PAGE
        REGISTRE DE PAGE

087083081082

08Fh08Bh089h08Ah

RWRWRWRW

8888

R C
E D O
G E N
I T
S R
T Ô
R L
E E

        STATUT
        COMMANDE
        REQUÊTE
        MASQUE 1
        MODE
        FLIPFLOP
        MÉMOIRE TEMPORAIRE
        RESET
        RESET DE MASQUE
        MASQUE 2

08h08h09h0Ah0Bh0Ch0Dh0Dh0Eh0Fh

0D0h0D0h0D2h0D4h0D6h0D8h0DAh0DAh0DCh0DEh

RWWWWWRWWW

8888888888

 
ADRESSE DE DEBUT :

C'est l'adresse à partir de laquelle le transfert débute .
Cette adresse est codée sur 24 bits (20 pour le XT), ici il
n'y a que les 16 bits inférieurs de l'adresse.

REGISTRE DE PAGE :

Les 8 bits (4 pour le XT) supérieurs de l'adresse sont
"stockés" dans le registre de PAGE .

ADRESSE EN COURS :

Quand on lit ce registre on obtient l'adresse ou le transfert
est arrivé au moment de la lecture du registre.

LONGUEUR DU TRANFERT -1: (=compteur)

C'est ici qu'on indique la taille du transfert -1 .

LONGUEUR RESTANTE -1: (=compteur)

Quand on lit ce registre (pendant le transfert) on obtient le
nombre d'octet -1 qu'il reste à transférer .

ATTENTION :
Le DMA ne peut pas changer de segment (c'est dû à
un défaut de conception).
Prenons un exemple pour être plus clair :
L'adresse de début du transfert est 7000:F000 et
on veut transfÉrer 16Ko (4000H) en DMA 8 bits .
Le registre de PAGE aura pour valeur 07h, le registre
d'adresse de début aura pour valeur 0F000h et le compteur
(longueur) aura pour valeur 3FFFh.
Quand le transfert sera arrivé à 7000:ffff, normalement le
registre de page doit s'incrementer (= 08) pour continuer à 8000:0000,
mais il ne le fait pas (c'est la le défaut conception), si bien
que le transfert continu à l'adresse 7000:0000 jusqu'à 7000:3000.
Pour faire ce transfert correctement , il faut s'y prendre à 2 fois :
Le registre de PAGE aura pour valeur 07h, le registre
d'adresse aura pour valeur 0F000h et le compteur (longueur)
aura pour valeur 0FFFh.
Arrivé là, on doit reconfigurer le DMA :
Le registre de PAGE aura pour valeur 08h, le registre
d'adresse aura pour valeur 0000h et le compteur (longueur)
aura pour valeur 2FFFh.
Et voila, le transfert est correctement éffectué :
de 7000:F000 à 8000:3000
Remarque : Si vous avez un driver EMS (EMM386.exe ou autre)
installé, vous n'avez pas besoin de faire ce transfert en 2
fois et certains modes DMA se sont plus suportés .
Pour faire des transferts 16 bits, il faut mettre dans le
registre d'adresse, une adresse PAIRE.
En 16 bits la longueur ne correspond plus à des octets, mais
à des mots.

----------------------------------------------------
VOICI UN TABLEAU RECAPITULATIF :
-----------------------------------------------------

 
CANAL
DMA

 
Reg de page
= SEGMENT

 
Adresse
= OFFSET

Longueur du
transfert -1
= COMPTEUR

0123

87H83H81H82H

00H02H04H06H

01H03H05H07H

4567

8FH8BH89H8AH

C0HC4HC8HCCH

C2HC6HCAHCEH

 
DESCRIPTION DES REGISTRES DE CONTRÔLE :

STATUT (SR) : 08h (DMA1) ou D0h (DMA2) /R

Ce registre indique qu'un transfert est finit.
Lorsque le compteur passe de 0000 à FFFF, le flag
TC (Terminal Count) est mis à 1.
DREQ indique une requête matériel (d'un périphérique).
SR est remis à 0 à sa lecture .

b7

b6

b5

b4

b3

b2

b1

b0

R-

|D3|

|D2|

|D1|

|D0|

|TC3|

|TC2|

|TC1|

|TC0|

08H

(D0H)

Bit 0 = 1 TC atteint pour le canal 0(transfert finit)
Bit 1 = 1 TC atteint pour le canal 1
Bit 2 = 1 TC atteint pour le canal 2
Bit 3 = 1 TC atteint pour le canal 3
Bit 4 = 1 Requête DMA via DREQ 0 pour le canal 0
Bit 5 = 1 Requête DMA via DREQ 1 pour le canal 1
Bit 6 = 1 Requête DMA via DREQ 2 pour le canal 2
Bit 7 = 1 Requête DMA via DREQ 3 pour le canal 3

 
COMMANDE : 08h (DMA1) ou D0h (DMA2) /W

b7

b6

b5

b4

b3

b2

b1

b0

-W

| 0 |

| 0 |

| 0 |

| 0 |

| 0 |

| 0 |

| 0 |

| 0 |

08H

(D0H)

 
Bit 0 = 0 Transfert entre Mémoire et Périphérique
= 1 Transfert entre Mémoire et Mémoire (impossible?)

Bit 1 = 0 le canal déborde de la mémoire
= 1 le canal reste figé à l'adresse de début

Bit 2 = 0 Active le contrôleur
= 1 Désactive le contrôleur

Bit 3 = 0 Accès ordinaire
= 1 Accès compressé

Bit 4 = 0 Priorité static (priorité max => canal 0 et
priorité min => canal 3 )
= 1 Priorité rotative

Bit 5 = 0 Signal write retardé (si b3=1)
= 1 Signal write rallongé (si b3=1)

Bit 6 = 0 Requête DRQ si ligne high
= 1 Requête DRQ si ligne low

Bit 7 = 0 Confirmation DACK via ligne low
= 1 Confirmation DACK via ligne high

En principe vous ne devez jamais toucher à ce registre.
Valeur par défaut = 00h

REQUÊTE : 09h (DMA1) ou D2h (DMA2) /W

Permet de simuler une requête DMA par logiciel .

b7

b6

b5

b4

b3

b2

b1

b0

-W

| 0 |

| 0 |

| 0 |

| 0 |

| 0 |

| M |

| C |

| C |

09H

(D2H)

 
Bit 7-3 = 0 Reservé

Bit 2 = 0 Pas de requete
1 Simulation de requÊte via la ligne DREQx

Bit 1-0 = 00 Sélectionne le canal 0
01 Sélectionne le canal 1
10 Sélectionne le canal 2
11 Sélectionne le canal 3

MASQUE1 : 0Ah (DMA1) ou D4h (DMA2) /W

Les 2 registres de MASQUE servent à masquer un ou plusieurs
canaux pour permettre leur initialisation. (Vous devez en
utiliser qu'un seul, celui que vous voulez)

b7

b6

b5

b4

b3

b2

b1

b0

-W

| 0 |

| 0 |

| 0 |

| 0 |

| 0 |

| M |

| C |

| C |

0AH

(D4H)

 
Bit 7-3 = 0 Réservé

Bit 2 = 0 Pas de masque sur le canal sélectionner
1 Masque le canal sélectionner

Bit 1-0 = 00 Sélectionne le canal 0
01 Sélectionne le canal 1
10 Sélectionne le canal 2
11 Sélectionne le canal 3

MASQUE2 : 0Fh (DMA1) ou DEh (DMA2) /W

Le registre de MASQUE2 sert exactement à la même chose
mais il fonctionne différement .

b7

b6

b5

b4

b3

b2

b1

b0

-W

| 0 |

| 0 |

| 0 |

| 0 |

| C3 |

| C2|

| C1 |

| C0 |

0FH

(DEH)

 
Bit 7-4 = 0 réservé

Bit 3 = 0 Pas de masque sur le canal 3
1 Masque le canal 3

Bit 2 = 0 Pas de masque sur le canal 2
1 Masque le canal 2

Bit 1 = 0 Pas de masque sur le canal 1
1 Masque le canal 1

Bit 0 = 0 Pas de masque sur le canal 0
1 Masque le canal 0

MODE : 0Bh (DMA1) ou D6h (DMA2) /W

Permet de sélectionner le fonctionnement du transfert.

b7

b6

b5

b4

b3

b2

b1

b0

-W

| MT |

| MT |

| ID |

| TC |

| TT |

|TT|

| C |

| C |

0BH

(D6H)

 
Bit 1-0 = 00 sélectionne le canal 0
01 sélectionne le canal 1
10 sélectionne le canal 2
11 sélectionne le canal 3

Bit 3-2 = 00 Vérifie (utilisé pour RAM REFRESH )
01 Ecriture (du périphérique vers la mémoire)
10 Lecture (de la mémoire vers le périphérique)
11 Réservé

Bit 4 = 0 auto initialisation inactif
1 auto initialisation actif

L'auto initialisation permet à la fin d'un transfert (quelque
soit le mode) de réinitialiser le DMA avec les valeurs
(compteur,adresse ...) déja programmées lors du transfert
précédent (on a plus besoin de reprogrammer le DMA ).

Bit 5 = 0 Incrémentation de l'adresse (de transfert)
1 Décrémentation de l'adresse

ATTENTION :
* Si vous choisissez INCREMENTATION de l'adresse , vous
devez placer l'adresse de DÉBUT du transfert au DÉBUT
du bloc à transferer.
* Si vous choisissez DÉCRÉMENTATION de l'adresse , vous
devez placer l'adresse de DÉBUT du transfert à la FIN
du bloc à transferer.

MODE :   INCRÉMENTATION            DÉCRÉMENTATION
          MÉMOIRE                   MÉMOIRE
0000:0000+--------+ 0000:0000+-------+
| | | |
| | | |
adr de ->+--------+ +-------+
début de | |<-- Bloc à --> | |
Transfert+--------+ transferé +-------+<-- Adresse de
| | | | début de
| | | | transfert
| | | |
FFFF:FFFF+--------+ FFFF:FFFF+-------+

Bit 7-6 = 00 Mode transfert à la demande
01 Mode transfert unique
10 Mode transfert en bloc
11 Mode CASCADE

TRANSFERT EN BLOC :
Le transfert en bloc correspond au transfert complet des
données sans interruption jusqu'à ce que le compteur passe
de 0000 à FFFF ( = TC ) ou que le péripherique interrompt le
transfert(/EOP). (Pendant ce temps le CPU ne peut acceder au BUS)
Le transfert débute par envoie d'un signal (bref)
d'un péripherique sur la ligne DREQ .

TRANSFERT UNIQUE :
Avec le transfert unique, le DMA ne transfert qu'un seul octet
(ou mot si cascade) à la fois et nécessite une nouvelle
commande venant du matériel (ou logiciel) pour déclencher
le transfert DMA de l'octet (ou mot) suivant.
C'est ce mode de transfert qui est utilisé pour jouer de la ZIK .

TRANSFERT A LA DEMANDE :
Le transfert à la demande est identique au transfert en bloc,
mais contrairement à ce dernier (qui necessite un bref signal
sur DREQ pour débuter le transfert complet),il faut ici que
le péripherique maintienne ce signal sur la ligne DREQ
pendant la totalité du transfert.
Remarquez que le péripherique peut interrompre le transfert
(quand il veut) en arrêtant ce signal .

TRANSFERT EN CASCADE :
Le transfert en cascade permet grâce à 2 DMA de réaliser
des transferts 16 bits .

FLIPFLOP : 0Ch (DMA1) ou D8h (DMA2) /W

Ce registre sert à initialiser une bascule interne pour
selectionner l'octet de poid faible / octet de poid fort
des registres 16 bits (adresse de début,longueur ...).
En effet on ne peut pas lire ou écrire directement des
valeurs de 16 bits dans ces registres.Il faut écrire
d'abord 0 dans le registre FLIPFLOP pour indiquer
qu'on va écrire le poid faible du MOT (16 bits):
Il faut écrire l'octet de poids faible (8 bits inférieurs)
dans le registre.
A ce moment le FLIPFLOP bascule automatiquement pour
permettre d'écrire le poid fort .
Ensuite, il faut écrire l'octet de poids fort dans
ce registre .

Remarque : le FLIPFLOP bascule sur le poids faible à nouveau .

TAMPON : 0Ch (DMA1) ou D8h (DMA2) R/

C'est l'octet qui en cours de transfert ??
dans le mode memory to memory, je crois.

RESET : 0Dh (DMA1) ou DAh (DMA2) /W

Reset du contrôleur DMA

RESET de masque : 0Eh (DMA1) ou DCh (DMA2) /W

Reset des masque : tous les masque sont enlevés.

 
-------------------------------------------------------------------

Voiçi les étapes à respecter pour programmer le DMA:

1) MASQUER LE CANAL DMA (à programmer)
2) ECRIRE DANS LE REGISTRE DE COMMANDE (FACULTATIF)
3) INDIQUER LE MODE DE TRANSFERT
4) ECRIRE LA PAGE (SEGMENT)
5) 0 => FLIPFLOP
6) ECRIRE L'OCTET DE POIDS FAIBLE DE L'ADRESSE DE DEBUT
7) ECRIRE L'OCTET DE POIDS FORT DE L'ADRESSE DE DEBUT
8) ECRIRE L'OCTET DE POIDS FAIBLE DE LA LONGUEUR -1 (COMPTEUR)
9) ECRIRE L'OCTET DE POIDS FORT DE LA LONGUEUR -1 (COMPTEUR)
10) LIBERER LE CANAL DMA

--------------------------------------------------------------------