From b867a40eb7680bdd99bfdd5e9a1416eb356e0ef0 Mon Sep 17 00:00:00 2001 From: zeromus Date: Fri, 1 Oct 2010 10:32:55 +0000 Subject: [PATCH] fix bugs in internal bios intrWaitARM after basic IRQ handling was rewritten --- desmume/src/armcpu.cpp | 1 + desmume/src/armcpu.h | 1 + desmume/src/bios.cpp | 66 +++++++++++++++++++++++++++--------------- desmume/src/saves.cpp | 2 ++ 4 files changed, 46 insertions(+), 24 deletions(-) diff --git a/desmume/src/armcpu.cpp b/desmume/src/armcpu.cpp index bff45cc58..3f0750744 100644 --- a/desmume/src/armcpu.cpp +++ b/desmume/src/armcpu.cpp @@ -221,6 +221,7 @@ void armcpu_init(armcpu_t *armcpu, u32 adr) armcpu->intVector = 0xFFFF0000 * (armcpu->proc_ID==0); armcpu->waitIRQ = FALSE; armcpu->halt_IE_and_IF = FALSE; + armcpu->intrWaitARM_state = 0; //#ifdef GDB_STUB // armcpu->irq_flag = 0; diff --git a/desmume/src/armcpu.h b/desmume/src/armcpu.h index 051c8d75d..1f9732316 100644 --- a/desmume/src/armcpu.h +++ b/desmume/src/armcpu.h @@ -206,6 +206,7 @@ struct armcpu_t u8 LDTBit; //1 : ARMv5 style 0 : non ARMv5 BOOL waitIRQ; BOOL halt_IE_and_IF; //the cpu is halted, waiting for IE&IF to signal something + u8 intrWaitARM_state; BOOL BIOS_loaded; diff --git a/desmume/src/bios.cpp b/desmume/src/bios.cpp index fad4af2ed..03891254f 100644 --- a/desmume/src/bios.cpp +++ b/desmume/src/bios.cpp @@ -216,40 +216,58 @@ TEMPLATE static u32 wait4IRQ() TEMPLATE u32 intrWaitARM() { - u32 intrFlagAdr = 0; - u32 intr = 0; - u32 intrFlag = 0; + //TODO - account for differences between arm7 and arm9 (according to gbatek, the "bug doesn't work") - //BOOL noDiscard = ((cpu->R[0] == 0) && (PROCNUM == ARMCPU_ARM7)); - - if(PROCNUM == ARMCPU_ARM7) - intrFlagAdr = 0x380FFF8; - else - intrFlagAdr = (((armcp15_t *)(cpu->coproc[15]))->DTCMRegion&0xFFFFF000)+0x3FF8; - - intr = _MMU_read32(intrFlagAdr); - intrFlag = (cpu->R[1] & intr); - - //INFO("ARM%c: wait for IRQ r0=0x%02X, r1=0x%08X - 0x%08X (flag 0x%08X)\n", PROCNUM?'7':'9', cpu->R[0], cpu->R[1], intr, intrFlag); - //if(!noDiscard) - // intrFlag &= cpu->newIrqFlags; + const u32 intrFlagAdr = (PROCNUM == ARMCPU_ARM7) + ? 0x380FFF8 + : (((armcp15_t *)(cpu->coproc[15]))->DTCMRegion&0xFFFFF000)+0x3FF8; //set IME=1 - _MMU_write32(0x04000208, 1); + //without this, no irq handlers can happen (even though IF&IE waits can happily happen) + //and so no bits in the OS irq flag variable can get set by the handlers + _MMU_write32(0x04000208, 1); - if (intrFlag) + //analyze the OS irq flag variable + u32 intr = _MMU_read32(intrFlagAdr); + u32 intrFlag = (cpu->R[1] & intr); + + //if the user requested us to discard flags, then clear the flag(s) we're going to be waiting on. + //(be sure to only do this only on the first run through. use a little state machine to control that) + if(cpu->intrWaitARM_state==0 && cpu->R[0]==1) { intr ^= intrFlag; - //if (intr) - _MMU_write32(intrFlagAdr, intr); - return wait4IRQ(); + _MMU_write32(intrFlagAdr, intr); + + //we want to make sure we wait at least once below + intrFlag = 0; } + + cpu->intrWaitARM_state = 1; + + //now, if the condition is satisfied (and it won't be the first time through, no matter what, due to cares taken above) + if(intrFlag) + { + //write back the OS irq flags with the ones we were waiting for cleared + intr ^= intrFlag; + _MMU_write32(intrFlagAdr, intr); + + //wait for an irq one last time. this is allegedly a bug. + cpu->waitIRQ = TRUE; + cpu->halt_IE_and_IF = TRUE; + + cpu->intrWaitARM_state = 0; + return 1; + } + + //the condition wasn't satisfied. this means that we need to halt, wait for some enabled interrupt, + //and then ensure that we return to this opcode again to check the condition again + cpu->waitIRQ = TRUE; + cpu->halt_IE_and_IF = TRUE; + + //(rewire PC to jump back to this opcode) u32 instructAddr = cpu->instruct_adr; cpu->R[15] = instructAddr; cpu->next_instruction = instructAddr; - cpu->waitIRQ = TRUE; - cpu->halt_IE_and_IF = TRUE; - return 1; } diff --git a/desmume/src/saves.cpp b/desmume/src/saves.cpp index b3fac2d25..349f17fd4 100644 --- a/desmume/src/saves.cpp +++ b/desmume/src/saves.cpp @@ -94,6 +94,7 @@ SFORMAT SF_ARM7[]={ { "7LDT", 1, 1, &NDS_ARM7.LDTBit }, { "7Wai", 4, 1, &NDS_ARM7.waitIRQ }, { "7hef", 4, 1, &NDS_ARM7.halt_IE_and_IF }, + { "7iws", 1, 1, &NDS_ARM7.intrWaitARM_state }, { 0 } }; @@ -130,6 +131,7 @@ SFORMAT SF_ARM9[]={ { "9LDT", 1, 1, &NDS_ARM9.LDTBit}, { "9Wai", 4, 1, &NDS_ARM9.waitIRQ}, { "9hef", 4, 1, &NDS_ARM9.halt_IE_and_IF }, + { "9iws", 1, 1, &NDS_ARM7.intrWaitARM_state }, { 0 } };