summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Panzlaff <michel@pa-bu.de>2021-05-23 21:43:46 +0200
committerMichael Panzlaff <michel@pa-bu.de>2021-05-23 21:43:46 +0200
commitd3cc143cb5722804361ba60b34b75e02d5ff3d65 (patch)
treebdce34f12d062ee093326cd6496ccd82c651d3a9
parent0a0d72522afa7549475564c4ea88911899502df2 (diff)
Add atomic DMA fix instructions
-rw-r--r--Implementing-ipatix's-High-Quality-Audio-Mixer.md24
1 files changed, 23 insertions, 1 deletions
diff --git a/Implementing-ipatix's-High-Quality-Audio-Mixer.md b/Implementing-ipatix's-High-Quality-Audio-Mixer.md
index 29e7a92..f87d6c2 100644
--- a/Implementing-ipatix's-High-Quality-Audio-Mixer.md
+++ b/Implementing-ipatix's-High-Quality-Audio-Mixer.md
@@ -95,7 +95,29 @@ Now all that we need to do is replace the definitions of the buffers. This must
1. In [constants/m4a_constants.inc](https://github.com/pret/pokeemerald/blob/master/constants/m4a_constants.inc), `PCM_DMA_BUF_SIZE` is set on line 3; change it there.
2. In [include/gba/m4a_internal.h](https://github.com/pret/pokeemerald/blob/master/include/gba/m4a_internal.h), PCM_DMA_BUF_SIZE is set on line 169; change it there.
-### Mixer Config (Optional)
+### Making DMA transfers atomic
+Because the new sound engine uses DMA3 (by default, see Mixer Config below), which the game does not expect, we have to make some adjustments to prevent game crashes. The reason we have to do this is that pokeemerald writes the DMA registers value by value which leaves a very small chance for interrupts inbetween those register writes. If we interrupt those writes before the DMA transfer is enabled (which is done by the last write) we will corrupt the register state and once the interrupt returns, a DMA transfer is initiated with the wrong values.
+
+We can fix this very easily by using the `STMIA` instruction for DMA register writes, which cannot be interrupted. If we do that we can make sure the registers are always in a well defined state. Either a transfer is initialized and comleted or it is has not begun yet. See the following patch which makes the game write to DMA by using `STMIA`:
+
+```diff
+--- pokeemerald/include/gba/macro.h
++++ pokeemerald/include/gba/macro.h
+ #define DmaSet(dmaNum, src, dest, control) \
+ { \
+ vu32 *dmaRegs = (vu32 *)REG_ADDR_DMA##dmaNum; \
+- dmaRegs[0] = (vu32)(src); \
+- dmaRegs[1] = (vu32)(dest); \
+- dmaRegs[2] = (vu32)(control); \
+- dmaRegs[2]; \
++ register uint32_t r_src asm("r0") = (uint32_t)src; \
++ register uint32_t r_dst asm("r1") = (uint32_t)dest; \
++ register uint32_t r_ctl asm("r2") = (uint32_t)control; \
++ asm volatile("stmia %0!, {%1, %2, %3}" : "+l" (dmaRegs) : "l" (r_src), "l" (r_dst), "l" (r_ctl) : "memory"); \
+ }
+```
+
+### Mixer Config
Lastly, I would like to briefly explain the two options at the top of the mixer code, namely `ENABLE_REVERB` and `ENABLE_DMA`.
`ENABLE_REVERB` does exactly what it sounds like; if set to 1, reverb will be applied as normal, sounding just like the original game. If set to 0, all reverb processing will be skipped, and the game will have no reverb. This is completely up to personal choice, but if you just want it to sound like the original game, leave it on.