Home | Forums | What's new | Resources | |
Interrupt-Driven DMA PWM on the 32X |
Chilly Willy - Sep 26, 2012 |
Chilly Willy | Sep 26, 2012 | |||||||||||||||||||
This is how you do interrupt driven DMA PWM audio on the 32X. The first thing to ask is, why? If you wish to do more than just audio on the slave sh2, you need to make your audio code interrupt driven. That way when you do something that takes a long time, the audio will interrupt the task as needed to generate audio. Otherwise you are stuck trying to break the tasks into small enough pieces that it doesn't interfere with your polled audio. With DMA'd buffers, that is a decent amount of time, but not enough for some things. This method works on real hardware and on Fusion 3.64 (remember that 3.63 sounds like crap). If you use Gens/GS release 7 with my DMA PWM modifications, you need to make one more change to pwm.c to use int-driven dma pwm: Change this
Code:
to this
Code:
So how do we do interrupt driven dma pwm audio? First, assign the dma an exception entry in the exception table... I suggest the exception right after the autovectors since it's the first free entry not used by anything else, and easy to find. So your table looks like this at the end:
Code:
Make sure you're using the slave table, not the master. Now you need the code for that exception.
Code:
We push the registers that aren't saved by C, then call the C function, slave_dma1_handler(). Before I talk about that function, we need to see how to set up the dma in the slave code.
Code:
Notice that the VCR for DMA1 is set to 72. That's that exception vector we added to the slave table. Notice that IPRA bits 12 to 8 are set to 0xF (15). That's the exception priority. Tailor that to your needs knowing that CMD is 8, HBlank is 10, VBlank is 12, and the reset button is 14. Other than that, we do a "standard" set up of the audio. We fill the first buffer and call the handler to start off the dma. After that, the transfer-end dma interrupt will continue the process. We then fall in a loop where we look at COMM4 for a command from the Master SH2 or 68K. That's where you stick any tasks that take a long time for the slave to do. Those tasks may/will be interrupted by the dma interrupt as needed to fill buffers and start the next dma operation. So how about that exception function?
Code:
Note that read TE/clear TE set of lines - those are REQUIRED for dma interrupts to occur properly. Took a while to figure that out. Then it's merely a matter of starting the next DMA on the proper buffer, then calling fill_buffer on the other buffer. We're then done until the next interrupt. See how easy that is? Here is the full source code. There is an arc with my current linker scripts for the compiler, an arc with the xm player library and converter tool, and an arc with the 32X code: ldscripts-32X.7z... libxmp-v1.1.7z... xmplayer-v1.1... The resultant binaries: XMP-Doom-Wolf3D.zip... UP/DOWN immediately goes to the previous/next songs, LEFT/RIGHT changes the volume down/up (it starts at max volume), and START pauses/resumes. If you have any questions, be sure to ask. Note, this could TOTALLY be applied to the Saturn. I intend to make an XM player driver for the Saturn here sometime this fall. |
Chilly Willy | Sep 28, 2012 | |||
Here's an update to the library that fixes a problem with instruments with a high relative note at a high octave: libxmp-v1.2.7z... as well as binaries using various soundfonts: XMPlayer-Doom-Wolf3D-RSO.7z... |