From c0cfa602af7249179d66d12c24cb624f4cb90738 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Ni=C3=B1o=20D=C3=ADaz?= Date: Sun, 21 Mar 2021 18:30:58 +0000 Subject: [PATCH] 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. --- include/mgba/internal/gba/audio.h | 1 + src/gba/audio.c | 22 ++++++++++++++++++++- src/gba/io.c | 32 +++++++++++++++++++++++-------- 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/include/mgba/internal/gba/audio.h b/include/mgba/internal/gba/audio.h index 212e1b860..c9fab3ae1 100644 --- a/include/mgba/internal/gba/audio.h +++ b/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); diff --git a/src/gba/audio.c b/src/gba/audio.c index b936edd1d..a8e2324b9 100644 --- a/src/gba/audio.c +++ b/src/gba/audio.c @@ -221,7 +221,27 @@ void GBAAudioWriteSOUNDBIAS(struct GBAAudio* audio, uint16_t 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) { diff --git a/src/gba/io.c b/src/gba/io.c index b544db166..b70411094 100644 --- a/src/gba/io.c +++ b/src/gba/io.c @@ -616,6 +616,9 @@ void GBAIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) { 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 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) { 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 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) { 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: