diff --git a/src/gba/io.c b/src/gba/io.c index 74a7e5610..ebce0249c 100644 --- a/src/gba/io.c +++ b/src/gba/io.c @@ -254,9 +254,9 @@ static const int _isRSpecialRegister[REG_MAX >> 1] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // DMA - 0, 0, 0, 0, 0, 1, 0, 0, - 0, 0, 0, 1, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Timers @@ -389,10 +389,11 @@ void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { break; case REG_SOUNDCNT_HI: GBAAudioWriteSOUNDCNT_HI(&gba->audio, value); + value &= 0x770F; break; case REG_SOUNDCNT_X: GBAAudioWriteSOUNDCNT_X(&gba->audio, value); - value &= 0xFFFF; + value &= 0x00F0; value |= gba->memory.io[REG_SOUNDCNT_X >> 1] & 0xF; break; case REG_SOUNDBIAS: @@ -531,7 +532,7 @@ void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { // Some bad interrupt libraries will write to this break; default: - GBALog(gba, GBA_LOG_STUB, "Stub I/O register write: %03x", address); + GBALog(gba, GBA_LOG_STUB, "Stub I/O register write: %03X", address); if (address >= REG_MAX) { GBALog(gba, GBA_LOG_GAME_ERROR, "Write to unused I/O register: %03X", address); return; @@ -620,10 +621,22 @@ bool GBAIOIsReadConstant(uint32_t address) { case REG_WINOUT: case REG_BLDCNT: case REG_BLDALPHA: - case REG_DMA0CNT_LO: - case REG_DMA1CNT_LO: - case REG_DMA2CNT_LO: - case REG_DMA3CNT_LO: + case REG_SOUND1CNT_LO: + case REG_SOUND1CNT_HI: + case REG_SOUND1CNT_X: + case REG_SOUND2CNT_LO: + case REG_SOUND2CNT_HI: + case REG_SOUND3CNT_LO: + case REG_SOUND3CNT_HI: + case REG_SOUND3CNT_X: + case REG_SOUND4CNT_LO: + case REG_SOUND4CNT_HI: + case REG_SOUNDCNT_LO: + case REG_SOUNDCNT_HI: + case REG_TM0CNT_HI: + case REG_TM1CNT_HI: + case REG_TM2CNT_HI: + case REG_TM3CNT_HI: case REG_KEYINPUT: case REG_IE: return true; @@ -671,12 +684,6 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) { case REG_RCNT: return gba->sio.rcnt; - case REG_DMA0CNT_LO: - case REG_DMA1CNT_LO: - case REG_DMA2CNT_LO: - case REG_DMA3CNT_LO: - // Write-only register - return 0; case REG_BG0HOFS: case REG_BG0VOFS: case REG_BG1HOFS: @@ -707,9 +714,42 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) { case REG_WIN1V: case REG_MOSAIC: case REG_BLDY: + case REG_FIFO_A_LO: + case REG_FIFO_A_HI: + case REG_FIFO_B_LO: + case REG_FIFO_B_HI: + case REG_DMA0SAD_LO: + case REG_DMA0SAD_HI: + case REG_DMA0DAD_LO: + case REG_DMA0DAD_HI: + case REG_DMA0CNT_LO: + case REG_DMA1SAD_LO: + case REG_DMA1SAD_HI: + case REG_DMA1DAD_LO: + case REG_DMA1DAD_HI: + case REG_DMA1CNT_LO: + case REG_DMA2SAD_LO: + case REG_DMA2SAD_HI: + case REG_DMA2DAD_LO: + case REG_DMA2DAD_HI: + case REG_DMA2CNT_LO: + case REG_DMA3SAD_LO: + case REG_DMA3SAD_HI: + case REG_DMA3DAD_LO: + case REG_DMA3DAD_HI: + case REG_DMA3CNT_LO: // Write-only register GBALog(gba, GBA_LOG_GAME_ERROR, "Read from write-only I/O register: %03X", address); - return GBALoad16(gba->cpu, 0x01000000, 0); // Simulate a bad load + return GBALoadBad(gba->cpu); + + case REG_SOUNDBIAS: + case REG_JOYCNT: + case REG_JOY_RECV: + case REG_JOY_TRANS: + case REG_KEYCNT: + case REG_POSTFLG: + GBALog(gba, GBA_LOG_STUB, "Stub I/O register read: %03x", address); + break; case REG_DISPCNT: case REG_DISPSTAT: case REG_VCOUNT: @@ -733,6 +773,15 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) { case REG_SOUND4CNT_HI: case REG_SOUNDCNT_LO: 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: @@ -752,12 +801,8 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) { // Some bad interrupt libraries will read from this break; default: - GBALog(gba, GBA_LOG_STUB, "Stub I/O register read: %03x", address); - if (address >= REG_MAX) { - GBALog(gba, GBA_LOG_GAME_ERROR, "Read from unused I/O register: %03X", address); - return GBALoad16(gba->cpu, 0x01000000, 0); - } - break; + GBALog(gba, GBA_LOG_GAME_ERROR, "Read from unused I/O register: %03X", address); + return GBALoadBad(gba->cpu); } return gba->memory.io[address >> 1]; } diff --git a/src/gba/memory.c b/src/gba/memory.c index 7f673dd5e..e67bd66ed 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -374,6 +374,13 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { value |= value << 8; \ value |= value << 16; +uint32_t GBALoadBad(struct ARMCore* cpu) { + struct GBA* gba = (struct GBA*) cpu->master; + uint32_t value = 0; + LOAD_BAD; + return value; +} + uint32_t GBALoad32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { struct GBA* gba = (struct GBA*) cpu->master; struct GBAMemory* memory = &gba->memory; @@ -1364,6 +1371,7 @@ uint16_t GBAMemoryWriteDMACNT_HI(struct GBA* gba, int dma, uint16_t control) { struct GBAMemory* memory = &gba->memory; struct GBADMA* currentDma = &memory->dma[dma]; int wasEnabled = GBADMARegisterIsEnable(currentDma->reg); + control &= 0xFFE0; currentDma->reg = control; if (GBADMARegisterIsDRQ(currentDma->reg)) { diff --git a/src/gba/memory.h b/src/gba/memory.h index 5a7deda1f..a70e3a1e6 100644 --- a/src/gba/memory.h +++ b/src/gba/memory.h @@ -151,6 +151,8 @@ uint32_t GBALoad32(struct ARMCore* cpu, uint32_t address, int* cycleCounter); uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter); uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter); +uint32_t GBALoadBad(struct ARMCore* cpu); + void GBAStore32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter); void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter); void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter);