diff --git a/CHANGES b/CHANGES index d2e2371d0..e58f45177 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,7 @@ Emulation fixes: - GB I/O: Fix STAT writing IRQ trigger conditions (fixes mgba.io/i/2501) - GBA GPIO: Fix gyro read-out start (fixes mgba.io/i/3141) - GBA I/O: Fix HALTCNT access behavior (fixes mgba.io/i/2309) + - GBA I/O: Fix audio register 8-bit write behavior (fixes mgba.io/i/3086) - GBA SIO: Fix MULTI mode SIOCNT bit 7 writes on secondary GBAs (fixes mgba.io/i/3110) Other fixes: - GB: Fix uninitialized save data when loading undersized temporary saves diff --git a/src/gba/io.c b/src/gba/io.c index 374f87208..07a5cc83c 100644 --- a/src/gba/io.c +++ b/src/gba/io.c @@ -378,17 +378,19 @@ void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { break; case REG_SOUND1CNT_HI: GBAAudioWriteSOUND1CNT_HI(&gba->audio, value); + value &= 0xFFC0; break; case REG_SOUND1CNT_X: GBAAudioWriteSOUND1CNT_X(&gba->audio, value); - value &= 0x47FF; + value &= 0x4000; break; case REG_SOUND2CNT_LO: GBAAudioWriteSOUND2CNT_LO(&gba->audio, value); + value &= 0xFFC0; break; case REG_SOUND2CNT_HI: GBAAudioWriteSOUND2CNT_HI(&gba->audio, value); - value &= 0x47FF; + value &= 0x4000; break; case REG_SOUND3CNT_LO: GBAAudioWriteSOUND3CNT_LO(&gba->audio, value); @@ -396,16 +398,15 @@ void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { break; case REG_SOUND3CNT_HI: GBAAudioWriteSOUND3CNT_HI(&gba->audio, value); - value &= 0xE03F; + value &= 0xE000; break; case REG_SOUND3CNT_X: GBAAudioWriteSOUND3CNT_X(&gba->audio, value); - // TODO: The low bits need to not be readable, but still 8-bit writable - value &= 0x47FF; + value &= 0x4000; break; case REG_SOUND4CNT_LO: GBAAudioWriteSOUND4CNT_LO(&gba->audio, value); - value &= 0xFF3F; + value &= 0xFF00; break; case REG_SOUND4CNT_HI: GBAAudioWriteSOUND4CNT_HI(&gba->audio, value); @@ -637,9 +638,96 @@ void GBAIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) { if (address > SIZE_IO) { return; } - uint16_t value16 = value << (8 * (address & 1)); - value16 |= (gba->memory.io[(address & (SIZE_IO - 1)) >> 1]) & ~(0xFF << (8 * (address & 1))); - GBAIOWrite(gba, address & 0xFFFFFFFE, value16); + uint16_t value16; + + switch (address) { + case REG_SOUND1CNT_HI: + GBAAudioSample(&gba->audio, mTimingCurrentTime(&gba->timing)); + GBAudioWriteNR11(&gba->audio.psg, value); + gba->memory.io[REG_SOUND1CNT_HI >> 1] &= 0xFF00; + gba->memory.io[REG_SOUND1CNT_HI >> 1] |= value & 0xC0; + break; + case REG_SOUND1CNT_HI + 1: + GBAAudioSample(&gba->audio, mTimingCurrentTime(&gba->timing)); + GBAudioWriteNR12(&gba->audio.psg, value); + gba->memory.io[REG_SOUND1CNT_HI >> 1] &= 0x00C0; + gba->memory.io[REG_SOUND1CNT_HI >> 1] |= value << 8; + break; + case REG_SOUND1CNT_X: + GBAAudioSample(&gba->audio, mTimingCurrentTime(&gba->timing)); + GBAudioWriteNR13(&gba->audio.psg, value); + break; + case REG_SOUND1CNT_X + 1: + GBAAudioSample(&gba->audio, mTimingCurrentTime(&gba->timing)); + GBAudioWriteNR14(&gba->audio.psg, value); + gba->memory.io[REG_SOUND1CNT_X >> 1] = (value & 0x40) << 8; + break; + case REG_SOUND2CNT_LO: + GBAAudioSample(&gba->audio, mTimingCurrentTime(&gba->timing)); + GBAudioWriteNR21(&gba->audio.psg, value); + gba->memory.io[REG_SOUND2CNT_LO >> 1] &= 0xFF00; + gba->memory.io[REG_SOUND2CNT_LO >> 1] |= value & 0xC0; + break; + case REG_SOUND2CNT_LO + 1: + GBAAudioSample(&gba->audio, mTimingCurrentTime(&gba->timing)); + GBAudioWriteNR22(&gba->audio.psg, value); + gba->memory.io[REG_SOUND2CNT_LO >> 1] &= 0x00C0; + gba->memory.io[REG_SOUND2CNT_LO >> 1] |= value << 8; + break; + case REG_SOUND2CNT_HI: + GBAAudioSample(&gba->audio, mTimingCurrentTime(&gba->timing)); + GBAudioWriteNR23(&gba->audio.psg, value); + break; + case REG_SOUND2CNT_HI + 1: + GBAAudioSample(&gba->audio, mTimingCurrentTime(&gba->timing)); + GBAudioWriteNR24(&gba->audio.psg, value); + gba->memory.io[REG_SOUND2CNT_HI >> 1] = (value & 0x40) << 8; + break; + case REG_SOUND3CNT_HI: + GBAAudioSample(&gba->audio, mTimingCurrentTime(&gba->timing)); + GBAudioWriteNR31(&gba->audio.psg, value); + break; + case REG_SOUND3CNT_HI + 1: + GBAAudioSample(&gba->audio, mTimingCurrentTime(&gba->timing)); + gba->audio.psg.ch3.volume = GBAudioRegisterBankVolumeGetVolumeGBA(value); + gba->memory.io[REG_SOUND3CNT_HI >> 1] = (value & 0xE0) << 8; + break; + case REG_SOUND3CNT_X: + GBAAudioSample(&gba->audio, mTimingCurrentTime(&gba->timing)); + GBAudioWriteNR33(&gba->audio.psg, value); + break; + case REG_SOUND3CNT_X + 1: + GBAAudioSample(&gba->audio, mTimingCurrentTime(&gba->timing)); + GBAudioWriteNR34(&gba->audio.psg, value); + gba->memory.io[REG_SOUND3CNT_X >> 1] = (value & 0x40) << 8; + break; + case REG_SOUND4CNT_LO: + GBAAudioSample(&gba->audio, mTimingCurrentTime(&gba->timing)); + GBAudioWriteNR41(&gba->audio.psg, value); + break; + case REG_SOUND4CNT_LO + 1: + GBAAudioSample(&gba->audio, mTimingCurrentTime(&gba->timing)); + GBAudioWriteNR42(&gba->audio.psg, value); + gba->memory.io[REG_SOUND4CNT_LO >> 1] = value << 8; + break; + case REG_SOUND4CNT_HI: + GBAAudioSample(&gba->audio, mTimingCurrentTime(&gba->timing)); + GBAudioWriteNR43(&gba->audio.psg, value); + gba->memory.io[REG_SOUND4CNT_HI >> 1] &= 0x4000; + gba->memory.io[REG_SOUND4CNT_HI >> 1] |= value; + break; + case REG_SOUND4CNT_HI + 1: + GBAAudioSample(&gba->audio, mTimingCurrentTime(&gba->timing)); + GBAudioWriteNR44(&gba->audio.psg, value); + gba->memory.io[REG_SOUND4CNT_HI >> 1] &= 0x00FF; + gba->memory.io[REG_SOUND4CNT_HI >> 1] |= (value & 0x40) << 8; + break; + default: + value16 = value << (8 * (address & 1)); + value16 |= (gba->memory.io[(address & (SIZE_IO - 1)) >> 1]) & ~(0xFF << (8 * (address & 1))); + GBAIOWrite(gba, address & 0xFFFFFFFE, value16); + break; + } } void GBAIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) {