Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Maddie:emulation
melonds
melonds_PR2125.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File melonds_PR2125.patch of Package melonds
diff --git a/src/ARM.cpp b/src/ARM.cpp index 3452d361..9919cbcb 100644 --- a/src/ARM.cpp +++ b/src/ARM.cpp @@ -343,13 +343,28 @@ void ARMv5::JumpTo(u32 addr, bool restorecpsr) CPSR &= ~0x20; } - if (!(PU_Map[addr>>12] & 0x04)) + NDS.MonitorARM9Jump(addr); +} + +void ARMv5::JumpTo8_16Bit(const u32 addr) +{ + // 8 and 16 loads (signed included) to pc + if (!(CP15Control & 0x1)) { - PrefetchAbort(); - return; + // if the pu is disabled it behaves like a normal jump + JumpTo((CP15Control & (1<<15)) ? (addr & ~0x1) : addr); + } + else + { + if (addr & 0x3) + { + // if the pu is enabled it will always prefetch abort if not word aligned + // although it will still attempt (and fail) to enter thumb mode if enabled + if ((addr & 0x1) && !(CP15Control & (1<<15))) CPSR |= 0x20; + PrefetchAbort(); + } + else JumpTo(addr); } - - NDS.MonitorARM9Jump(addr); } void ARMv4::JumpTo(u32 addr, bool restorecpsr) @@ -396,6 +411,11 @@ void ARMv4::JumpTo(u32 addr, bool restorecpsr) } } +void ARMv4::JumpTo8_16Bit(const u32 addr) +{ + JumpTo(addr & ~1); // checkme? +} + void ARM::RestoreCPSR() { u32 oldcpsr = CPSR; @@ -517,6 +537,7 @@ void ARM::UpdateMode(u32 oldmode, u32 newmode, bool phony) } } +template <CPUExecuteMode mode> void ARM::TriggerIRQ() { if (CPSR & 0x80) @@ -528,7 +549,10 @@ void ARM::TriggerIRQ() UpdateMode(oldcpsr, CPSR); R_IRQ[2] = oldcpsr; - R[14] = R[15] + (oldcpsr & 0x20 ? 2 : 0); + if constexpr (mode == CPUExecuteMode::JIT) + R[14] = R[15] + (oldcpsr & 0x20 ? 2 : 0); + else + R[14] = R[15] - (oldcpsr & 0x20 ? 0 : 4); JumpTo(ExceptionBase + 0x18); // ARDS cheat support @@ -539,6 +563,11 @@ void ARM::TriggerIRQ() NDS.AREngine.RunCheats(); } } +template void ARM::TriggerIRQ<CPUExecuteMode::Interpreter>(); +template void ARM::TriggerIRQ<CPUExecuteMode::InterpreterGDB>(); +#ifdef JIT_ENABLED +template void ARM::TriggerIRQ<CPUExecuteMode::JIT>(); +#endif void ARMv5::PrefetchAbort() { @@ -549,17 +578,8 @@ void ARMv5::PrefetchAbort() CPSR |= 0x97; UpdateMode(oldcpsr, CPSR); - // this shouldn't happen, but if it does, we're stuck in some nasty endless loop - // so better take care of it - if (!(PU_Map[ExceptionBase>>12] & 0x04)) - { - Log(LogLevel::Error, "!!!!! EXCEPTION REGION NOT EXECUTABLE. THIS IS VERY BAD!!\n"); - NDS.Stop(Platform::StopReason::BadExceptionRegion); - return; - } - R_ABT[2] = oldcpsr; - R[14] = R[15] + (oldcpsr & 0x20 ? 2 : 0); + R[14] = R[15] - (oldcpsr & 0x20 ? 0 : 4); JumpTo(ExceptionBase + 0x0C); } @@ -598,7 +618,10 @@ void ARMv5::Execute() { Halted = 0; if (NDS.IME[0] & 0x1) - TriggerIRQ(); + { + if constexpr (mode == CPUExecuteMode::JIT) TriggerIRQ<mode>(); + else IRQ = 1; + } } else { @@ -632,7 +655,7 @@ void ARMv5::Execute() { // this order is crucial otherwise idle loops waiting for an IRQ won't function if (IRQ) - TriggerIRQ(); + TriggerIRQ<mode>(); if (Halted || IdleLoop) { @@ -659,10 +682,18 @@ void ARMv5::Execute() NextInstr[0] = NextInstr[1]; if (R[15] & 0x2) { NextInstr[1] >>= 16; CodeCycles = 0; } else NextInstr[1] = CodeRead32(R[15], false); - - // actually execute - u32 icode = (CurInstr >> 6) & 0x3FF; - ARMInterpreter::THUMBInstrTable[icode](this); + + + if (IRQ && !(CPSR & 0x80)) TriggerIRQ<mode>(); + else if (!(PU_Map[(R[15]-4)>>12] & 0x04)) [[unlikely]] // handle aborted instructions + { + PrefetchAbort(); + } + else [[likely]] // actually execute + { + u32 icode = (CurInstr >> 6) & 0x3FF; + ARMInterpreter::THUMBInstrTable[icode](this); + } } else { @@ -674,9 +705,14 @@ void ARMv5::Execute() CurInstr = NextInstr[0]; NextInstr[0] = NextInstr[1]; NextInstr[1] = CodeRead32(R[15], false); + - // actually execute - if (CheckCondition(CurInstr >> 28)) + if (IRQ && !(CPSR & 0x80)) TriggerIRQ<mode>(); + else if (!(PU_Map[(R[15]-8)>>12] & 0x04)) [[unlikely]] // handle aborted instructions + { + PrefetchAbort(); + } + else if (CheckCondition(CurInstr >> 28)) [[likely]] // actually execute { u32 icode = ((CurInstr >> 4) & 0xF) | ((CurInstr >> 16) & 0xFF0); ARMInterpreter::ARMInstrTable[icode](this); @@ -701,10 +737,8 @@ void ARMv5::Execute() /*if (NDS::IF[0] & NDS::IE[0]) { if (NDS::IME[0] & 0x1) - TriggerIRQ(); + TriggerIRQ<mode>(); }*/ - if (IRQ) TriggerIRQ(); - } NDS.ARM9Timestamp += Cycles; @@ -736,7 +770,10 @@ void ARMv4::Execute() { Halted = 0; if (NDS.IME[1] & 0x1) - TriggerIRQ(); + { + if constexpr (mode == CPUExecuteMode::JIT) TriggerIRQ<mode>(); + else IRQ = 1; + } } else { @@ -769,7 +806,7 @@ void ARMv4::Execute() if (StopExecution) { if (IRQ) - TriggerIRQ(); + TriggerIRQ<mode>(); if (Halted || IdleLoop) { @@ -796,9 +833,13 @@ void ARMv4::Execute() NextInstr[0] = NextInstr[1]; NextInstr[1] = CodeRead16(R[15]); - // actually execute - u32 icode = (CurInstr >> 6); - ARMInterpreter::THUMBInstrTable[icode](this); + if (IRQ && !(CPSR & 0x80)) TriggerIRQ<mode>(); + else + { + // actually execute + u32 icode = (CurInstr >> 6); + ARMInterpreter::THUMBInstrTable[icode](this); + } } else { @@ -811,8 +852,8 @@ void ARMv4::Execute() NextInstr[0] = NextInstr[1]; NextInstr[1] = CodeRead32(R[15]); - // actually execute - if (CheckCondition(CurInstr >> 28)) + if (IRQ && !(CPSR & 0x80)) TriggerIRQ<mode>(); + else if (CheckCondition(CurInstr >> 28)) // actually execute { u32 icode = ((CurInstr >> 4) & 0xF) | ((CurInstr >> 16) & 0xFF0); ARMInterpreter::ARMInstrTable[icode](this); @@ -833,9 +874,8 @@ void ARMv4::Execute() /*if (NDS::IF[1] & NDS::IE[1]) { if (NDS::IME[1] & 0x1) - TriggerIRQ(); + TriggerIRQ<mode>(); }*/ - if (IRQ) TriggerIRQ(); } NDS.ARM7Timestamp += Cycles; @@ -1108,70 +1148,78 @@ u32 ARMv5::ReadMem(u32 addr, int size) } #endif -void ARMv4::DataRead8(u32 addr, u32* val) +bool ARMv4::DataRead8(u32 addr, u32* val) { *val = BusRead8(addr); DataRegion = addr; DataCycles = NDS.ARM7MemTimings[addr >> 15][0]; + return true; } -void ARMv4::DataRead16(u32 addr, u32* val) +bool ARMv4::DataRead16(u32 addr, u32* val) { addr &= ~1; *val = BusRead16(addr); DataRegion = addr; DataCycles = NDS.ARM7MemTimings[addr >> 15][0]; + return true; } -void ARMv4::DataRead32(u32 addr, u32* val) +bool ARMv4::DataRead32(u32 addr, u32* val) { addr &= ~3; *val = BusRead32(addr); DataRegion = addr; DataCycles = NDS.ARM7MemTimings[addr >> 15][2]; + return true; } -void ARMv4::DataRead32S(u32 addr, u32* val) +bool ARMv4::DataRead32S(u32 addr, u32* val) { addr &= ~3; *val = BusRead32(addr); DataCycles += NDS.ARM7MemTimings[addr >> 15][3]; + return true; } -void ARMv4::DataWrite8(u32 addr, u8 val) +bool ARMv4::DataWrite8(u32 addr, u8 val) { BusWrite8(addr, val); DataRegion = addr; DataCycles = NDS.ARM7MemTimings[addr >> 15][0]; + return true; } -void ARMv4::DataWrite16(u32 addr, u16 val) +bool ARMv4::DataWrite16(u32 addr, u16 val) { addr &= ~1; BusWrite16(addr, val); DataRegion = addr; DataCycles = NDS.ARM7MemTimings[addr >> 15][0]; + return true; } -void ARMv4::DataWrite32(u32 addr, u32 val) +bool ARMv4::DataWrite32(u32 addr, u32 val) { addr &= ~3; BusWrite32(addr, val); DataRegion = addr; DataCycles = NDS.ARM7MemTimings[addr >> 15][2]; + return true; } -void ARMv4::DataWrite32S(u32 addr, u32 val) +bool ARMv4::DataWrite32S(u32 addr, u32 val, bool dataabort) { addr &= ~3; BusWrite32(addr, val); DataCycles += NDS.ARM7MemTimings[addr >> 15][3]; + return true; } diff --git a/src/ARM.h b/src/ARM.h index b652e74d..2603e646 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -75,6 +75,7 @@ public: virtual void FillPipeline() = 0; virtual void JumpTo(u32 addr, bool restorecpsr = false) = 0; + virtual void JumpTo8_16Bit(u32 addr) = 0; void RestoreCPSR(); void Halt(u32 halt) @@ -128,19 +129,20 @@ public: void UpdateMode(u32 oldmode, u32 newmode, bool phony = false); + template <CPUExecuteMode mode> void TriggerIRQ(); void SetupCodeMem(u32 addr); - virtual void DataRead8(u32 addr, u32* val) = 0; - virtual void DataRead16(u32 addr, u32* val) = 0; - virtual void DataRead32(u32 addr, u32* val) = 0; - virtual void DataRead32S(u32 addr, u32* val) = 0; - virtual void DataWrite8(u32 addr, u8 val) = 0; - virtual void DataWrite16(u32 addr, u16 val) = 0; - virtual void DataWrite32(u32 addr, u32 val) = 0; - virtual void DataWrite32S(u32 addr, u32 val) = 0; + virtual bool DataRead8(u32 addr, u32* val) = 0; + virtual bool DataRead16(u32 addr, u32* val) = 0; + virtual bool DataRead32(u32 addr, u32* val) = 0; + virtual bool DataRead32S(u32 addr, u32* val) = 0; + virtual bool DataWrite8(u32 addr, u8 val) = 0; + virtual bool DataWrite16(u32 addr, u16 val) = 0; + virtual bool DataWrite32(u32 addr, u32 val) = 0; + virtual bool DataWrite32S(u32 addr, u32 val, bool dataabort = false) = 0; virtual void AddCycles_C() = 0; virtual void AddCycles_CI(s32 numI) = 0; @@ -242,6 +244,7 @@ public: void FillPipeline() override; void JumpTo(u32 addr, bool restorecpsr = false) override; + void JumpTo8_16Bit(const u32 addr) override; void PrefetchAbort(); void DataAbort(); @@ -252,14 +255,14 @@ public: // all code accesses are forced nonseq 32bit u32 CodeRead32(u32 addr, bool branch); - void DataRead8(u32 addr, u32* val) override; - void DataRead16(u32 addr, u32* val) override; - void DataRead32(u32 addr, u32* val) override; - void DataRead32S(u32 addr, u32* val) override; - void DataWrite8(u32 addr, u8 val) override; - void DataWrite16(u32 addr, u16 val) override; - void DataWrite32(u32 addr, u32 val) override; - void DataWrite32S(u32 addr, u32 val) override; + bool DataRead8(u32 addr, u32* val) override; + bool DataRead16(u32 addr, u32* val) override; + bool DataRead32(u32 addr, u32* val) override; + bool DataRead32S(u32 addr, u32* val) override; + bool DataWrite8(u32 addr, u8 val) override; + bool DataWrite16(u32 addr, u16 val) override; + bool DataWrite32(u32 addr, u32 val) override; + bool DataWrite32S(u32 addr, u32 val, bool dataabort = false) override; void AddCycles_C() override { @@ -385,6 +388,7 @@ public: void FillPipeline() override; void JumpTo(u32 addr, bool restorecpsr = false) override; + void JumpTo8_16Bit(const u32 addr) override; template <CPUExecuteMode mode> void Execute(); @@ -399,18 +403,19 @@ public: return BusRead32(addr); } - void DataRead8(u32 addr, u32* val) override; - void DataRead16(u32 addr, u32* val) override; - void DataRead32(u32 addr, u32* val) override; - void DataRead32S(u32 addr, u32* val) override; - void DataWrite8(u32 addr, u8 val) override; - void DataWrite16(u32 addr, u16 val) override; - void DataWrite32(u32 addr, u32 val) override; - void DataWrite32S(u32 addr, u32 val) override; + bool DataRead8(u32 addr, u32* val) override; + bool DataRead16(u32 addr, u32* val) override; + bool DataRead32(u32 addr, u32* val) override; + bool DataRead32S(u32 addr, u32* val) override; + bool DataWrite8(u32 addr, u8 val) override; + bool DataWrite16(u32 addr, u16 val) override; + bool DataWrite32(u32 addr, u32 val) override; + bool DataWrite32S(u32 addr, u32 val, bool dataabort = false) override; void AddCycles_C() override; void AddCycles_CI(s32 num) override; void AddCycles_CDI() override; void AddCycles_CD() override; + protected: u8 BusRead8(u32 addr) override; u16 BusRead16(u32 addr) override; diff --git a/src/ARMInterpreter.cpp b/src/ARMInterpreter.cpp index f5bf7713..6e6c9a8d 100644 --- a/src/ARMInterpreter.cpp +++ b/src/ARMInterpreter.cpp @@ -101,9 +101,9 @@ void A_MSR_IMM(ARM* cpu) u32 mask = 0; if (cpu->CurInstr & (1<<16)) mask |= 0x000000FF; - if (cpu->CurInstr & (1<<17)) mask |= 0x0000FF00; - if (cpu->CurInstr & (1<<18)) mask |= 0x00FF0000; - if (cpu->CurInstr & (1<<19)) mask |= 0xFF000000; + //if (cpu->CurInstr & (1<<17)) mask |= 0x0000FF00; // unused by arm 7 & 9 + //if (cpu->CurInstr & (1<<18)) mask |= 0x00FF0000; // unused by arm 7 & 9 + if (cpu->CurInstr & (1<<19)) mask |= ((cpu->Num==1) ? 0xF0000000 : 0xF8000000); if (!(cpu->CurInstr & (1<<22))) mask &= 0xFFFFFFDF; @@ -121,7 +121,8 @@ void A_MSR_IMM(ARM* cpu) if (!(cpu->CurInstr & (1<<22))) cpu->UpdateMode(oldpsr, cpu->CPSR); - cpu->AddCycles_C(); + if ((cpu->Num != 1) && (cpu->CurInstr & (0x7<<16))) cpu->AddCycles_CI(2); + else cpu->AddCycles_C(); } void A_MSR_REG(ARM* cpu) @@ -154,9 +155,9 @@ void A_MSR_REG(ARM* cpu) u32 mask = 0; if (cpu->CurInstr & (1<<16)) mask |= 0x000000FF; - if (cpu->CurInstr & (1<<17)) mask |= 0x0000FF00; - if (cpu->CurInstr & (1<<18)) mask |= 0x00FF0000; - if (cpu->CurInstr & (1<<19)) mask |= 0xFF000000; + //if (cpu->CurInstr & (1<<17)) mask |= 0x0000FF00; // unused by arm 7 & 9 + //if (cpu->CurInstr & (1<<18)) mask |= 0x00FF0000; // unused by arm 7 & 9 + if (cpu->CurInstr & (1<<19)) mask |= ((cpu->Num==1) ? 0xF0000000 : 0xF8000000); if (!(cpu->CurInstr & (1<<22))) mask &= 0xFFFFFFDF; @@ -174,7 +175,8 @@ void A_MSR_REG(ARM* cpu) if (!(cpu->CurInstr & (1<<22))) cpu->UpdateMode(oldpsr, cpu->CPSR); - cpu->AddCycles_C(); + if ((cpu->Num != 1) && (cpu->CurInstr & (0x7<<16))) cpu->AddCycles_CI(2); + else cpu->AddCycles_C(); } void A_MRS(ARM* cpu) @@ -202,7 +204,9 @@ void A_MRS(ARM* cpu) psr = cpu->CPSR; cpu->R[(cpu->CurInstr>>12) & 0xF] = psr; - cpu->AddCycles_C(); + + if (cpu->Num != 1) cpu->AddCycles_CI(1); // arm9 + else cpu->AddCycles_C(); // arm7 } @@ -216,10 +220,12 @@ void A_MCR(ARM* cpu) u32 cn = (cpu->CurInstr >> 16) & 0xF; u32 cm = cpu->CurInstr & 0xF; u32 cpinfo = (cpu->CurInstr >> 5) & 0x7; + u32 val = cpu->R[(cpu->CurInstr>>12)&0xF]; + if (((cpu->CurInstr>>12) & 0xF) == 15) val += 4; if (cpu->Num==0 && cp==15) { - ((ARMv5*)cpu)->CP15Write((cn<<8)|(cm<<4)|cpinfo, cpu->R[(cpu->CurInstr>>12)&0xF]); + ((ARMv5*)cpu)->CP15Write((cn<<8)|(cm<<4)|cpinfo, val); } else if (cpu->Num==1 && cp==14) { @@ -259,12 +265,13 @@ void A_MRC(ARM* cpu) return A_UNK(cpu); // TODO: check what kind of exception it really is } - cpu->AddCycles_CI(2 + 1); // TODO: checkme + if (cpu->Num != 1) cpu->AddCycles_CI(1); // checkme + else cpu->AddCycles_CI(2 + 1); // TODO: checkme } -void A_SVC(ARM* cpu) +void A_SVC(ARM* cpu) // A_SWI { u32 oldcpsr = cpu->CPSR; cpu->CPSR &= ~0xBF; @@ -276,7 +283,7 @@ void A_SVC(ARM* cpu) cpu->JumpTo(cpu->ExceptionBase + 0x08); } -void T_SVC(ARM* cpu) +void T_SVC(ARM* cpu) // T_SWI { u32 oldcpsr = cpu->CPSR; cpu->CPSR &= ~0xBF; diff --git a/src/ARMInterpreter_ALU.cpp b/src/ARMInterpreter_ALU.cpp index 167e184e..37c79904 100644 --- a/src/ARMInterpreter_ALU.cpp +++ b/src/ARMInterpreter_ALU.cpp @@ -836,7 +836,7 @@ void A_UMULL(ARM* cpu) u32 cycles; if (cpu->Num == 0) - cycles = (cpu->CurInstr & (1<<20)) ? 3 : 1; + cycles = (cpu->CurInstr & (1<<20)) ? 4 : 2; else { if ((rs & 0xFFFFFF00) == 0x00000000) cycles = 2; @@ -869,7 +869,7 @@ void A_UMLAL(ARM* cpu) u32 cycles; if (cpu->Num == 0) - cycles = (cpu->CurInstr & (1<<20)) ? 3 : 1; + cycles = (cpu->CurInstr & (1<<20)) ? 4 : 2; else { if ((rs & 0xFFFFFF00) == 0x00000000) cycles = 2; @@ -899,7 +899,7 @@ void A_SMULL(ARM* cpu) u32 cycles; if (cpu->Num == 0) - cycles = (cpu->CurInstr & (1<<20)) ? 3 : 1; + cycles = (cpu->CurInstr & (1<<20)) ? 4 : 2; else { if ((rs & 0xFFFFFF00) == 0x00000000 || (rs & 0xFFFFFF00) == 0xFFFFFF00) cycles = 2; @@ -932,7 +932,7 @@ void A_SMLAL(ARM* cpu) u32 cycles; if (cpu->Num == 0) - cycles = (cpu->CurInstr & (1<<20)) ? 3 : 1; + cycles = (cpu->CurInstr & (1<<20)) ? 4 : 2; else { if ((rs & 0xFFFFFF00) == 0x00000000 || (rs & 0xFFFFFF00) == 0xFFFFFF00) cycles = 2; @@ -1067,7 +1067,8 @@ void A_CLZ(ARM* cpu) val |= 0x1; } - cpu->R[(cpu->CurInstr >> 12) & 0xF] = res; + if (((cpu->CurInstr >> 12) & 0xF) == 15) cpu->JumpTo(res & ~1); + else cpu->R[(cpu->CurInstr >> 12) & 0xF] = res; cpu->AddCycles_C(); } diff --git a/src/ARMInterpreter_LoadStore.cpp b/src/ARMInterpreter_LoadStore.cpp index cb646df5..580c66fc 100644 --- a/src/ARMInterpreter_LoadStore.cpp +++ b/src/ARMInterpreter_LoadStore.cpp @@ -65,9 +65,10 @@ namespace melonDS::ARMInterpreter u32 storeval = cpu->R[(cpu->CurInstr>>12) & 0xF]; \ if (((cpu->CurInstr>>12) & 0xF) == 0xF) \ storeval += 4; \ - cpu->DataWrite32(offset, storeval); \ - if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; \ - cpu->AddCycles_CD(); + bool dataabort = !cpu->DataWrite32(offset, storeval); \ + cpu->AddCycles_CD(); \ + if (dataabort) return; \ + if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; // TODO: user mode (bit21) #define A_STR_POST \ @@ -75,32 +76,40 @@ namespace melonDS::ARMInterpreter u32 storeval = cpu->R[(cpu->CurInstr>>12) & 0xF]; \ if (((cpu->CurInstr>>12) & 0xF) == 0xF) \ storeval += 4; \ - cpu->DataWrite32(addr, storeval); \ - cpu->R[(cpu->CurInstr>>16) & 0xF] += offset; \ - cpu->AddCycles_CD(); + bool dataabort = !cpu->DataWrite32(addr, storeval); \ + cpu->AddCycles_CD(); \ + if (dataabort) return; \ + cpu->R[(cpu->CurInstr>>16) & 0xF] += offset; #define A_STRB \ offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \ - cpu->DataWrite8(offset, cpu->R[(cpu->CurInstr>>12) & 0xF]); \ - if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; \ - cpu->AddCycles_CD(); + u32 storeval = cpu->R[(cpu->CurInstr>>12) & 0xF]; \ + if (((cpu->CurInstr>>12) & 0xF) == 15) storeval+=4; \ + bool dataabort = !cpu->DataWrite8(offset, storeval); \ + cpu->AddCycles_CD(); \ + if (dataabort) return; \ + if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; // TODO: user mode (bit21) #define A_STRB_POST \ u32 addr = cpu->R[(cpu->CurInstr>>16) & 0xF]; \ - cpu->DataWrite8(addr, cpu->R[(cpu->CurInstr>>12) & 0xF]); \ - cpu->R[(cpu->CurInstr>>16) & 0xF] += offset; \ - cpu->AddCycles_CD(); + u32 storeval = cpu->R[(cpu->CurInstr>>12) & 0xF]; \ + if (((cpu->CurInstr>>12) & 0xF) == 15) storeval+=4; \ + bool dataabort = !cpu->DataWrite8(addr, storeval); \ + cpu->AddCycles_CD(); \ + if (dataabort) return; \ + cpu->R[(cpu->CurInstr>>16) & 0xF] += offset; #define A_LDR \ offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \ - u32 val; cpu->DataRead32(offset, &val); \ + u32 val; bool dataabort = !cpu->DataRead32(offset, &val); \ + cpu->AddCycles_CDI(); \ + if (dataabort) return; \ val = ROR(val, ((offset&0x3)<<3)); \ if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; \ - cpu->AddCycles_CDI(); \ if (((cpu->CurInstr>>12) & 0xF) == 15) \ { \ - if (cpu->Num==1) val &= ~0x1; \ + if (cpu->Num==1 || (((ARMv5*)cpu)->CP15Control & (1<<15))) val &= ~0x1; \ cpu->JumpTo(val); \ } \ else \ @@ -111,13 +120,14 @@ namespace melonDS::ARMInterpreter // TODO: user mode #define A_LDR_POST \ u32 addr = cpu->R[(cpu->CurInstr>>16) & 0xF]; \ - u32 val; cpu->DataRead32(addr, &val); \ + u32 val; bool dataabort = !cpu->DataRead32(addr, &val); \ + cpu->AddCycles_CDI(); \ + if (dataabort) return; \ val = ROR(val, ((addr&0x3)<<3)); \ cpu->R[(cpu->CurInstr>>16) & 0xF] += offset; \ - cpu->AddCycles_CDI(); \ if (((cpu->CurInstr>>12) & 0xF) == 15) \ { \ - if (cpu->Num==1) val &= ~0x1; \ + if (cpu->Num==1 || (((ARMv5*)cpu)->CP15Control & (1<<15))) val &= ~0x1; \ cpu->JumpTo(val); \ } \ else \ @@ -127,20 +137,22 @@ namespace melonDS::ARMInterpreter #define A_LDRB \ offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \ - u32 val; cpu->DataRead8(offset, &val); \ - if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; \ + u32 val; bool dataabort = !cpu->DataRead8(offset, &val); \ cpu->AddCycles_CDI(); \ - cpu->R[(cpu->CurInstr>>12) & 0xF] = val; \ - if (((cpu->CurInstr>>12) & 0xF) == 15) printf("!! LDRB PC %08X\n", cpu->R[15]); \ + if (dataabort) return; \ + if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; \ + if (((cpu->CurInstr>>12) & 0xF) == 15) cpu->JumpTo8_16Bit(val); \ + else cpu->R[(cpu->CurInstr>>12) & 0xF] = val; // TODO: user mode #define A_LDRB_POST \ u32 addr = cpu->R[(cpu->CurInstr>>16) & 0xF]; \ - u32 val; cpu->DataRead8(addr, &val); \ - cpu->R[(cpu->CurInstr>>16) & 0xF] += offset; \ + u32 val; bool dataabort = !cpu->DataRead8(addr, &val); \ cpu->AddCycles_CDI(); \ - cpu->R[(cpu->CurInstr>>12) & 0xF] = val; \ - if (((cpu->CurInstr>>12) & 0xF) == 15) printf("!! LDRB PC %08X\n", cpu->R[15]); \ + if (dataabort) return; \ + cpu->R[(cpu->CurInstr>>16) & 0xF] += offset; \ + if (((cpu->CurInstr>>12) & 0xF) == 15) cpu->JumpTo8_16Bit(val); \ + else cpu->R[(cpu->CurInstr>>12) & 0xF] = val; @@ -225,103 +237,129 @@ A_IMPLEMENT_WB_LDRSTR(LDRB) #define A_STRH \ offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \ - cpu->DataWrite16(offset, cpu->R[(cpu->CurInstr>>12) & 0xF]); \ - if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; \ - cpu->AddCycles_CD(); + u32 storeval = cpu->R[(cpu->CurInstr>>12) & 0xF]; \ + if (((cpu->CurInstr>>12) & 0xF) == 15) storeval+=4; \ + bool dataabort = !cpu->DataWrite16(offset, storeval); \ + cpu->AddCycles_CD(); \ + if (dataabort) return; \ + if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; #define A_STRH_POST \ u32 addr = cpu->R[(cpu->CurInstr>>16) & 0xF]; \ - cpu->DataWrite16(addr, cpu->R[(cpu->CurInstr>>12) & 0xF]); \ - cpu->R[(cpu->CurInstr>>16) & 0xF] += offset; \ - cpu->AddCycles_CD(); + u32 storeval = cpu->R[(cpu->CurInstr>>12) & 0xF]; \ + if (((cpu->CurInstr>>12) & 0xF) == 15) storeval+=4; \ + bool dataabort = !cpu->DataWrite16(addr, storeval); \ + cpu->AddCycles_CD(); \ + if (dataabort) return; \ + cpu->R[(cpu->CurInstr>>16) & 0xF] += offset; // TODO: CHECK LDRD/STRD TIMINGS!! #define A_LDRD \ if (cpu->Num != 0) return; \ offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \ - if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; \ u32 r = (cpu->CurInstr>>12) & 0xF; \ - if (r&1) { r--; printf("!! MISALIGNED LDRD %d\n", r+1); } \ - cpu->DataRead32 (offset , &cpu->R[r ]); \ - cpu->DataRead32S(offset+4, &cpu->R[r+1]); \ - cpu->AddCycles_CDI(); + if (r&1) { A_UNK(cpu); return; } \ + if (!cpu->DataRead32 (offset , &cpu->R[r ])) {cpu->AddCycles_CDI(); return;} \ + u32 val; if (!cpu->DataRead32S(offset+4, &val)) {cpu->AddCycles_CDI(); return;} \ + if (r == 14) cpu->JumpTo(((((ARMv5*)cpu)->CP15Control & (1<<15)) ? (val & ~0x1) : val), cpu->CurInstr & (1<<22)); /* restores cpsr presumably due to shared dna with ldm */ \ + else cpu->R[r+1] = val; \ + cpu->AddCycles_CDI(); \ + if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; #define A_LDRD_POST \ if (cpu->Num != 0) return; \ u32 addr = cpu->R[(cpu->CurInstr>>16) & 0xF]; \ - cpu->R[(cpu->CurInstr>>16) & 0xF] += offset; \ u32 r = (cpu->CurInstr>>12) & 0xF; \ - if (r&1) { r--; printf("!! MISALIGNED LDRD_POST %d\n", r+1); } \ - cpu->DataRead32 (addr , &cpu->R[r ]); \ - cpu->DataRead32S(addr+4, &cpu->R[r+1]); \ - cpu->AddCycles_CDI(); + if (r&1) { A_UNK(cpu); return; } \ + if (!cpu->DataRead32 (addr , &cpu->R[r ])) {cpu->AddCycles_CDI(); return;} \ + u32 val; if (!cpu->DataRead32S(addr+4, &val)) {cpu->AddCycles_CDI(); return;} \ + if (r == 14) cpu->JumpTo(((((ARMv5*)cpu)->CP15Control & (1<<15)) ? (val & ~0x1) : val), cpu->CurInstr & (1<<22)); /* restores cpsr presumably due to shared dna with ldm */ \ + else cpu->R[r+1] = val; \ + cpu->AddCycles_CDI(); \ + cpu->R[(cpu->CurInstr>>16) & 0xF] += offset; #define A_STRD \ if (cpu->Num != 0) return; \ offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \ - if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; \ u32 r = (cpu->CurInstr>>12) & 0xF; \ - if (r&1) { r--; printf("!! MISALIGNED STRD %d\n", r+1); } \ - cpu->DataWrite32 (offset , cpu->R[r ]); \ - cpu->DataWrite32S(offset+4, cpu->R[r+1]); \ - cpu->AddCycles_CD(); + if (r&1) { A_UNK(cpu); return; } \ + bool dataabort = !cpu->DataWrite32(offset, cpu->R[r]); /* yes, this data abort behavior is on purpose */ \ + u32 storeval = cpu->R[r+1]; if (r == 14) storeval+=4; \ + dataabort |= !cpu->DataWrite32S (offset+4, storeval, dataabort); /* no, i dont understand it either */ \ + cpu->AddCycles_CD(); \ + if (dataabort) return; \ + if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; #define A_STRD_POST \ if (cpu->Num != 0) return; \ u32 addr = cpu->R[(cpu->CurInstr>>16) & 0xF]; \ - cpu->R[(cpu->CurInstr>>16) & 0xF] += offset; \ u32 r = (cpu->CurInstr>>12) & 0xF; \ - if (r&1) { r--; printf("!! MISALIGNED STRD_POST %d\n", r+1); } \ - cpu->DataWrite32 (addr , cpu->R[r ]); \ - cpu->DataWrite32S(addr+4, cpu->R[r+1]); \ - cpu->AddCycles_CD(); + if (r&1) { A_UNK(cpu); return; } \ + bool dataabort = !cpu->DataWrite32(addr, cpu->R[r]); \ + u32 storeval = cpu->R[r+1]; if (r == 14) storeval+=4; \ + dataabort |= !cpu->DataWrite32S (addr+4, storeval, dataabort); \ + cpu->AddCycles_CD(); \ + if (dataabort) return; \ + cpu->R[(cpu->CurInstr>>16) & 0xF] += offset; #define A_LDRH \ offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \ - if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; \ - cpu->DataRead16(offset, &cpu->R[(cpu->CurInstr>>12) & 0xF]); \ + u32 val; bool dataabort = !cpu->DataRead16(offset, &val); \ cpu->AddCycles_CDI(); \ - if (((cpu->CurInstr>>12) & 0xF) == 15) printf("!! LDRH PC %08X\n", cpu->R[15]); \ + if (dataabort) return; \ + if (((cpu->CurInstr>>12) & 0xF) == 15) cpu->JumpTo8_16Bit(val); \ + else cpu->R[(cpu->CurInstr>>12) & 0xF] = val; \ + if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; #define A_LDRH_POST \ u32 addr = cpu->R[(cpu->CurInstr>>16) & 0xF]; \ - cpu->R[(cpu->CurInstr>>16) & 0xF] += offset; \ - cpu->DataRead16(addr, &cpu->R[(cpu->CurInstr>>12) & 0xF]); \ + u32 val; bool dataabort = !cpu->DataRead16(addr, &val); \ cpu->AddCycles_CDI(); \ - if (((cpu->CurInstr>>12) & 0xF) == 15) printf("!! LDRH PC %08X\n", cpu->R[15]); \ + if (dataabort) return; \ + if (((cpu->CurInstr>>12) & 0xF) == 15) cpu->JumpTo8_16Bit(val); \ + else cpu->R[(cpu->CurInstr>>12) & 0xF] = val; \ + cpu->R[(cpu->CurInstr>>16) & 0xF] += offset; #define A_LDRSB \ offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \ - if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; \ - cpu->DataRead8(offset, &cpu->R[(cpu->CurInstr>>12) & 0xF]); \ - cpu->R[(cpu->CurInstr>>12) & 0xF] = (s32)(s8)cpu->R[(cpu->CurInstr>>12) & 0xF]; \ + u32 val; bool dataabort = !cpu->DataRead8(offset, &val); \ cpu->AddCycles_CDI(); \ - if (((cpu->CurInstr>>12) & 0xF) == 15) printf("!! LDRSB PC %08X\n", cpu->R[15]); \ + if (dataabort) return; \ + val = (s32)(s8)val; \ + if (((cpu->CurInstr>>12) & 0xF) == 15) cpu->JumpTo8_16Bit(val); \ + else cpu->R[(cpu->CurInstr>>12) & 0xF] = val; \ + if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; #define A_LDRSB_POST \ u32 addr = cpu->R[(cpu->CurInstr>>16) & 0xF]; \ - cpu->R[(cpu->CurInstr>>16) & 0xF] += offset; \ - cpu->DataRead8(addr, &cpu->R[(cpu->CurInstr>>12) & 0xF]); \ - cpu->R[(cpu->CurInstr>>12) & 0xF] = (s32)(s8)cpu->R[(cpu->CurInstr>>12) & 0xF]; \ + u32 val; bool dataabort = !cpu->DataRead8(addr, &val); \ cpu->AddCycles_CDI(); \ - if (((cpu->CurInstr>>12) & 0xF) == 15) printf("!! LDRSB PC %08X\n", cpu->R[15]); \ + if (dataabort) return; \ + val = (s32)(s8)val; \ + if (((cpu->CurInstr>>12) & 0xF) == 15) cpu->JumpTo8_16Bit(val); \ + else cpu->R[(cpu->CurInstr>>12) & 0xF] = val; \ + cpu->R[(cpu->CurInstr>>16) & 0xF] += offset; #define A_LDRSH \ offset += cpu->R[(cpu->CurInstr>>16) & 0xF]; \ - if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; \ - cpu->DataRead16(offset, &cpu->R[(cpu->CurInstr>>12) & 0xF]); \ - cpu->R[(cpu->CurInstr>>12) & 0xF] = (s32)(s16)cpu->R[(cpu->CurInstr>>12) & 0xF]; \ + u32 val; bool dataabort = !cpu->DataRead16(offset, &val); \ cpu->AddCycles_CDI(); \ - if (((cpu->CurInstr>>12) & 0xF) == 15) printf("!! LDRSH PC %08X\n", cpu->R[15]); \ + if (dataabort) return; \ + val = (s32)(s16)val; \ + if (((cpu->CurInstr>>12) & 0xF) == 15) cpu->JumpTo8_16Bit(val); \ + else cpu->R[(cpu->CurInstr>>12) & 0xF] = val; \ + if (cpu->CurInstr & (1<<21)) cpu->R[(cpu->CurInstr>>16) & 0xF] = offset; #define A_LDRSH_POST \ u32 addr = cpu->R[(cpu->CurInstr>>16) & 0xF]; \ - cpu->R[(cpu->CurInstr>>16) & 0xF] += offset; \ - cpu->DataRead16(addr, &cpu->R[(cpu->CurInstr>>12) & 0xF]); \ - cpu->R[(cpu->CurInstr>>12) & 0xF] = (s32)(s16)cpu->R[(cpu->CurInstr>>12) & 0xF]; \ + u32 val; bool dataabort = !cpu->DataRead16(addr, &val); \ cpu->AddCycles_CDI(); \ - if (((cpu->CurInstr>>12) & 0xF) == 15) printf("!! LDRSH PC %08X\n", cpu->R[15]); \ + if (dataabort) return; \ + val = (s32)(s16)val; \ + if (((cpu->CurInstr>>12) & 0xF) == 15) cpu->JumpTo8_16Bit(val); \ + else cpu->R[(cpu->CurInstr>>12) & 0xF] = val; \ + cpu->R[(cpu->CurInstr>>16) & 0xF] += offset; #define A_IMPLEMENT_HD_LDRSTR(x) \ @@ -362,15 +400,21 @@ void A_SWP(ARM* cpu) { u32 base = cpu->R[(cpu->CurInstr >> 16) & 0xF]; u32 rm = cpu->R[cpu->CurInstr & 0xF]; + if ((cpu->CurInstr & 0xF) == 15) rm += 4; u32 val; - cpu->DataRead32(base, &val); - cpu->R[(cpu->CurInstr >> 12) & 0xF] = ROR(val, 8*(base&0x3)); - - u32 numD = cpu->DataCycles; - cpu->DataWrite32(base, rm); - cpu->DataCycles += numD; - + if (cpu->DataRead32(base, &val)) + { + u32 numD = cpu->DataCycles; + if (cpu->DataWrite32(base, rm)) + { + // rd only gets updated if both read and write succeed + u32 rd = (cpu->CurInstr >> 12) & 0xF; + if (rd != 15) cpu->R[rd] = ROR(val, 8*(base&0x3)); + else if (cpu->Num==1) cpu->JumpTo(ROR(val, 8*(base&0x3)) & ~1); // for some reason these jumps don't work on the arm 9? + } + cpu->DataCycles += numD; + } cpu->AddCycles_CDI(); } @@ -378,13 +422,21 @@ void A_SWPB(ARM* cpu) { u32 base = cpu->R[(cpu->CurInstr >> 16) & 0xF]; u32 rm = cpu->R[cpu->CurInstr & 0xF] & 0xFF; + if ((cpu->CurInstr & 0xF) == 15) rm += 4; - cpu->DataRead8(base, &cpu->R[(cpu->CurInstr >> 12) & 0xF]); - - u32 numD = cpu->DataCycles; - cpu->DataWrite8(base, rm); - cpu->DataCycles += numD; - + u32 val; + if (cpu->DataRead8(base, &val)) + { + u32 numD = cpu->DataCycles; + if (cpu->DataWrite8(base, rm)) + { + // rd only gets updated if both read and write succeed + u32 rd = (cpu->CurInstr >> 12) & 0xF; + if (rd != 15) cpu->R[rd] = val; + else if (cpu->Num==1) cpu->JumpTo(val & ~1); // for some reason these jumps don't work on the arm 9? + } + cpu->DataCycles += numD; + } cpu->AddCycles_CDI(); } @@ -395,11 +447,13 @@ void A_LDM(ARM* cpu) u32 baseid = (cpu->CurInstr >> 16) & 0xF; u32 base = cpu->R[baseid]; u32 wbbase; + u32 oldbase = base; u32 preinc = (cpu->CurInstr & (1<<24)); bool first = true; - if (!(cpu->CurInstr & (1<<23))) + if (!(cpu->CurInstr & (1<<23))) // decrement { + // decrement is actually an increment starting from the end address for (int i = 0; i < 16; i++) { if (cpu->CurInstr & (1<<i)) @@ -415,6 +469,7 @@ void A_LDM(ARM* cpu) preinc = !preinc; } + // switch to user mode regs if ((cpu->CurInstr & (1<<22)) && !(cpu->CurInstr & (1<<15))) cpu->UpdateMode(cpu->CPSR, (cpu->CPSR&~0x1F)|0x10, true); @@ -423,30 +478,38 @@ void A_LDM(ARM* cpu) if (cpu->CurInstr & (1<<i)) { if (preinc) base += 4; - if (first) cpu->DataRead32 (base, &cpu->R[i]); - else cpu->DataRead32S(base, &cpu->R[i]); + if (!(first ? cpu->DataRead32 (base, &cpu->R[i]) + : cpu->DataRead32S(base, &cpu->R[i]))) + { + goto dataabort; + } + first = false; if (!preinc) base += 4; } } - if (cpu->CurInstr & (1<<15)) + u32 pc; + if ((cpu->CurInstr & (1<<15))) { - u32 pc; if (preinc) base += 4; - if (first) cpu->DataRead32 (base, &pc); - else cpu->DataRead32S(base, &pc); + if (!(first ? cpu->DataRead32 (base, &pc) + : cpu->DataRead32S(base, &pc))) + { + goto dataabort; + } + if (!preinc) base += 4; - if (cpu->Num == 1) + if (cpu->Num == 1 || (((ARMv5*)cpu)->CP15Control & (1<<15))) pc &= ~0x1; - - cpu->JumpTo(pc, cpu->CurInstr & (1<<22)); } + // switch back to previous regs if ((cpu->CurInstr & (1<<22)) && !(cpu->CurInstr & (1<<15))) cpu->UpdateMode((cpu->CPSR&~0x1F)|0x10, cpu->CPSR, true); + // writeback to base if (cpu->CurInstr & (1<<21)) { // post writeback @@ -465,6 +528,23 @@ void A_LDM(ARM* cpu) else cpu->R[baseid] = wbbase; } + + // jump if pc got written + if (cpu->CurInstr & (1<<15)) + cpu->JumpTo(pc, cpu->CurInstr & (1<<22)); + + // jump here if a data abort occurred; writeback is ignored, and any jumps were aborted + if (false) + { + dataabort: + + // switch back to original set of regs + if ((cpu->CurInstr & (1<<22)) && !(cpu->CurInstr & (1<<15))) + cpu->UpdateMode((cpu->CPSR&~0x1F)|0x10, cpu->CPSR, true); + + // restore original value of base in case the reg got written to + cpu->R[baseid] = oldbase; + } cpu->AddCycles_CDI(); } @@ -509,15 +589,22 @@ void A_STM(ARM* cpu) { if (preinc) base += 4; + u32 val; if (i == baseid && !isbanked) { if ((cpu->Num == 0) || (!(cpu->CurInstr & ((1<<i)-1)))) - first ? cpu->DataWrite32(base, oldbase) : cpu->DataWrite32S(base, oldbase); - else - first ? cpu->DataWrite32(base, base) : cpu->DataWrite32S(base, base); // checkme + val = oldbase; + else val = base; + } + else val = cpu->R[i]; + + if (i == 15) val+=4; + + if (!(first ? cpu->DataWrite32 (base, val) + : cpu->DataWrite32S(base, val))) + { + goto dataabort; } - else - first ? cpu->DataWrite32(base, cpu->R[i]) : cpu->DataWrite32S(base, cpu->R[i]); first = false; @@ -531,6 +618,18 @@ void A_STM(ARM* cpu) if ((cpu->CurInstr & (1<<23)) && (cpu->CurInstr & (1<<21))) cpu->R[baseid] = base; + // jump here if a data abort occurred + if (false) + { + dataabort: + + if (cpu->CurInstr & (1<<22)) + cpu->UpdateMode((cpu->CPSR&~0x1F)|0x10, cpu->CPSR, true); + + // restore original value of base + cpu->R[baseid] = oldbase; + } + cpu->AddCycles_CD(); } @@ -571,8 +670,8 @@ void T_LDR_REG(ARM* cpu) u32 addr = cpu->R[(cpu->CurInstr >> 3) & 0x7] + cpu->R[(cpu->CurInstr >> 6) & 0x7]; u32 val; - cpu->DataRead32(addr, &val); - cpu->R[cpu->CurInstr & 0x7] = ROR(val, 8*(addr&0x3)); + if (cpu->DataRead32(addr, &val)) + cpu->R[cpu->CurInstr & 0x7] = ROR(val, 8*(addr&0x3)); cpu->AddCycles_CDI(); } @@ -597,8 +696,8 @@ void T_STRH_REG(ARM* cpu) void T_LDRSB_REG(ARM* cpu) { u32 addr = cpu->R[(cpu->CurInstr >> 3) & 0x7] + cpu->R[(cpu->CurInstr >> 6) & 0x7]; - cpu->DataRead8(addr, &cpu->R[cpu->CurInstr & 0x7]); - cpu->R[cpu->CurInstr & 0x7] = (s32)(s8)cpu->R[cpu->CurInstr & 0x7]; + if (cpu->DataRead8(addr, &cpu->R[cpu->CurInstr & 0x7])) + cpu->R[cpu->CurInstr & 0x7] = (s32)(s8)cpu->R[cpu->CurInstr & 0x7]; cpu->AddCycles_CDI(); } @@ -614,8 +713,8 @@ void T_LDRH_REG(ARM* cpu) void T_LDRSH_REG(ARM* cpu) { u32 addr = cpu->R[(cpu->CurInstr >> 3) & 0x7] + cpu->R[(cpu->CurInstr >> 6) & 0x7]; - cpu->DataRead16(addr, &cpu->R[cpu->CurInstr & 0x7]); - cpu->R[cpu->CurInstr & 0x7] = (s32)(s16)cpu->R[cpu->CurInstr & 0x7]; + if (cpu->DataRead16(addr, &cpu->R[cpu->CurInstr & 0x7])) + cpu->R[cpu->CurInstr & 0x7] = (s32)(s16)cpu->R[cpu->CurInstr & 0x7]; cpu->AddCycles_CDI(); } @@ -636,8 +735,8 @@ void T_LDR_IMM(ARM* cpu) offset += cpu->R[(cpu->CurInstr >> 3) & 0x7]; u32 val; - cpu->DataRead32(offset, &val); - cpu->R[cpu->CurInstr & 0x7] = ROR(val, 8*(offset&0x3)); + if (cpu->DataRead32(offset, &val)) + cpu->R[cpu->CurInstr & 0x7] = ROR(val, 8*(offset&0x3)); cpu->AddCycles_CDI(); } @@ -714,14 +813,17 @@ void T_PUSH(ARM* cpu) u32 base = cpu->R[13]; base -= (nregs<<2); - cpu->R[13] = base; + u32 wbbase = base; for (int i = 0; i < 8; i++) { if (cpu->CurInstr & (1<<i)) { - if (first) cpu->DataWrite32 (base, cpu->R[i]); - else cpu->DataWrite32S(base, cpu->R[i]); + if (!(first ? cpu->DataWrite32 (base, cpu->R[i]) + : cpu->DataWrite32S(base, cpu->R[i]))) + { + goto dataabort; + } first = false; base += 4; } @@ -729,10 +831,16 @@ void T_PUSH(ARM* cpu) if (cpu->CurInstr & (1<<8)) { - if (first) cpu->DataWrite32 (base, cpu->R[14]); - else cpu->DataWrite32S(base, cpu->R[14]); + if (!(first ? cpu->DataWrite32 (base, cpu->R[14]) + : cpu->DataWrite32S(base, cpu->R[14]))) + { + goto dataabort; + } } + cpu->R[13] = wbbase; + + dataabort: cpu->AddCycles_CD(); } @@ -745,8 +853,11 @@ void T_POP(ARM* cpu) { if (cpu->CurInstr & (1<<i)) { - if (first) cpu->DataRead32 (base, &cpu->R[i]); - else cpu->DataRead32S(base, &cpu->R[i]); + if (!(first ? cpu->DataRead32 (base, &cpu->R[i]) + : cpu->DataRead32S(base, &cpu->R[i]))) + { + goto dataabort; + } first = false; base += 4; } @@ -755,14 +866,19 @@ void T_POP(ARM* cpu) if (cpu->CurInstr & (1<<8)) { u32 pc; - if (first) cpu->DataRead32 (base, &pc); - else cpu->DataRead32S(base, &pc); - if (cpu->Num==1) pc |= 0x1; + if (!(first ? cpu->DataRead32 (base, &pc) + : cpu->DataRead32S(base, &pc))) + { + goto dataabort; + } + if (cpu->Num==1 || (((ARMv5*)cpu)->CP15Control & (1<<15))) pc |= 0x1; cpu->JumpTo(pc); base += 4; } cpu->R[13] = base; + + dataabort: cpu->AddCycles_CDI(); } @@ -775,8 +891,11 @@ void T_STMIA(ARM* cpu) { if (cpu->CurInstr & (1<<i)) { - if (first) cpu->DataWrite32 (base, cpu->R[i]); - else cpu->DataWrite32S(base, cpu->R[i]); + if (!(first ? cpu->DataWrite32 (base, cpu->R[i]) + : cpu->DataWrite32S(base, cpu->R[i]))) + { + goto dataabort; + } first = false; base += 4; } @@ -784,6 +903,7 @@ void T_STMIA(ARM* cpu) // TODO: check "Rb included in Rlist" case cpu->R[(cpu->CurInstr >> 8) & 0x7] = base; + dataabort: cpu->AddCycles_CD(); } @@ -796,8 +916,11 @@ void T_LDMIA(ARM* cpu) { if (cpu->CurInstr & (1<<i)) { - if (first) cpu->DataRead32 (base, &cpu->R[i]); - else cpu->DataRead32S(base, &cpu->R[i]); + if (!(first ? cpu->DataRead32 (base, &cpu->R[i]) + : cpu->DataRead32S(base, &cpu->R[i]))) + { + goto dataabort; + } first = false; base += 4; } @@ -806,6 +929,7 @@ void T_LDMIA(ARM* cpu) if (!(cpu->CurInstr & (1<<((cpu->CurInstr >> 8) & 0x7)))) cpu->R[(cpu->CurInstr >> 8) & 0x7] = base; + dataabort: cpu->AddCycles_CDI(); } diff --git a/src/CP15.cpp b/src/CP15.cpp index c271e180..6fcaff93 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -266,8 +266,6 @@ void ARMv5::UpdatePURegions(bool update_all) // PU disabled u8 mask = 0x07; - if (CP15Control & (1<<2)) mask |= 0x30; - if (CP15Control & (1<<12)) mask |= 0x40; memset(PU_UserMap, mask, 0x100000); memset(PU_PrivMap, mask, 0x100000); @@ -579,7 +577,7 @@ void ARMv5::CP15Write(u32 id, u32 val) case 0x670: case 0x671: char log_output[1024]; - PU_Region[(id >> 4) & 0xF] = val; + PU_Region[(id >> 4) & 0xF] = val & ~(0x3F<<6); std::snprintf(log_output, sizeof(log_output), @@ -775,14 +773,13 @@ u32 ARMv5::CP15Read(u32 id) const u32 ARMv5::CodeRead32(u32 addr, bool branch) { - /*if (branch || (!(addr & 0xFFF))) + // prefetch abort + // the actual exception is not raised until the aborted instruction is executed + if (!(PU_Map[addr>>12] & 0x04)) [[unlikely]] { - if (!(PU_Map[addr>>12] & 0x04)) - { - PrefetchAbort(); - return 0; - } - }*/ + CodeCycles = 1; + return 0; + } if (addr < ITCMSize) { @@ -807,150 +804,151 @@ u32 ARMv5::CodeRead32(u32 addr, bool branch) } -void ARMv5::DataRead8(u32 addr, u32* val) +bool ARMv5::DataRead8(u32 addr, u32* val) { - if (!(PU_Map[addr>>12] & 0x01)) + if (!(PU_Map[addr>>12] & 0x01)) [[unlikely]] { DataAbort(); - return; + return false; } - DataRegion = addr; - if (addr < ITCMSize) { DataCycles = 1; *val = *(u8*)&ITCM[addr & (ITCMPhysicalSize - 1)]; - return; + return true; } if ((addr & DTCMMask) == DTCMBase) { DataCycles = 1; *val = *(u8*)&DTCM[addr & (DTCMPhysicalSize - 1)]; - return; + return true; } - + *val = BusRead8(addr); DataCycles = MemTimings[addr >> 12][1]; + return true; } -void ARMv5::DataRead16(u32 addr, u32* val) +bool ARMv5::DataRead16(u32 addr, u32* val) { - if (!(PU_Map[addr>>12] & 0x01)) + if (!(PU_Map[addr>>12] & 0x01)) [[unlikely]] { DataAbort(); - return; + return false; } - DataRegion = addr; - addr &= ~1; if (addr < ITCMSize) { DataCycles = 1; *val = *(u16*)&ITCM[addr & (ITCMPhysicalSize - 1)]; - return; + return true; } if ((addr & DTCMMask) == DTCMBase) { DataCycles = 1; *val = *(u16*)&DTCM[addr & (DTCMPhysicalSize - 1)]; - return; + return true; } - + *val = BusRead16(addr); DataCycles = MemTimings[addr >> 12][1]; + return true; } -void ARMv5::DataRead32(u32 addr, u32* val) +bool ARMv5::DataRead32(u32 addr, u32* val) { - if (!(PU_Map[addr>>12] & 0x01)) + if (!(PU_Map[addr>>12] & 0x01)) [[unlikely]] { DataAbort(); - return; + return false; } - DataRegion = addr; - addr &= ~3; if (addr < ITCMSize) { DataCycles = 1; *val = *(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)]; - return; + return true; } if ((addr & DTCMMask) == DTCMBase) { DataCycles = 1; *val = *(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)]; - return; + return true; } *val = BusRead32(addr); DataCycles = MemTimings[addr >> 12][2]; + return true; } -void ARMv5::DataRead32S(u32 addr, u32* val) +bool ARMv5::DataRead32S(u32 addr, u32* val) { + if (!(PU_Map[addr>>12] & 0x01)) [[unlikely]] + { + DataAbort(); + return false; + } + addr &= ~3; if (addr < ITCMSize) { DataCycles += 1; *val = *(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)]; - return; + return true; } if ((addr & DTCMMask) == DTCMBase) { DataCycles += 1; *val = *(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)]; - return; + return true; } *val = BusRead32(addr); DataCycles += MemTimings[addr >> 12][3]; + return true; } -void ARMv5::DataWrite8(u32 addr, u8 val) +bool ARMv5::DataWrite8(u32 addr, u8 val) { - if (!(PU_Map[addr>>12] & 0x02)) + if (!(PU_Map[addr>>12] & 0x02)) [[unlikely]] { DataAbort(); - return; + return false; } - DataRegion = addr; - if (addr < ITCMSize) { DataCycles = 1; *(u8*)&ITCM[addr & (ITCMPhysicalSize - 1)] = val; NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr); - return; + return true; } if ((addr & DTCMMask) == DTCMBase) { DataCycles = 1; *(u8*)&DTCM[addr & (DTCMPhysicalSize - 1)] = val; - return; + return true; } BusWrite8(addr, val); DataCycles = MemTimings[addr >> 12][1]; + return true; } -void ARMv5::DataWrite16(u32 addr, u16 val) +bool ARMv5::DataWrite16(u32 addr, u16 val) { - if (!(PU_Map[addr>>12] & 0x02)) + if (!(PU_Map[addr>>12] & 0x02)) [[unlikely]] { DataAbort(); - return; + return false; } - DataRegion = addr; - addr &= ~1; if (addr < ITCMSize) @@ -958,29 +956,28 @@ void ARMv5::DataWrite16(u32 addr, u16 val) DataCycles = 1; *(u16*)&ITCM[addr & (ITCMPhysicalSize - 1)] = val; NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr); - return; + return true; } if ((addr & DTCMMask) == DTCMBase) { DataCycles = 1; *(u16*)&DTCM[addr & (DTCMPhysicalSize - 1)] = val; - return; + return true; } BusWrite16(addr, val); DataCycles = MemTimings[addr >> 12][1]; + return true; } -void ARMv5::DataWrite32(u32 addr, u32 val) +bool ARMv5::DataWrite32(u32 addr, u32 val) { - if (!(PU_Map[addr>>12] & 0x02)) + if (!(PU_Map[addr>>12] & 0x02)) [[unlikely]] { DataAbort(); - return; + return false; } - DataRegion = addr; - addr &= ~3; if (addr < ITCMSize) @@ -988,21 +985,28 @@ void ARMv5::DataWrite32(u32 addr, u32 val) DataCycles = 1; *(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)] = val; NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr); - return; + return true; } if ((addr & DTCMMask) == DTCMBase) { DataCycles = 1; *(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)] = val; - return; + return true; } BusWrite32(addr, val); DataCycles = MemTimings[addr >> 12][2]; + return true; } -void ARMv5::DataWrite32S(u32 addr, u32 val) +bool ARMv5::DataWrite32S(u32 addr, u32 val, bool dataabort) { + if (!(PU_Map[addr>>12] & 0x02)) [[unlikely]] + { + if (!dataabort) DataAbort(); + return false; + } + addr &= ~3; if (addr < ITCMSize) @@ -1012,17 +1016,18 @@ void ARMv5::DataWrite32S(u32 addr, u32 val) #ifdef JIT_ENABLED NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr); #endif - return; + return true; } if ((addr & DTCMMask) == DTCMBase) { DataCycles += 1; *(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)] = val; - return; + return true; } BusWrite32(addr, val); DataCycles += MemTimings[addr >> 12][3]; + return true; } void ARMv5::GetCodeMemRegion(u32 addr, MemRegion* region) diff --git a/src/DSi.cpp b/src/DSi.cpp index 00ed8da0..0a0bd36d 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -162,6 +162,7 @@ void DSi::Reset() SCFG_Clock9 = 0x0187; // CHECKME SCFG_Clock7 = 0x0187; SCFG_EXT[0] = 0x8307F100; + SetVRAMTimings(true); SCFG_EXT[1] = 0x93FFFB06; SCFG_MC = 0x0010 | (~((u32)(NDSCartSlot.GetCart() != nullptr))&1);//0x0011; SCFG_RST = 0; @@ -235,6 +236,7 @@ void DSi::DoSavestateExtra(Savestate* file) Set_SCFG_Clock9(SCFG_Clock9); Set_SCFG_MC(SCFG_MC); DSP.SetRstLine(SCFG_RST & 0x0001); + SetVRAMTimings(SCFG_EXT[0] & (1<<13)); MBK[0][8] = 0; MBK[1][8] = 0; @@ -713,6 +715,7 @@ void DSi::SoftReset() SCFG_Clock9 = 0x0187; // CHECKME SCFG_Clock7 = 0x0187; SCFG_EXT[0] = 0x8307F100; + SetVRAMTimings(true); SCFG_EXT[1] = 0x93FFFB06; SCFG_MC = 0x0010;//0x0011; // TODO: is this actually reset? @@ -1303,6 +1306,14 @@ void DSi::Set_SCFG_MC(u32 val) } } +void DSi::SetVRAMTimings(bool extrabuswidth) +{ + if (extrabuswidth) + SetARM9RegionTimings(0x06000, 0x07000, Mem9_VRAM, 32, 1, 1); // dsi vram + else + SetARM9RegionTimings(0x06000, 0x07000, Mem9_VRAM, 16, 1, 1); // ds vram +} + u8 DSi::ARM9Read8(u32 addr) { @@ -2541,11 +2552,18 @@ void DSi::ARM9IOWrite32(u32 addr, u32 val) u32 oldram = (SCFG_EXT[0] >> 14) & 0x3; u32 newram = (val >> 14) & 0x3; + u32 oldvram = (SCFG_EXT[0] & (1<<13)); + u32 newvram = (val & (1<<13)); + SCFG_EXT[0] &= ~0x8007F19F; SCFG_EXT[0] |= (val & 0x8007F19F); SCFG_EXT[1] &= ~0x0000F080; SCFG_EXT[1] |= (val & 0x0000F080); Log(LogLevel::Debug, "SCFG_EXT = %08X / %08X (val9 %08X)\n", SCFG_EXT[0], SCFG_EXT[1], val); + + if (oldvram != newvram) + SetVRAMTimings(newvram); + /*switch ((SCFG_EXT[0] >> 14) & 0x3) { case 0: diff --git a/src/DSi.h b/src/DSi.h index 23a2460c..7b7a94a2 100644 --- a/src/DSi.h +++ b/src/DSi.h @@ -96,6 +96,7 @@ public: void MapNWRAM_B(u32 num, u8 val); void MapNWRAM_C(u32 num, u8 val); void MapNWRAMRange(u32 cpu, u32 num, u32 val); + void SetVRAMTimings(bool extrabuswidth); u8 ARM9Read8(u32 addr) override; u16 ARM9Read16(u32 addr) override;
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor