Direct Memory Access (DMA)

If we have a large amount of data to transfer in a stereotyped way, it makes sense to let the device itself take care of it. A perfect example of a device that's appropriate for DMA is a disk drive: data is on the device in nice regular-sized chunks (called sectors), and you always transfer a whole sector at a time between the device and memory. So it makes really good sense to add some more registers to the device: a pointer to the current location in memory it's writing to, and a counter saying how much data is to be sent.

Basics

The basic idea is that the device has two extra control/status registers: a pointer register, and a count register. The pointer register contains the address we're going to write to/read from next, and the count register says how much more data we have to transfer.

So, suppose a device is doing a DMA transfer to memory. We start by loading up the pointer register with the location in memory we want to transfer to. Then, we load up the count register with the amount of data we want to transfer. The ``start'' part of the device driver is done now, and we go back to running our program.

Now, as each byte of data becomes available, the device asserts a control line on the bus to request permission to do a transfer. The CPU responds by asserting a control line that grants permission (this is done completely by the hardware - there is no software intervention). The device writes the byte of data to the memory, adds one to the pointer, and subtracts one from the counter. This continues until the transfer is complete.

When the transfer has completed, the device requests an interrupt to let the CPU know it's all done.

Variations

There are a lot of variations on all of this. Here are a few of them:
  1. GO bit. I described the transfer as starting as soon as you load a non-zero value into the COUNT register. Many devices have a GO bit in one of their control registers; once you've set everything up, you have to set this bit to 1 before anything actually happens.
  2. Transfer size. What I described (one byte at a time) is what you'd do if you had a one-byte wide bus. If you've got a word-size bus, or a wider bus (current PCI busses are 64 bits wide), that's how much you'd transfer at a time. Frequently (but not always), the Count register is in units of ``transfer size'' rather than bytes, as well (so if it were a word-size transfer, you'd specify how many words to transfer instead of how many bytes).
  3. Burst mode. Some DMA devices support a ``burst mode.'' If it transfers in burst mode, it grabs the bus and then does a bunch of transfers (maybe even the whole requested buffer) before giving the bus back. This is appropriate for a device that can either generate or receive data very quickly, but can have a really nasty effect on overall system performance.
  4. First and Third Party DMA. What I've described so far is ``first party DMA,'' which is how most systems other than PCs do it, and how most texts describe it.

    PCs use a slightly different technique called ``third party DMA.'' The idea here is that there is actually a separate controller to do DMA, which maintains the pointer and count registers. When a device is ready to transfer a byte, it asks the DMA controller to do it for it; the DMA controller handles the bus handshaking and keeping track of the address to which the transfer should be made, while the device just reads or writes the bus's data lines. The original PC had a DMA controller that would support four DMA channels (of which users were able to make use of three; channel 0 was dedicated to refreshing dynamic RAM); there are now two DMA controllers which can handle eight channels (though 0 and 3 are not usable by other devices).

    Just to make things more confusing, this is too slow to support high-performance disks and the like, so these devices use first-party DMA.


Last modified: Wed Nov 13 08:52:48 MST 2002