Direct Memory Access (DMA) is the term given to a certain type of memory-to-device transfer that is used on PCs. Only certain devices, generally those with a high throughput of data (such as sound cards and disk drives), support DMA transfers. The important idea is that DMA can occur in the background, while the processor is doing other things (ie, running a program). The data is pumped through but the program itself does this at the block level, not the byte level: it is the task of the DMA controller (DMAC) to handle these "low level" parts of the transfer.
PCs (AT and later) have two DMA controller chips. Generally, there is a slave chip and master chip. Channel 0 of the second chip (logical channel 4) is used to master the first chip. The exception to this rule is that in some of IBM's PS/2 line (specifically, those that used the microchannel architecture), the DMA chips (if indeed multiple chips were used) did not require cascading. The first chip does 8 bit DMA transfers; the second does 16 bit transfers. Again, the PS/2's were an exception in that any channel could be programmed for either 8 or 16 bit operation. Generally, though, the PS/2 chip is compatible with the PC chip.
The DMAC chip type used was originally designed only for 64KB memory systems. Intel added some 'page registers' (seperate to the controller itself) which allow selecting (for the first chip) any of 256 64KB pages in memory (ie, any range of addresses in the first 16MB of memory, not spanning a 64KB boundary) or, for the second chip, any of 128 128KB pages in memory. The second chip can access larger pages because it's count and offset (address) registers give a count of words (double-bytes), rather than bytes.
Originally it seems the DMAC chips were designed to allow memory to memory transfers (ie, transfer data from one memory location to another). From all reports, this capability has *not* been implemented in PCs (probably, the DMAC is not connected to the data bus).
| logical channel number | controller chip used | address port | count port | page port
| 0 | DMAC1 | 0x00 | 0x01 | 0x87
| 1 | DMAC1 | 0x02 | 0x03 | 0x83
| 2 | DMAC1 | 0x04 | 0x05 | 0x81
| 3 | DMAC1 | 0x06 | 0x07 | 0x82
| 4 | DMAC2 | 0xC0 | 0xC1 | Normally, this channel as unusable. It acts as a cascade for DMAC1 - whenever DMAC1 asserts access to the bus, DMAC2 allows this access through logical channel 4, using the page specified for the appropriate DMAC1 channel. On PS/2 systems, the page register address is 0x8F.
| 5 | DMAC2 | 0xC2 | 0xC3 | 0x8B
| 6 | DMAC2 | 0xC4 | 0xC5 | 0x89
| 7 | DMAC2 | 0xC6 | 0xC7 | 0x8A
| |
The DMA controllers have their ports defined as such:
| Controller | Command/status register | write single mask register | write mode register | clear byte pointer flip flop | clear mask register | All mask register bits (AMRB) |
| DMAC1 | 0x08 | 0x0A | 0x0B | 0x0C | 0x0E | 0x0F |
| DMAC2 | 0xD0 | 0xD4 | 0xD6 | 0xD8 | 0xDC | 0xDE |
Note that there should be a short delay between port accesses in order to give the DMA chip 'recovery time' (at least, this is the case for the original AT computers). The exact amount of time is probably around 5 10-millionths of a second (50 microseconds).
The channels are basically independent. They can operate in any of the following modes (the mode which should be used depends on the hardware connected to the particular channel). It should be noted that the DMAC cooperates with attached devices so that no transfer is made if the device is not ready. When transfer is occurring, the address bus of the system is commandeered, so that the CPU must generally pause operation.
The channels can each be set for 'autoinitialize' operation so that the count and address values are reloaded after a complete transfer. This enables a block of memory to be transferred several times, possibly being modified 'on the fly', so that DMAC does not need to be reprogrammed. This type of setting is particularly useful for hardware such as sound cards, which continuosly read in processed data. Autoinitialization setting is ignored for cascade mode.
It is also possible to clear all mask bits (for a particular DMAC) by writing any value to the 'clear mask register' port, and to set the state of all four mask bits to specific values by writing to the AMRB port (least significant bit corresponds to physical channel number 0, 1 for set, 0 for clear).
| bits | meaning |
| 7-6 | 00b = demand mode, 01b = single mode, 10b = block mode, 11b = cascade mode |
| 5 | 0 = address is incremented after each unit of transfer, 1 = address is decremented (...) |
| 4 | 1 = auto initialization on, 0 = off |
| 3-2 | transfer type (ignored for cascade mode): 00b "Verify transfer" (unused?), 01b "Write" (to device, from memory), 10b "Read" (from device), 11b illegal |
| 1-0 | Gives channel number for which mode is being set |
***It is possible to read one or both of the count and address
At the same port address the 'command register' can be accessed. Sources advise that this should not be changed by the programmer, however the BIOS writes a value of 4 to disable all DMA and 0 to enable DMA.
The Microchannel PS/2 systems support additional features to the standard PC DMA chips. The function register (port 0x18) is used to execute commands on any of the 8 DMA channels,as the following tables show. Any data to the commands was input to or output from port 0x1A (all registers are readable and writeable, though some appear to have seperate commands for either operation), least significant byte first. The details I have on these commands are sketchy, I have done my best to interpret their meaning.
| bits | meaning |
| 7-4 | Command. 0x00 = I/O address register, uses one data byte with lower 5 bits meaningful, use unknown to me. 0x01 = reserved, 0x02 = Write memory address register (3 bytes follow, presumably this command also sets the page register), 0x03 = read memory address register (see 0x02). 0x04 = transfer count register write, 2 bytes of data. 0x05 = transfer count register read, 2 data bytes. 0x06 = status register, presumably the same as already documented, 1 data byte. 0x07 = mode register, this is the extended mode register of the PS/2 DMAC: see table below, 1 data byte. 0x08 = arbitration bus register, 1 data byte, use unknown to me. 0x09 sets mask bit for selected channel, no data. 0x0A resets mask bit for selected channel, no data. 0x0B & 0x0C reserved, 0x0D clears all mask bits, no data. 0xE & 0xF reserved. |
| 3 | reserved, must be 0. |
| 2-0 | channel number select (0-7). |
PS/2 DMAC extended mode register:
| bits | meaning |
| 7 | must be 0 |
| 6 | select transfer data width, 0=8 bit, 1=16 bit. |
| 5-4 | must be 0 |
| 3 | Read/write select, 0='read memory transfer' (read from memory?), 1=write memory transfer |
| 2 | 0 = verify, 1 = transfer |
| 1 | must be 0 |
| 0 | I/O to address 0x0000, 1=I/O to programmed address |