Add atomic DMA fix instructions

Michael Panzlaff 2021-05-23 21:43:46 +02:00
parent 0a0d72522a
commit d3cc143cb5
1 changed files with 23 additions and 1 deletions

@ -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.