LA PROGRAMMATION DU DMA (8237)   

              ***********************************************
              * ecrit par PC-CODER pour PROGRAZINE le 09/97 *
              * E-mail :  pccoder@club-internet.fr          *
              ***********************************************
               Si vous avez des informations suplementaire
               ou si vous constater une erreur ecriver moi 
               ---------------------------------------------

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'avait qu'un seul controleur DMA et permetait
de faire des transferts 8 bits.
De nos jours les PC (AT) on 2 controleurs DMA qui utilisé ensemble
permetent 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                     |
+---------+-----------+-----------------------------------+
|         | CANAL 0   | Liber (Ram-refresh pour vieux PC) |
| DMA 1   | CANAL 1   | libre   (souvent carte son)       |
| (8 bits)| CANAL 2   | lecteur de disquette              |
|         | CANAL 3   | IMPRIMANTE (Disque Dur )          |
+---------+-----------+-----------------------------------+
|         | CANAL 4(0)| Cascade DMA 1 => DMA 2            |
| DMA 2   | CANAL 5(1)| libre    (carte son-16 bits)      |
|(16 bits)| CANAL 6(2)| libre                             |
|         | CANAL 7(3)| libre                             |
+---------------------------------------------------------+

Le DMA possede 27 registres :

---------------------------------------------------------------------
| CANAL | REGISTRE              | port DMA | port DMA | RW | TAILLE |
|       |                       |  8 bits  | 16 bits  |    | en bit |
---------------------------------------------------------------------
| 0 (4) | adresse de début      |   00h    |   0C0h   |  W |   16   |
| 0 (4) | adresse en cours      |   00h    |   0C0h   | R  |   16   |
| 0 (4) | longueur transfert -1 |   01h    |   0C2h   |  W |   16   |
| 0 (4) | longueur restante -1  |   01h    |   0C2h   | R  |   16   |
---------------------------------------------------------------------
| 1 (5) | adresse de début      |   02h    |   0C4h   |  W |   16   |
| 1 (5) | adresse en cours      |   02h    |   0C4h   | R  |   16   |
| 1 (5) | longueur transfert -1 |   03h    |   0C6h   |  W |   16   |
| 1 (5) | longueur restante -1  |   03h    |   0C6h   | R  |   16   |
---------------------------------------------------------------------
| 2 (6) | adresse de début      |   04h    |   0C8h   |  W |   16   |
| 2 (6) | adresse en cours      |   04h    |   0C8h   | R  |   16   |
| 2 (6) | longueur transfert -1 |   05h    |   0CAh   |  W |   16   |
| 2 (6) | longueur restante -1  |   05h    |   0CAh   | R  |   16   |
---------------------------------------------------------------------
| 3 (7) | adresse de début      |   06h    |   0CCh   |  W |   16   |
| 3 (7) | adresse en cours      |   06h    |   0CCh   | R  |   16   |
| 3 (7) | longueur transfert -1 |   07h    |   0CEh   |  W |   16   |
| 3 (7) | longueur restante -1  |   07h    |   0CEh   | R  |   16   |
---------------------------------------------------------------------
---------------------------------------------------------------------
| 0 (4) | REGISTRE DE PAGE      |   087h   |   08Fh   | RW |    8   |
| 1 (5) | REGISTRE DE PAGE      |   083h   |   08Bh   | RW |    8   | 
| 2 (6) | REGISTRE DE PAGE      |   081h   |   089h   | RW |    8   |
| 3 (7) | REGISTRE DE PAGE      |   082h   |   08Ah   | RW |    8   |
---------------------------------------------------------------------
---------------------------------------------------------------------
        |  STATUT               |   08h    |   0D0h   | R  |    8   |
R   C   |  COMMANDE             |   08h    |   0D0h   |  W |    8   |
E D O   |  REQUETE              |   09h    |   0D2h   |  W |    8   |
G E N   |  MASQUE 1             |   0Ah    |   0D4h   |  W |    8   |
I   T   |  MODE                 |   0Bh    |   0D6h   |  W |    8   |
S   R   |  FLIPFLOP             |   0Ch    |   0D8h   |  W |    8   |
T   O   |  MEMOIRE TAMPORAIRE   |   0Dh    |   0DAh   | R  |    8   |
R   L   |  RESET                |   0Dh    |   0DAh   |  W |    8   |
E       |  RESET DE MASQUE      |   0Eh    |   0DCh   |  W |    8   |
        |  MASQUE 2             |   0Fh    |   0DEh   |  W |    8   |
---------------------------------------------------------------------
---------------------------------------------------------------------

ADRESSE DE DEBUT :

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

REGISTRE DE PAGE :

Les 8 bits (4 pour le XT) superieurs de l'adresse sont
stoké 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 à transferer .

ATTENTION : 
Le DMA ne peut pas changer de segment (c'est dû à
un défaut de conception).
Prenons un exemple pour être plus claire :
L'adresse de début du transfert est 7000:F000 et
on veut transferé 16Ko(4000H) en DMA 8bit .
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'incrementé(=08)pour continué à 8000:0000,
mais il ne le fait pas(c'est la le défaut conception),Si bien
que le transfert continue à l'adresse 7000:0000 jusque 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é la ,on doit reconfiguré 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 A 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 certain mode DMA se sont plus suporté ??
Il est utile parfois de modier la ligne de commande (pour le
DRIVER EMS) dans le FICHIER CONFIG.SYS comme suit :

DEVICE=C:\WIN95\EMM386.EXE RAM d=128

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 :
--------------------------------
                             | longueur du
CANAL |Reg de page | adresse | transfert -1 
 DMA  | = SEGMENT  | =OFFSET | = COMPTEUR
---------------------------------------------
   0  |    87H     |   00H   |    01H
   1  |    83H     |   02H   |    03H
   2  |    81H     |   04H   |    05H
   3  |    82H     |   06H   |    07H
---------------------------------------------
   4  |    8FH     |   C0H   |    C2H
   5  |    8BH     |   C4H   |    C6H
   6  |    89H     |   C8H   |    CAH
   7  |    8AH     |   CCH   |    CEH
---------------------------------------------

DESCRIPTION DES REGISTRES DE CONTROL : 

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 requete materiel (d'un peripherique)
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 Requete DMA via DREQ 0 pour le canal 0
Bit 5 = 1 Requete DMA via DREQ 1 pour le canal 1
Bit 6 = 1 Requete DMA via DREQ 2 pour le canal 2
Bit 7 = 1 Requete 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 controleur
      = 1 Désactive le controleur

Bit 3 = 0 Accés ordinaire
      = 1 Accés compresse

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 Requete DRQ si ligne high
      = 1 Requete DRQ si ligne low

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

En principe vous ne devez jamais touché à ce registre.
Valeur par defaut = 00h

REQUETE :  09h (DMA1) ou D2h (DMA2) /W

Permet de simuler une requete 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 requete via la ligne DREQx

Bit 1-0 = 00 Selectionne 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 registre de MASQUE servent à masquer un ou plusieurs
canaux pour permettre leur initialisation.(Vous devez en
utilisé qu'un seul ,ce lui 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 selectionner 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 autoinitialisation inactif
         1 autoinitialisation actif

L'autoinitialisation permet à la fin d'un transfert (quelque
soit le mode) de réintitialiser le DMA avec les valeurs
(compteur,adresse ...)déja programmer lors du transfert
précédent(on a put 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 placé l'adresse de DEBUT du transfert au DEBUT
  du bloc à transferé.
* Si vous choisissez DECREMENTATION de l'adresse , vous
  devez placé l'adresse de DEBUT du transfert à la FIN
  du bloc à transferé.

MODE :   INCREMENTATION            DECREMENTATION
          MEMOIRE                   MEMOIRE
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'a 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 accedé au BUS)
Le transfert débute par envoie d'un signal (bref)
d'un peripherique 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 materiel(ou logiciel) pour déclencher
le transfert DMA de l'octet(ou mot)suivant.
C'est ce mode de transfert qui est utilise 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 debuter le transfert complet),il faut ici que
le péripherique maintiennent ce signal sur la ligne DREQ
pendant la totalité du transfert.
Remarquer que le peripherique peut interrompre le transfert
(quand il veut) en arretant ce signal .

TRANSFERT EN CASCADE :
Le transfert en cascade permet grace à 2 DMA de réaliser
des trasferts 16 bits .(utiliser ceci pour le DMA 1 uniquement)

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 registre 16 bits .(adresse de début,longueur ...)
En effet on ne peut pas lire ou ecrire 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 poid faible (8 bits inferieurs)
dans le registre.
A ce moment le FLIPFLOP bascule automatiquement pour
permettre d'écrire le poid fort .
Et ensuite ,il faut écrire l'octet de poid fort dans
ce registre .

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

TAMPOM :  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 controlleur DMA

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

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

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

Voici les etapes à 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 POID FAIBLE DE L'ADRESSE DE DEBUT
7) ECRIRE L'OCTET DE POID FORT DE L'ADRESSE DE DEBUT
8) ECRIRE L'OCTET DE POID FAIBLE DE LA LONGUEUR -1 (COMPTEUR)
9) ECRIRE L'OCTET DE POID FORT DE LA LONGUEUR -1 (COMPTEUR)
10) LIBERER LE CANAL DMA 

--------------------------------------------------------------------
LA PROGRAMATION DU DMA 16 bit :

Pour jouer des sons 16 bits il faut obligatoirement programmer
le DMA en 16 bits :

Il faut d'abord programmer le DMA 1 en utilisant le mode de 
transfert EN CASCADE ,
puis programmer le DMA 2 avec le mode souhaiter (normalement
transfert UNIQUE .

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