GBA Audio: Fix reads from CH3 Wave RAM The previous code always read the state of bank 0. The correct behaviour is to read from the bank that isn't selected. Most likely, no game has ever tried to read from this RAM and verify the values because the values are destroyed as soon as the channel starts to play the desired sound. Writes were done correctly: The values are saved to the bank that isn't selected. Also, when the sound hardware is off, it acts like bank 0 has been selected in register SOUND3CNT_L.
Antonio Niño Díaz antonio_nd@outlook.com
Sun, 21 Mar 2021 18:30:58 +0000
3 files changed,
46 insertions(+),
9 deletions(-)
M
include/mgba/internal/gba/audio.h
→
include/mgba/internal/gba/audio.h
@@ -304,6 +304,7 @@ void GBAAudioWriteSOUNDCNT_X(struct GBAAudio* audio, uint16_t value);
void GBAAudioWriteSOUNDBIAS(struct GBAAudio* audio, uint16_t value); void GBAAudioWriteWaveRAM(struct GBAAudio* audio, int address, uint32_t value); +uint32_t GBAAudioReadWaveRAM(struct GBAAudio* audio, int address); uint32_t GBAAudioWriteFIFO(struct GBAAudio* audio, int address, uint32_t value); void GBAAudioSampleFIFO(struct GBAAudio* audio, int fifoId, int32_t cycles);
M
src/gba/audio.c
→
src/gba/audio.c
@@ -221,7 +221,27 @@ audio->soundbias = value;
} void GBAAudioWriteWaveRAM(struct GBAAudio* audio, int address, uint32_t value) { - audio->psg.ch3.wavedata32[address | (!audio->psg.ch3.bank * 4)] = value; + int bank = !audio->psg.ch3.bank; + + // When the audio hardware is turned off, it acts like bank 0 has been + // selected in SOUND3CNT_L, so any read comes from bank 1. + if (!audio->enable) { + bank = 1; + } + + audio->psg.ch3.wavedata32[address | (bank * 4)] = value; +} + +uint32_t GBAAudioReadWaveRAM(struct GBAAudio* audio, int address) { + int bank = !audio->psg.ch3.bank; + + // When the audio hardware is turned off, it acts like bank 0 has been + // selected in SOUND3CNT_L, so any read comes from bank 1. + if (!audio->enable) { + bank = 1; + } + + return audio->psg.ch3.wavedata32[address | (bank * 4)]; } uint32_t GBAAudioWriteFIFO(struct GBAAudio* audio, int address, uint32_t value) {
M
src/gba/io.c
→
src/gba/io.c
@@ -616,6 +616,9 @@ }
void GBAIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) { switch (address) { + // Wave RAM can be written and read even if the audio hardware is disabled. + // However, it is not possible to switch between the two banks because it + // isn't possible to write to register SOUND3CNT_LO. case REG_WAVE_RAM0_LO: GBAAudioWriteWaveRAM(&gba->audio, 0, value); break;@@ -833,6 +836,27 @@ case REG_SOUNDBIAS:
case REG_POSTFLG: mLOG(GBA_IO, STUB, "Stub I/O register read: %03x", address); break; + + // Wave RAM can be written and read even if the audio hardware is disabled. + // However, it is not possible to switch between the two banks because it + // isn't possible to write to register SOUND3CNT_LO. + case REG_WAVE_RAM0_LO: + return GBAAudioReadWaveRAM(&gba->audio, 0) & 0xFFFF; + case REG_WAVE_RAM0_HI: + return GBAAudioReadWaveRAM(&gba->audio, 0) >> 16; + case REG_WAVE_RAM1_LO: + return GBAAudioReadWaveRAM(&gba->audio, 1) & 0xFFFF; + case REG_WAVE_RAM1_HI: + return GBAAudioReadWaveRAM(&gba->audio, 1) >> 16; + case REG_WAVE_RAM2_LO: + return GBAAudioReadWaveRAM(&gba->audio, 2) & 0xFFFF; + case REG_WAVE_RAM2_HI: + return GBAAudioReadWaveRAM(&gba->audio, 2) >> 16; + case REG_WAVE_RAM3_LO: + return GBAAudioReadWaveRAM(&gba->audio, 3) & 0xFFFF; + case REG_WAVE_RAM3_HI: + return GBAAudioReadWaveRAM(&gba->audio, 3) >> 16; + case REG_SOUND1CNT_LO: case REG_SOUND1CNT_HI: case REG_SOUND1CNT_X:@@ -863,14 +887,6 @@ case REG_BLDCNT:
case REG_BLDALPHA: case REG_SOUNDCNT_HI: case REG_SOUNDCNT_X: - case REG_WAVE_RAM0_LO: - case REG_WAVE_RAM0_HI: - case REG_WAVE_RAM1_LO: - case REG_WAVE_RAM1_HI: - case REG_WAVE_RAM2_LO: - case REG_WAVE_RAM2_HI: - case REG_WAVE_RAM3_LO: - case REG_WAVE_RAM3_HI: case REG_DMA0CNT_HI: case REG_DMA1CNT_HI: case REG_DMA2CNT_HI: