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: