Basic dma in MSX (1)

Basic dma in MSX (1)

If you can access the cpu bus in an msx computer and can use the Z-80 signals to stop the cpu, you can use dma to feed a special data consumer hardware. That mechanism is often used for move data for storage or, in example, play pcm audio in other computers, but not in the msx. That way the cpu can work independently while the data access for the dma-enabled devices happens when required.

The msx lacks the required z-80 signals (/busreq and /busack) in the physical slot and often the bus signals that reach the slot are buffered in "one-way" only so the required bus turn-around can't happen, even if you manage to connect the bus request signals to the z-80. Solving that was one of the innovations in the Tides Rider board but, for the description of the theory of operation, we are going to talk about "any msx" as if you had connected our "dma master" directly under the Z-80 cpu.

Every dma mechanism involves a device which has a role as producer or consumer of data, which also "knows" when the data transaction are needed. Each of the dma-enabled devices uses a "dma channel" which is programmed before the device is enabled. If the device can produce data, it will write to memory when needed. If it only consumes data, it will read from memory instead. Usually the device doesn't provide the memory address for the data so it has to be programmed (in a register of the dma master) before the dma can proceed.

The basic Z-80 mechanism for dma

The Z-80 provides two signals for dma, /busreq and /busack

/Busreq is an input to the CPU, and is asserted by the dma-device or related hardware when the dma-device requires access to the bus. When the Z-80 detects the /busreq asserted, it ends the current cpu instruction, releases the bus signals and then asserts /busack in response. This cpu-output enables de dma hardware to go on and perform the access to memory employing the same bus signals that the Z-80 uses to do so in normal operation.

The MSX special requirements for addressing

The msx uses several custom mechanisms to expand the addressing capability and allow a large amount of memory to be used by software.

  • The slots system, which splits the 64KB address map in 4 pages, allowing each of the pages to be mapped to a different logical slot (or sub-slot), providing diferent locations for memory
  • The memory mapper, which allows a larger than 64KB memory size to appear in a given slot, and any 16-KB section of that memory to appear on any of the 4 pages of the slot 

The hardware mechanism which implements both systems is "static". I.e. the system has a "state" or context which has to be set and remains while it provides the expanded addressing to the "normal" addressing present in the bus. The lower 14 bits of the Z-80 address bus "pass through" but the higher two (A14-A15) provide the page number for the slot selection. If the target slot is populated with a memory mapper, the page number also goes into the mapper table, which provides the higher address bits up to what's needed for the amount of ram managed by the mapper.

The minimal dma manager

The minimal dma manager is a simple hardware which provides both a "cpu cycle machine" for a generic dma-enabled device and a cpu-accesible set of registers to allow software to use that machine (setting pointer, etc).

In the simplest form, the dma manager stops the cpu when a single dma-enabled device requests data, provides a single dma pointer ("single channel"), and a minimal set of registers to set the pointer to the desired memory location before the dma begins.

Other optional features usually present are: 

  • A length/counter register to control the progress of the dma transfer, and, when it reaches zero/completion,
  • An interrupt generation for the the software to go on after the block has been transferred. Possibly with an interrupt vector (if vectored ints are to be used - aka im2 - rare in msx) and a bit in some register to mask the interrupt flag.

(program flow for doing a dma transfer)

  • Set the dma pointer in the dma manager
  • Enable the dma-device
  • Enable the interrupt generation, if desired either in the dma-device (if the peripheral has the hability to track the completion) or the dma-manager (if it includes the option), or (preferibly after interrupt),
  • Poll the device to check that the entire dma block has been transferred. A new transfer may be started now

Note that the dma-enabled device may request for multiple "single-access" transfers, or several "multi-access" where several bytes are done each cpu-stop, until the full block of data is completed.  Or maybe a single transfer for all the data block, depending of the timing requirements for the data.

A pcm player may request only one or two bytes to fill its buffer each of the "cpu stops" and continue every now and then until the pcm data has been played in real-time, while a storage device will probably read a block of data in a single "cpu stop" to complete as-fast-as-possible.

Enhancing the dma controller for the msx

When large blocks of memory are to be transferred, it is highly desirable to be able to perform the dma transfer in (from/to) memory segments without keeping them visible in the pages selected for the cpu in the memory mapper. I.e. specifying large addresses as if all memory was directly accesible for dma.

As the slots and mapper are systems that work beyond the cpu bus, and the the actual dma transfers (cpu stops) occur decoupled of program execution, it would be very difficult to keep the slot and memory mapper ready to be accessed anytime. Thus, in msx, it's very recommendable that the dma manager is made capable of providing its own "expansion context" for dma access, "saving" the context, then restoring the context for the cpu to continue after the transfer.

A dma-manager can keep track of the actual context anytime by "snooping" the cpu activity, both the slot registers of the ppi and the mapper registers int the ram expansion. It can also provide its own context by setting that same registers when it has gained access as if the cpu did it, using a "larger" pointer provided in the dma registers.

Before restarting the cpu the previous context can be restored, setting again the saved (tracked) values for modified registers.

Hope that you find this view interesting. IMHO it was never done in the msx (even if it would have been great for later msx models) because of the msx special requirements. Those special requirements are not that complex to implement, but preclude the usage of "off the shelf" dma managers for the Z-80.

We'll see that in part 2: Minimalistic DMA manager for MSX

Back to blog