diff --git a/include/mgba/internal/arm/arm.h b/include/mgba/internal/arm/arm.h index ac2734172..6d1d9291e 100644 --- a/include/mgba/internal/arm/arm.h +++ b/include/mgba/internal/arm/arm.h @@ -254,6 +254,7 @@ void ARMSetPrivilegeMode(struct ARMCore*, enum PrivilegeMode); void ARMRaiseIRQ(struct ARMCore*); void ARMRaiseSWI(struct ARMCore*); void ARMRaiseUndefined(struct ARMCore*); +void ARMHalt(struct ARMCore*); void ARMv4Run(struct ARMCore* cpu); void ARMv4RunLoop(struct ARMCore* cpu); diff --git a/src/arm/arm.c b/src/arm/arm.c index 7db39d7a9..372da1411 100644 --- a/src/arm/arm.c +++ b/src/arm/arm.c @@ -223,6 +223,11 @@ void ARMRaiseUndefined(struct ARMCore* cpu) { cpu->cycles += currentCycles; } +void ARMHalt(struct ARMCore* cpu) { + cpu->nextEvent = cpu->cycles; + cpu->halted = 1; +} + #define ARM_IMPLEMENT(VERSION) \ static inline void ARM ## VERSION ## Step(struct ARMCore* cpu) { \ uint32_t opcode = cpu->prefetch[0]; \ diff --git a/src/ds/ds.c b/src/ds/ds.c index 536e15a61..555ed2d14 100644 --- a/src/ds/ds.c +++ b/src/ds/ds.c @@ -508,6 +508,14 @@ static void _writeRegionConfiguration(struct ARMCore* cpu, int crm, int opcode2, } static void _writeCache(struct ARMCore* cpu, int crm, int opcode2, uint32_t value) { + switch (crm) { + case 0: + if (opcode2 == 4) { + ARMHalt(cpu); + return; + } + break; + } mLOG(DS, STUB, "CP15 cache write: CRm: %i, Op2: %i, Value: 0x%08X", crm, opcode2, value); } diff --git a/src/ds/io.c b/src/ds/io.c index 856aecdf1..dc7c26933 100644 --- a/src/ds/io.c +++ b/src/ds/io.c @@ -10,6 +10,23 @@ mLOG_DEFINE_CATEGORY(DS_IO, "DS I/O"); +static void _DSHaltCNT(struct DSCommon* dscore, uint8_t value) { + switch (value >> 6) { + case 0: + default: + break; + case 1: + mLOG(DS_IO, STUB, "Enter GBA mode not supported"); + break; + case 2: + ARMHalt(dscore->cpu); + break; + case 3: + mLOG(DS_IO, STUB, "Enter sleep mode not supported"); + break; + } +} + static uint32_t DSIOWrite(struct DSCommon* dscore, uint32_t address, uint16_t value) { switch (address) { // Timers @@ -108,6 +125,10 @@ void DS7IOWrite(struct DS* ds, uint32_t address, uint16_t value) { } void DS7IOWrite8(struct DS* ds, uint32_t address, uint8_t value) { + if (address == DS7_REG_HALTCNT) { + _DSHaltCNT(&ds->ds7, value); + return; + } if (address < DS7_REG_MAX) { uint16_t value16 = value << (8 * (address & 1)); value16 |= (ds->ds7.memory.io[(address & 0xFFF) >> 1]) & ~(0xFF << (8 * (address & 1))); diff --git a/src/gba/gba.c b/src/gba/gba.c index 857552ed2..f1b8c63ca 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -434,8 +434,7 @@ void GBATestIRQ(struct ARMCore* cpu) { } void GBAHalt(struct GBA* gba) { - gba->cpu->nextEvent = gba->cpu->cycles; - gba->cpu->halted = 1; + ARMHalt(gba->cpu); } void GBAStop(struct GBA* gba) {