Thoughts on DMA
I’ve been reading through Linkers and Loaders for the last couple months, and my brain is very full with toolchain stuff so I figured I’d think about hardware again for a little bit.
I think DMA will probably just be used for the front panel, but it’s possible it could be used for more than that. We’ll have an IDE/PATA hard disk attached, so it’s possible DMA could be used there (but I know nothing about this so far, so maybe that’s impractical for reasons I don’t yet understand). Flexible disk (if I end up implementing that) might make sense to do DMA on, but probably nothing else (serial port, RTC) does. I could expose it on the extension interface for future ideas as well, no matter what “kind” I end up implementing.
There’s three paths I can think of for how to implement DMA:
- “CPU Halt” DMA – CPU releases the address and data busses and halts when DMA_REQ is asserted, allowing whatever needs to touch memory directly to do so.
- “Semi-parallel” DMA, CPU releases the address and data busses but keeps executing instructions until it hits one that needs memory, at which point I think it would have to halt. This probably isn’t worth the extra complexity, as we have no cache so the CPU is going to be executing out of RAM 99% of the time, meaning it would just halt as soon as it finished the current instruction either way.
- “Full-parallel” DMA, CPU would release the address and data busses during certain phases at which point DMA_ACK would be asserted and the peripheral would have a guaranteed X microseconds to do DMA before the CPU might need it again.
“CPU Halt” DMA probably makes the most sense, the other kinds seem like they’d add a lot of complexity and, despite seeming “cooler”, probably aren’t worth it for this project. I may never end up using DMA for anything other than letting the front panel poke at memory, so it’s not worth over-complicating it.
This form of DMA seems pretty straightforward at least on the surface. DMA_REQ would be treated like an interrupt, so at the next instruction fetch the microcode would jump to a dedicated area that would assert DMA_ACK then go into a tight loop until DMA_REQ was de-asserted. DMA_ACK would hi-Z some buffers between the address bus/MDR and RAM, and do the opposite for buffers between the front panel switches and RAM. Then the CPU just sits in the tight microcode loop as the peripheral (front panel, etc.) pokes at RAM, and then once DMA_REQ is de-asserted it will exit the loop which will de-assert DMA_ACK and return the RAM to its normal connectivity.
I’m sure there’s some edge cases or missing knowledge here that I’ll discover once I start implementing, but I think that’s a good start at least! I haven’t touched the hardware side in a couple years, having been mostly working on toolchain for quite awhile now, so I’m excited to dive back into it and re-learn how everything fits together. At some point I need to figure out exceptions as well, but I think this will be a little more straightforward so want to tackle this first, to get my feet wet on the hardware again.