mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2024-11-14 05:17:40 -07:00
Merge 9d92b8708a
into 7c1d2a64f4
This commit is contained in:
commit
30d1bbec94
125
src/ARM.cpp
125
src/ARM.cpp
@ -222,7 +222,7 @@ void ARM::DoSavestate(Savestate* file)
|
|||||||
file->VarArray(R_ABT, 3*sizeof(u32));
|
file->VarArray(R_ABT, 3*sizeof(u32));
|
||||||
file->VarArray(R_IRQ, 3*sizeof(u32));
|
file->VarArray(R_IRQ, 3*sizeof(u32));
|
||||||
file->VarArray(R_UND, 3*sizeof(u32));
|
file->VarArray(R_UND, 3*sizeof(u32));
|
||||||
file->Var32(&CurInstr);
|
file->Var64(&CurInstr);
|
||||||
#ifdef JIT_ENABLED
|
#ifdef JIT_ENABLED
|
||||||
if (file->Saving && NDS.IsJITEnabled())
|
if (file->Saving && NDS.IsJITEnabled())
|
||||||
{
|
{
|
||||||
@ -232,7 +232,7 @@ void ARM::DoSavestate(Savestate* file)
|
|||||||
FillPipeline();
|
FillPipeline();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
file->VarArray(NextInstr, 2*sizeof(u32));
|
file->VarArray(NextInstr, 2*sizeof(u64));
|
||||||
|
|
||||||
file->Var32(&ExceptionBase);
|
file->Var32(&ExceptionBase);
|
||||||
|
|
||||||
@ -344,12 +344,6 @@ void ARMv5::JumpTo(u32 addr, bool restorecpsr)
|
|||||||
CPSR &= ~0x20;
|
CPSR &= ~0x20;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(PU_Map[addr>>12] & 0x04))
|
|
||||||
{
|
|
||||||
PrefetchAbort();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NDS.MonitorARM9Jump(addr);
|
NDS.MonitorARM9Jump(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -518,6 +512,7 @@ void ARM::UpdateMode(u32 oldmode, u32 newmode, bool phony)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <CPUExecuteMode mode>
|
||||||
void ARM::TriggerIRQ()
|
void ARM::TriggerIRQ()
|
||||||
{
|
{
|
||||||
if (CPSR & 0x80)
|
if (CPSR & 0x80)
|
||||||
@ -529,7 +524,12 @@ void ARM::TriggerIRQ()
|
|||||||
UpdateMode(oldcpsr, CPSR);
|
UpdateMode(oldcpsr, CPSR);
|
||||||
|
|
||||||
R_IRQ[2] = oldcpsr;
|
R_IRQ[2] = oldcpsr;
|
||||||
R[14] = R[15] + (oldcpsr & 0x20 ? 2 : 0);
|
#ifdef JIT_ENABLED
|
||||||
|
if constexpr (mode == CPUExecuteMode::JIT)
|
||||||
|
R[14] = R[15] + (oldcpsr & 0x20 ? 2 : 0);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
R[14] = R[15] - (oldcpsr & 0x20 ? 0 : 4);
|
||||||
JumpTo(ExceptionBase + 0x18);
|
JumpTo(ExceptionBase + 0x18);
|
||||||
|
|
||||||
// ARDS cheat support
|
// ARDS cheat support
|
||||||
@ -540,6 +540,11 @@ void ARM::TriggerIRQ()
|
|||||||
NDS.AREngine.RunCheats();
|
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()
|
void ARMv5::PrefetchAbort()
|
||||||
{
|
{
|
||||||
@ -550,17 +555,8 @@ void ARMv5::PrefetchAbort()
|
|||||||
CPSR |= 0x97;
|
CPSR |= 0x97;
|
||||||
UpdateMode(oldcpsr, CPSR);
|
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_ABT[2] = oldcpsr;
|
||||||
R[14] = R[15] + (oldcpsr & 0x20 ? 2 : 0);
|
R[14] = R[15] - (oldcpsr & 0x20 ? 0 : 4);
|
||||||
JumpTo(ExceptionBase + 0x0C);
|
JumpTo(ExceptionBase + 0x0C);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -599,7 +595,13 @@ void ARMv5::Execute()
|
|||||||
{
|
{
|
||||||
Halted = 0;
|
Halted = 0;
|
||||||
if (NDS.IME[0] & 0x1)
|
if (NDS.IME[0] & 0x1)
|
||||||
TriggerIRQ();
|
{
|
||||||
|
#ifdef JIT_ENABLED
|
||||||
|
if constexpr (mode == CPUExecuteMode::JIT) TriggerIRQ<mode>();
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
IRQ = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -634,7 +636,7 @@ void ARMv5::Execute()
|
|||||||
{
|
{
|
||||||
// this order is crucial otherwise idle loops waiting for an IRQ won't function
|
// this order is crucial otherwise idle loops waiting for an IRQ won't function
|
||||||
if (IRQ)
|
if (IRQ)
|
||||||
TriggerIRQ();
|
TriggerIRQ<mode>();
|
||||||
|
|
||||||
if (Halted || IdleLoop)
|
if (Halted || IdleLoop)
|
||||||
{
|
{
|
||||||
@ -662,10 +664,18 @@ void ARMv5::Execute()
|
|||||||
NextInstr[0] = NextInstr[1];
|
NextInstr[0] = NextInstr[1];
|
||||||
if (R[15] & 0x2) { NextInstr[1] >>= 16; CodeCycles = 0; }
|
if (R[15] & 0x2) { NextInstr[1] >>= 16; CodeCycles = 0; }
|
||||||
else NextInstr[1] = CodeRead32(R[15], false);
|
else NextInstr[1] = CodeRead32(R[15], false);
|
||||||
|
|
||||||
// actually execute
|
|
||||||
u32 icode = (CurInstr >> 6) & 0x3FF;
|
if (IRQ && !(CPSR & 0x80)) TriggerIRQ<mode>();
|
||||||
ARMInterpreter::THUMBInstrTable[icode](this);
|
else if (CurInstr > 0xFFFFFFFF) [[unlikely]] // handle aborted instructions
|
||||||
|
{
|
||||||
|
PrefetchAbort();
|
||||||
|
}
|
||||||
|
else [[likely]] // actually execute
|
||||||
|
{
|
||||||
|
u32 icode = (CurInstr >> 6) & 0x3FF;
|
||||||
|
ARMInterpreter::THUMBInstrTable[icode](this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -677,9 +687,14 @@ void ARMv5::Execute()
|
|||||||
CurInstr = NextInstr[0];
|
CurInstr = NextInstr[0];
|
||||||
NextInstr[0] = NextInstr[1];
|
NextInstr[0] = NextInstr[1];
|
||||||
NextInstr[1] = CodeRead32(R[15], false);
|
NextInstr[1] = CodeRead32(R[15], false);
|
||||||
|
|
||||||
|
|
||||||
// actually execute
|
if (IRQ && !(CPSR & 0x80)) TriggerIRQ<mode>();
|
||||||
if (CheckCondition(CurInstr >> 28))
|
else if (CurInstr & ((u64)1<<63)) [[unlikely]] // handle aborted instructions
|
||||||
|
{
|
||||||
|
PrefetchAbort();
|
||||||
|
}
|
||||||
|
else if (CheckCondition(CurInstr >> 28)) [[likely]] // actually execute
|
||||||
{
|
{
|
||||||
u32 icode = ((CurInstr >> 4) & 0xF) | ((CurInstr >> 16) & 0xFF0);
|
u32 icode = ((CurInstr >> 4) & 0xF) | ((CurInstr >> 16) & 0xFF0);
|
||||||
ARMInterpreter::ARMInstrTable[icode](this);
|
ARMInterpreter::ARMInstrTable[icode](this);
|
||||||
@ -688,6 +703,10 @@ void ARMv5::Execute()
|
|||||||
{
|
{
|
||||||
ARMInterpreter::A_BLX_IMM(this);
|
ARMInterpreter::A_BLX_IMM(this);
|
||||||
}
|
}
|
||||||
|
else if ((CurInstr & 0x0FF000F0) == 0x01200070)
|
||||||
|
{
|
||||||
|
ARMInterpreter::A_BKPT(this); // always passes regardless of condition code
|
||||||
|
}
|
||||||
else
|
else
|
||||||
AddCycles_C();
|
AddCycles_C();
|
||||||
}
|
}
|
||||||
@ -704,10 +723,8 @@ void ARMv5::Execute()
|
|||||||
/*if (NDS::IF[0] & NDS::IE[0])
|
/*if (NDS::IF[0] & NDS::IE[0])
|
||||||
{
|
{
|
||||||
if (NDS::IME[0] & 0x1)
|
if (NDS::IME[0] & 0x1)
|
||||||
TriggerIRQ();
|
TriggerIRQ<mode>();
|
||||||
}*/
|
}*/
|
||||||
if (IRQ) TriggerIRQ();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NDS.ARM9Timestamp += Cycles;
|
NDS.ARM9Timestamp += Cycles;
|
||||||
@ -739,7 +756,10 @@ void ARMv4::Execute()
|
|||||||
{
|
{
|
||||||
Halted = 0;
|
Halted = 0;
|
||||||
if (NDS.IME[1] & 0x1)
|
if (NDS.IME[1] & 0x1)
|
||||||
TriggerIRQ();
|
{
|
||||||
|
if constexpr (mode == CPUExecuteMode::JIT) TriggerIRQ<mode>();
|
||||||
|
else IRQ = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -773,7 +793,7 @@ void ARMv4::Execute()
|
|||||||
if (StopExecution)
|
if (StopExecution)
|
||||||
{
|
{
|
||||||
if (IRQ)
|
if (IRQ)
|
||||||
TriggerIRQ();
|
TriggerIRQ<mode>();
|
||||||
|
|
||||||
if (Halted || IdleLoop)
|
if (Halted || IdleLoop)
|
||||||
{
|
{
|
||||||
@ -801,9 +821,13 @@ void ARMv4::Execute()
|
|||||||
NextInstr[0] = NextInstr[1];
|
NextInstr[0] = NextInstr[1];
|
||||||
NextInstr[1] = CodeRead16(R[15]);
|
NextInstr[1] = CodeRead16(R[15]);
|
||||||
|
|
||||||
// actually execute
|
if (IRQ && !(CPSR & 0x80)) TriggerIRQ<mode>();
|
||||||
u32 icode = (CurInstr >> 6);
|
else
|
||||||
ARMInterpreter::THUMBInstrTable[icode](this);
|
{
|
||||||
|
// actually execute
|
||||||
|
u32 icode = (CurInstr >> 6);
|
||||||
|
ARMInterpreter::THUMBInstrTable[icode](this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -816,8 +840,8 @@ void ARMv4::Execute()
|
|||||||
NextInstr[0] = NextInstr[1];
|
NextInstr[0] = NextInstr[1];
|
||||||
NextInstr[1] = CodeRead32(R[15]);
|
NextInstr[1] = CodeRead32(R[15]);
|
||||||
|
|
||||||
// actually execute
|
if (IRQ && !(CPSR & 0x80)) TriggerIRQ<mode>();
|
||||||
if (CheckCondition(CurInstr >> 28))
|
else if (CheckCondition(CurInstr >> 28)) // actually execute
|
||||||
{
|
{
|
||||||
u32 icode = ((CurInstr >> 4) & 0xF) | ((CurInstr >> 16) & 0xFF0);
|
u32 icode = ((CurInstr >> 4) & 0xF) | ((CurInstr >> 16) & 0xFF0);
|
||||||
ARMInterpreter::ARMInstrTable[icode](this);
|
ARMInterpreter::ARMInstrTable[icode](this);
|
||||||
@ -838,9 +862,8 @@ void ARMv4::Execute()
|
|||||||
/*if (NDS::IF[1] & NDS::IE[1])
|
/*if (NDS::IF[1] & NDS::IE[1])
|
||||||
{
|
{
|
||||||
if (NDS::IME[1] & 0x1)
|
if (NDS::IME[1] & 0x1)
|
||||||
TriggerIRQ();
|
TriggerIRQ<mode>();
|
||||||
}*/
|
}*/
|
||||||
if (IRQ) TriggerIRQ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NDS.ARM7Timestamp += Cycles;
|
NDS.ARM7Timestamp += Cycles;
|
||||||
@ -1113,70 +1136,78 @@ u32 ARMv5::ReadMem(u32 addr, int size)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void ARMv4::DataRead8(u32 addr, u32* val)
|
bool ARMv4::DataRead8(u32 addr, u32* val)
|
||||||
{
|
{
|
||||||
*val = BusRead8(addr);
|
*val = BusRead8(addr);
|
||||||
DataRegion = addr;
|
DataRegion = addr;
|
||||||
DataCycles = NDS.ARM7MemTimings[addr >> 15][0];
|
DataCycles = NDS.ARM7MemTimings[addr >> 15][0];
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARMv4::DataRead16(u32 addr, u32* val)
|
bool ARMv4::DataRead16(u32 addr, u32* val)
|
||||||
{
|
{
|
||||||
addr &= ~1;
|
addr &= ~1;
|
||||||
|
|
||||||
*val = BusRead16(addr);
|
*val = BusRead16(addr);
|
||||||
DataRegion = addr;
|
DataRegion = addr;
|
||||||
DataCycles = NDS.ARM7MemTimings[addr >> 15][0];
|
DataCycles = NDS.ARM7MemTimings[addr >> 15][0];
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARMv4::DataRead32(u32 addr, u32* val)
|
bool ARMv4::DataRead32(u32 addr, u32* val)
|
||||||
{
|
{
|
||||||
addr &= ~3;
|
addr &= ~3;
|
||||||
|
|
||||||
*val = BusRead32(addr);
|
*val = BusRead32(addr);
|
||||||
DataRegion = addr;
|
DataRegion = addr;
|
||||||
DataCycles = NDS.ARM7MemTimings[addr >> 15][2];
|
DataCycles = NDS.ARM7MemTimings[addr >> 15][2];
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARMv4::DataRead32S(u32 addr, u32* val)
|
bool ARMv4::DataRead32S(u32 addr, u32* val)
|
||||||
{
|
{
|
||||||
addr &= ~3;
|
addr &= ~3;
|
||||||
|
|
||||||
*val = BusRead32(addr);
|
*val = BusRead32(addr);
|
||||||
DataCycles += NDS.ARM7MemTimings[addr >> 15][3];
|
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);
|
BusWrite8(addr, val);
|
||||||
DataRegion = addr;
|
DataRegion = addr;
|
||||||
DataCycles = NDS.ARM7MemTimings[addr >> 15][0];
|
DataCycles = NDS.ARM7MemTimings[addr >> 15][0];
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARMv4::DataWrite16(u32 addr, u16 val)
|
bool ARMv4::DataWrite16(u32 addr, u16 val)
|
||||||
{
|
{
|
||||||
addr &= ~1;
|
addr &= ~1;
|
||||||
|
|
||||||
BusWrite16(addr, val);
|
BusWrite16(addr, val);
|
||||||
DataRegion = addr;
|
DataRegion = addr;
|
||||||
DataCycles = NDS.ARM7MemTimings[addr >> 15][0];
|
DataCycles = NDS.ARM7MemTimings[addr >> 15][0];
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARMv4::DataWrite32(u32 addr, u32 val)
|
bool ARMv4::DataWrite32(u32 addr, u32 val)
|
||||||
{
|
{
|
||||||
addr &= ~3;
|
addr &= ~3;
|
||||||
|
|
||||||
BusWrite32(addr, val);
|
BusWrite32(addr, val);
|
||||||
DataRegion = addr;
|
DataRegion = addr;
|
||||||
DataCycles = NDS.ARM7MemTimings[addr >> 15][2];
|
DataCycles = NDS.ARM7MemTimings[addr >> 15][2];
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARMv4::DataWrite32S(u32 addr, u32 val)
|
bool ARMv4::DataWrite32S(u32 addr, u32 val)
|
||||||
{
|
{
|
||||||
addr &= ~3;
|
addr &= ~3;
|
||||||
|
|
||||||
BusWrite32(addr, val);
|
BusWrite32(addr, val);
|
||||||
DataCycles += NDS.ARM7MemTimings[addr >> 15][3];
|
DataCycles += NDS.ARM7MemTimings[addr >> 15][3];
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
56
src/ARM.h
56
src/ARM.h
@ -128,19 +128,20 @@ public:
|
|||||||
|
|
||||||
void UpdateMode(u32 oldmode, u32 newmode, bool phony = false);
|
void UpdateMode(u32 oldmode, u32 newmode, bool phony = false);
|
||||||
|
|
||||||
|
template <CPUExecuteMode mode>
|
||||||
void TriggerIRQ();
|
void TriggerIRQ();
|
||||||
|
|
||||||
void SetupCodeMem(u32 addr);
|
void SetupCodeMem(u32 addr);
|
||||||
|
|
||||||
|
|
||||||
virtual void DataRead8(u32 addr, u32* val) = 0;
|
virtual bool DataRead8(u32 addr, u32* val) = 0;
|
||||||
virtual void DataRead16(u32 addr, u32* val) = 0;
|
virtual bool DataRead16(u32 addr, u32* val) = 0;
|
||||||
virtual void DataRead32(u32 addr, u32* val) = 0;
|
virtual bool DataRead32(u32 addr, u32* val) = 0;
|
||||||
virtual void DataRead32S(u32 addr, u32* val) = 0;
|
virtual bool DataRead32S(u32 addr, u32* val) = 0;
|
||||||
virtual void DataWrite8(u32 addr, u8 val) = 0;
|
virtual bool DataWrite8(u32 addr, u8 val) = 0;
|
||||||
virtual void DataWrite16(u32 addr, u16 val) = 0;
|
virtual bool DataWrite16(u32 addr, u16 val) = 0;
|
||||||
virtual void DataWrite32(u32 addr, u32 val) = 0;
|
virtual bool DataWrite32(u32 addr, u32 val) = 0;
|
||||||
virtual void DataWrite32S(u32 addr, u32 val) = 0;
|
virtual bool DataWrite32S(u32 addr, u32 val) = 0;
|
||||||
|
|
||||||
virtual void AddCycles_C() = 0;
|
virtual void AddCycles_C() = 0;
|
||||||
virtual void AddCycles_CI(s32 numI) = 0;
|
virtual void AddCycles_CI(s32 numI) = 0;
|
||||||
@ -176,8 +177,8 @@ public:
|
|||||||
u32 R_ABT[3];
|
u32 R_ABT[3];
|
||||||
u32 R_IRQ[3];
|
u32 R_IRQ[3];
|
||||||
u32 R_UND[3];
|
u32 R_UND[3];
|
||||||
u32 CurInstr;
|
u64 CurInstr;
|
||||||
u32 NextInstr[2];
|
u64 NextInstr[2];
|
||||||
|
|
||||||
u32 ExceptionBase;
|
u32 ExceptionBase;
|
||||||
|
|
||||||
@ -250,16 +251,16 @@ public:
|
|||||||
void Execute();
|
void Execute();
|
||||||
|
|
||||||
// all code accesses are forced nonseq 32bit
|
// all code accesses are forced nonseq 32bit
|
||||||
u32 CodeRead32(u32 addr, bool branch);
|
u64 CodeRead32(u32 addr, bool branch);
|
||||||
|
|
||||||
void DataRead8(u32 addr, u32* val) override;
|
bool DataRead8(u32 addr, u32* val) override;
|
||||||
void DataRead16(u32 addr, u32* val) override;
|
bool DataRead16(u32 addr, u32* val) override;
|
||||||
void DataRead32(u32 addr, u32* val) override;
|
bool DataRead32(u32 addr, u32* val) override;
|
||||||
void DataRead32S(u32 addr, u32* val) override;
|
bool DataRead32S(u32 addr, u32* val) override;
|
||||||
void DataWrite8(u32 addr, u8 val) override;
|
bool DataWrite8(u32 addr, u8 val) override;
|
||||||
void DataWrite16(u32 addr, u16 val) override;
|
bool DataWrite16(u32 addr, u16 val) override;
|
||||||
void DataWrite32(u32 addr, u32 val) override;
|
bool DataWrite32(u32 addr, u32 val) override;
|
||||||
void DataWrite32S(u32 addr, u32 val) override;
|
bool DataWrite32S(u32 addr, u32 val) override;
|
||||||
|
|
||||||
void AddCycles_C() override
|
void AddCycles_C() override
|
||||||
{
|
{
|
||||||
@ -399,18 +400,19 @@ public:
|
|||||||
return BusRead32(addr);
|
return BusRead32(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataRead8(u32 addr, u32* val) override;
|
bool DataRead8(u32 addr, u32* val) override;
|
||||||
void DataRead16(u32 addr, u32* val) override;
|
bool DataRead16(u32 addr, u32* val) override;
|
||||||
void DataRead32(u32 addr, u32* val) override;
|
bool DataRead32(u32 addr, u32* val) override;
|
||||||
void DataRead32S(u32 addr, u32* val) override;
|
bool DataRead32S(u32 addr, u32* val) override;
|
||||||
void DataWrite8(u32 addr, u8 val) override;
|
bool DataWrite8(u32 addr, u8 val) override;
|
||||||
void DataWrite16(u32 addr, u16 val) override;
|
bool DataWrite16(u32 addr, u16 val) override;
|
||||||
void DataWrite32(u32 addr, u32 val) override;
|
bool DataWrite32(u32 addr, u32 val) override;
|
||||||
void DataWrite32S(u32 addr, u32 val) override;
|
bool DataWrite32S(u32 addr, u32 val) override;
|
||||||
void AddCycles_C() override;
|
void AddCycles_C() override;
|
||||||
void AddCycles_CI(s32 num) override;
|
void AddCycles_CI(s32 num) override;
|
||||||
void AddCycles_CDI() override;
|
void AddCycles_CDI() override;
|
||||||
void AddCycles_CD() override;
|
void AddCycles_CD() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
u8 BusRead8(u32 addr) override;
|
u8 BusRead8(u32 addr) override;
|
||||||
u16 BusRead16(u32 addr) override;
|
u16 BusRead16(u32 addr) override;
|
||||||
|
@ -69,6 +69,14 @@ void T_UNK(ARM* cpu)
|
|||||||
cpu->JumpTo(cpu->ExceptionBase + 0x04);
|
cpu->JumpTo(cpu->ExceptionBase + 0x04);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void A_BKPT(ARM* cpu)
|
||||||
|
{
|
||||||
|
if (cpu->Num == 1) A_UNK(cpu); // checkme
|
||||||
|
|
||||||
|
Log(LogLevel::Warn, "BKPT: "); // combine with the prefetch abort warning message
|
||||||
|
((ARMv5*)cpu)->PrefetchAbort();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void A_MSR_IMM(ARM* cpu)
|
void A_MSR_IMM(ARM* cpu)
|
||||||
@ -90,7 +98,8 @@ void A_MSR_IMM(ARM* cpu)
|
|||||||
case 0x1A:
|
case 0x1A:
|
||||||
case 0x1B: psr = &cpu->R_UND[2]; break;
|
case 0x1B: psr = &cpu->R_UND[2]; break;
|
||||||
default:
|
default:
|
||||||
cpu->AddCycles_C();
|
if (cpu->Num != 1) cpu->AddCycles_C(); // arm 7
|
||||||
|
else cpu->AddCycles_CI(2); // arm 9
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -101,12 +110,9 @@ void A_MSR_IMM(ARM* cpu)
|
|||||||
|
|
||||||
u32 mask = 0;
|
u32 mask = 0;
|
||||||
if (cpu->CurInstr & (1<<16)) mask |= 0x000000FF;
|
if (cpu->CurInstr & (1<<16)) mask |= 0x000000FF;
|
||||||
if (cpu->CurInstr & (1<<17)) mask |= 0x0000FF00;
|
//if (cpu->CurInstr & (1<<17)) mask |= 0x0000FF00; // unused by arm 7 & 9
|
||||||
if (cpu->CurInstr & (1<<18)) mask |= 0x00FF0000;
|
//if (cpu->CurInstr & (1<<18)) mask |= 0x00FF0000; // unused by arm 7 & 9
|
||||||
if (cpu->CurInstr & (1<<19)) mask |= 0xFF000000;
|
if (cpu->CurInstr & (1<<19)) mask |= ((cpu->Num==1) ? 0xF0000000 : 0xF8000000);
|
||||||
|
|
||||||
if (!(cpu->CurInstr & (1<<22)))
|
|
||||||
mask &= 0xFFFFFFDF;
|
|
||||||
|
|
||||||
if ((cpu->CPSR & 0x1F) == 0x10) mask &= 0xFFFFFF00;
|
if ((cpu->CPSR & 0x1F) == 0x10) mask &= 0xFFFFFF00;
|
||||||
|
|
||||||
@ -121,7 +127,26 @@ void A_MSR_IMM(ARM* cpu)
|
|||||||
if (!(cpu->CurInstr & (1<<22)))
|
if (!(cpu->CurInstr & (1<<22)))
|
||||||
cpu->UpdateMode(oldpsr, cpu->CPSR);
|
cpu->UpdateMode(oldpsr, cpu->CPSR);
|
||||||
|
|
||||||
cpu->AddCycles_C();
|
if (cpu->CPSR & 0x20) [[unlikely]]
|
||||||
|
{
|
||||||
|
if (cpu->Num == 0) cpu->R[15] += 2; // pc should actually increment by 4 one more time after switching to thumb mode without a pipeline flush, this gets the same effect.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Platform::Log(Platform::LogLevel::Warn, "UNIMPLEMENTED: MSR REG T bit change on ARM7\n");
|
||||||
|
cpu->CPSR &= ~0x20; // keep it from crashing the emulator at least
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpu->Num != 1)
|
||||||
|
{
|
||||||
|
if (cpu->CurInstr & (1<<22))
|
||||||
|
{
|
||||||
|
cpu->AddCycles_CI(2); // spsr
|
||||||
|
}
|
||||||
|
else if (cpu->CurInstr & (0x7<<16)) cpu->AddCycles_CI(2); // cpsr_sxc
|
||||||
|
else cpu->AddCycles_C();
|
||||||
|
}
|
||||||
|
else cpu->AddCycles_C();
|
||||||
}
|
}
|
||||||
|
|
||||||
void A_MSR_REG(ARM* cpu)
|
void A_MSR_REG(ARM* cpu)
|
||||||
@ -143,7 +168,8 @@ void A_MSR_REG(ARM* cpu)
|
|||||||
case 0x1A:
|
case 0x1A:
|
||||||
case 0x1B: psr = &cpu->R_UND[2]; break;
|
case 0x1B: psr = &cpu->R_UND[2]; break;
|
||||||
default:
|
default:
|
||||||
cpu->AddCycles_C();
|
if (cpu->Num != 1) cpu->AddCycles_C(); // arm 7
|
||||||
|
else cpu->AddCycles_CI(2); // arm 9
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,12 +180,9 @@ void A_MSR_REG(ARM* cpu)
|
|||||||
|
|
||||||
u32 mask = 0;
|
u32 mask = 0;
|
||||||
if (cpu->CurInstr & (1<<16)) mask |= 0x000000FF;
|
if (cpu->CurInstr & (1<<16)) mask |= 0x000000FF;
|
||||||
if (cpu->CurInstr & (1<<17)) mask |= 0x0000FF00;
|
//if (cpu->CurInstr & (1<<17)) mask |= 0x0000FF00; // unused by arm 7 & 9
|
||||||
if (cpu->CurInstr & (1<<18)) mask |= 0x00FF0000;
|
//if (cpu->CurInstr & (1<<18)) mask |= 0x00FF0000; // unused by arm 7 & 9
|
||||||
if (cpu->CurInstr & (1<<19)) mask |= 0xFF000000;
|
if (cpu->CurInstr & (1<<19)) mask |= ((cpu->Num==1) ? 0xF0000000 : 0xF8000000);
|
||||||
|
|
||||||
if (!(cpu->CurInstr & (1<<22)))
|
|
||||||
mask &= 0xFFFFFFDF;
|
|
||||||
|
|
||||||
if ((cpu->CPSR & 0x1F) == 0x10) mask &= 0xFFFFFF00;
|
if ((cpu->CPSR & 0x1F) == 0x10) mask &= 0xFFFFFF00;
|
||||||
|
|
||||||
@ -174,7 +197,26 @@ void A_MSR_REG(ARM* cpu)
|
|||||||
if (!(cpu->CurInstr & (1<<22)))
|
if (!(cpu->CurInstr & (1<<22)))
|
||||||
cpu->UpdateMode(oldpsr, cpu->CPSR);
|
cpu->UpdateMode(oldpsr, cpu->CPSR);
|
||||||
|
|
||||||
cpu->AddCycles_C();
|
if (cpu->CPSR & 0x20) [[unlikely]]
|
||||||
|
{
|
||||||
|
if (cpu->Num == 0) cpu->R[15] += 2; // pc should actually increment by 4 one more time after switching to thumb mode without a pipeline flush, this gets the same effect.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Platform::Log(Platform::LogLevel::Warn, "UNIMPLEMENTED: MSR REG T bit change on ARM7\n");
|
||||||
|
cpu->CPSR &= ~0x20; // keep it from crashing the emulator at least
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpu->Num != 1)
|
||||||
|
{
|
||||||
|
if (cpu->CurInstr & (1<<22))
|
||||||
|
{
|
||||||
|
cpu->AddCycles_CI(2); // spsr
|
||||||
|
}
|
||||||
|
else if (cpu->CurInstr & (0x7<<16)) cpu->AddCycles_CI(2); // cpsr_sxc
|
||||||
|
else cpu->AddCycles_C();
|
||||||
|
}
|
||||||
|
else cpu->AddCycles_C();
|
||||||
}
|
}
|
||||||
|
|
||||||
void A_MRS(ARM* cpu)
|
void A_MRS(ARM* cpu)
|
||||||
@ -201,8 +243,15 @@ void A_MRS(ARM* cpu)
|
|||||||
else
|
else
|
||||||
psr = cpu->CPSR;
|
psr = cpu->CPSR;
|
||||||
|
|
||||||
cpu->R[(cpu->CurInstr>>12) & 0xF] = psr;
|
if (((cpu->CurInstr>>12) & 0xF) == 15)
|
||||||
cpu->AddCycles_C();
|
{
|
||||||
|
if (cpu->Num == 1) // doesn't seem to jump on the arm9? checkme
|
||||||
|
cpu->JumpTo(psr & ~0x1); // checkme: this shouldn't be able to switch to thumb?
|
||||||
|
}
|
||||||
|
else cpu->R[(cpu->CurInstr>>12) & 0xF] = psr;
|
||||||
|
|
||||||
|
if (cpu->Num != 1) cpu->AddCycles_CI(1); // arm9
|
||||||
|
else cpu->AddCycles_C(); // arm7
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -216,10 +265,12 @@ void A_MCR(ARM* cpu)
|
|||||||
u32 cn = (cpu->CurInstr >> 16) & 0xF;
|
u32 cn = (cpu->CurInstr >> 16) & 0xF;
|
||||||
u32 cm = cpu->CurInstr & 0xF;
|
u32 cm = cpu->CurInstr & 0xF;
|
||||||
u32 cpinfo = (cpu->CurInstr >> 5) & 0x7;
|
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)
|
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)
|
else if (cpu->Num==1 && cp==14)
|
||||||
{
|
{
|
||||||
@ -244,10 +295,17 @@ void A_MRC(ARM* cpu)
|
|||||||
u32 cn = (cpu->CurInstr >> 16) & 0xF;
|
u32 cn = (cpu->CurInstr >> 16) & 0xF;
|
||||||
u32 cm = cpu->CurInstr & 0xF;
|
u32 cm = cpu->CurInstr & 0xF;
|
||||||
u32 cpinfo = (cpu->CurInstr >> 5) & 0x7;
|
u32 cpinfo = (cpu->CurInstr >> 5) & 0x7;
|
||||||
|
u32 rd = (cpu->CurInstr>>12) & 0xF;
|
||||||
|
|
||||||
if (cpu->Num==0 && cp==15)
|
if (cpu->Num==0 && cp==15)
|
||||||
{
|
{
|
||||||
cpu->R[(cpu->CurInstr>>12)&0xF] = ((ARMv5*)cpu)->CP15Read((cn<<8)|(cm<<4)|cpinfo);
|
if (rd != 15) cpu->R[rd] = ((ARMv5*)cpu)->CP15Read((cn<<8)|(cm<<4)|cpinfo);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// r15 updates the top 4 bits of the cpsr, done to "allow for conditional branching based on coprocessor status"
|
||||||
|
u32 flags = ((ARMv5*)cpu)->CP15Read((cn<<8)|(cm<<4)|cpinfo) & 0xF0000000;
|
||||||
|
cpu->CPSR = (cpu->CPSR & ~0xF0000000) | flags;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (cpu->Num==1 && cp==14)
|
else if (cpu->Num==1 && cp==14)
|
||||||
{
|
{
|
||||||
@ -259,12 +317,13 @@ void A_MRC(ARM* cpu)
|
|||||||
return A_UNK(cpu); // TODO: check what kind of exception it really is
|
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;
|
u32 oldcpsr = cpu->CPSR;
|
||||||
cpu->CPSR &= ~0xBF;
|
cpu->CPSR &= ~0xBF;
|
||||||
@ -276,7 +335,7 @@ void A_SVC(ARM* cpu)
|
|||||||
cpu->JumpTo(cpu->ExceptionBase + 0x08);
|
cpu->JumpTo(cpu->ExceptionBase + 0x08);
|
||||||
}
|
}
|
||||||
|
|
||||||
void T_SVC(ARM* cpu)
|
void T_SVC(ARM* cpu) // T_SWI
|
||||||
{
|
{
|
||||||
u32 oldcpsr = cpu->CPSR;
|
u32 oldcpsr = cpu->CPSR;
|
||||||
cpu->CPSR &= ~0xBF;
|
cpu->CPSR &= ~0xBF;
|
||||||
|
@ -36,6 +36,7 @@ void A_MRS(ARM* cpu);
|
|||||||
void A_MCR(ARM* cpu);
|
void A_MCR(ARM* cpu);
|
||||||
void A_MRC(ARM* cpu);
|
void A_MRC(ARM* cpu);
|
||||||
void A_SVC(ARM* cpu);
|
void A_SVC(ARM* cpu);
|
||||||
|
void A_BKPT(ARM* cpu);
|
||||||
|
|
||||||
void T_SVC(ARM* cpu);
|
void T_SVC(ARM* cpu);
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "ARM.h"
|
#include "ARM.h"
|
||||||
#include "NDS.h"
|
#include "NDS.h"
|
||||||
|
#include "ARMInterpreter_MultiplySuperLLE.h"
|
||||||
|
|
||||||
namespace melonDS::ARMInterpreter
|
namespace melonDS::ARMInterpreter
|
||||||
{
|
{
|
||||||
@ -581,8 +582,27 @@ A_IMPLEMENT_ALU_OP(RSC,)
|
|||||||
#define A_TST(c) \
|
#define A_TST(c) \
|
||||||
u32 a = cpu->R[(cpu->CurInstr>>16) & 0xF]; \
|
u32 a = cpu->R[(cpu->CurInstr>>16) & 0xF]; \
|
||||||
u32 res = a & b; \
|
u32 res = a & b; \
|
||||||
cpu->SetNZ(res & 0x80000000, \
|
if (((cpu->CurInstr>>12) & 0xF) == 15) [[unlikely]] /* this seems to trigger alu rd==15 behavior for arm7 and legacy instruction behavior for arm9 */ \
|
||||||
!res); \
|
{ \
|
||||||
|
if (cpu->Num == 1) \
|
||||||
|
{ \
|
||||||
|
cpu->SetNZ(res & 0x80000000, \
|
||||||
|
!res); \
|
||||||
|
u32 oldpsr = cpu->CPSR; \
|
||||||
|
cpu->RestoreCPSR(); /* ARM7TDMI restores cpsr and does ___not___ flush the pipeline. */ \
|
||||||
|
if (cpu->CPSR & 0x20) \
|
||||||
|
{ \
|
||||||
|
Platform::Log(Platform::LogLevel::Warn, "UNIMPLEMENTED: TST T bit change on ARM7\n"); \
|
||||||
|
cpu->CPSR &= ~0x20; /* keep it from crashing the emulator at least */ \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
else cpu->JumpTo(res & ~1, true); /* TSTP dna, doesn't update flags */ \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
cpu->SetNZ(res & 0x80000000, \
|
||||||
|
!res); \
|
||||||
|
} \
|
||||||
if (c) cpu->AddCycles_CI(c); else cpu->AddCycles_C();
|
if (c) cpu->AddCycles_CI(c); else cpu->AddCycles_C();
|
||||||
|
|
||||||
A_IMPLEMENT_ALU_TEST(TST,_S)
|
A_IMPLEMENT_ALU_TEST(TST,_S)
|
||||||
@ -591,8 +611,27 @@ A_IMPLEMENT_ALU_TEST(TST,_S)
|
|||||||
#define A_TEQ(c) \
|
#define A_TEQ(c) \
|
||||||
u32 a = cpu->R[(cpu->CurInstr>>16) & 0xF]; \
|
u32 a = cpu->R[(cpu->CurInstr>>16) & 0xF]; \
|
||||||
u32 res = a ^ b; \
|
u32 res = a ^ b; \
|
||||||
cpu->SetNZ(res & 0x80000000, \
|
if (((cpu->CurInstr>>12) & 0xF) == 15) [[unlikely]] /* this seems to trigger alu rd==15 behavior for arm7 and legacy instruction behavior for arm9 */ \
|
||||||
!res); \
|
{ \
|
||||||
|
if (cpu->Num == 1) \
|
||||||
|
{ \
|
||||||
|
cpu->SetNZ(res & 0x80000000, \
|
||||||
|
!res); \
|
||||||
|
u32 oldpsr = cpu->CPSR; \
|
||||||
|
cpu->RestoreCPSR(); /* ARM7TDMI restores cpsr and does ___not___ flush the pipeline. */ \
|
||||||
|
if (cpu->CPSR & 0x20) \
|
||||||
|
{ \
|
||||||
|
Platform::Log(Platform::LogLevel::Warn, "UNIMPLEMENTED: TEQ T bit change on ARM7\n"); \
|
||||||
|
cpu->CPSR &= ~0x20; /* keep it from crashing the emulator at least */ \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
else cpu->JumpTo(res & ~1, true); /* TEQP dna, doesn't update flags */ \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
cpu->SetNZ(res & 0x80000000, \
|
||||||
|
!res); \
|
||||||
|
} \
|
||||||
if (c) cpu->AddCycles_CI(c); else cpu->AddCycles_C();
|
if (c) cpu->AddCycles_CI(c); else cpu->AddCycles_C();
|
||||||
|
|
||||||
A_IMPLEMENT_ALU_TEST(TEQ,_S)
|
A_IMPLEMENT_ALU_TEST(TEQ,_S)
|
||||||
@ -601,10 +640,31 @@ A_IMPLEMENT_ALU_TEST(TEQ,_S)
|
|||||||
#define A_CMP(c) \
|
#define A_CMP(c) \
|
||||||
u32 a = cpu->R[(cpu->CurInstr>>16) & 0xF]; \
|
u32 a = cpu->R[(cpu->CurInstr>>16) & 0xF]; \
|
||||||
u32 res = a - b; \
|
u32 res = a - b; \
|
||||||
cpu->SetNZCV(res & 0x80000000, \
|
if (((cpu->CurInstr>>12) & 0xF) == 15) [[unlikely]] /* this seems to trigger alu rd==15 behavior for arm7 and legacy instruction behavior for arm9 */ \
|
||||||
!res, \
|
{ \
|
||||||
CarrySub(a, b), \
|
if (cpu->Num == 1) \
|
||||||
OverflowSub(a, b)); \
|
{ \
|
||||||
|
cpu->SetNZCV(res & 0x80000000, \
|
||||||
|
!res, \
|
||||||
|
CarrySub(a, b), \
|
||||||
|
OverflowSub(a, b)); \
|
||||||
|
u32 oldpsr = cpu->CPSR; \
|
||||||
|
cpu->RestoreCPSR(); /* ARM7TDMI restores cpsr and does ___not___ flush the pipeline. */ \
|
||||||
|
if (cpu->CPSR & 0x20) \
|
||||||
|
{ \
|
||||||
|
Platform::Log(Platform::LogLevel::Warn, "UNIMPLEMENTED: CMP T bit change on ARM7\n"); \
|
||||||
|
cpu->CPSR &= ~0x20; /* keep it from crashing the emulator at least */ \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
else cpu->JumpTo(res & ~1, true); /* CMPP dna, doesn't update flags */ \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
cpu->SetNZCV(res & 0x80000000, \
|
||||||
|
!res, \
|
||||||
|
CarrySub(a, b), \
|
||||||
|
OverflowSub(a, b)); \
|
||||||
|
} \
|
||||||
if (c) cpu->AddCycles_CI(c); else cpu->AddCycles_C();
|
if (c) cpu->AddCycles_CI(c); else cpu->AddCycles_C();
|
||||||
|
|
||||||
A_IMPLEMENT_ALU_TEST(CMP,)
|
A_IMPLEMENT_ALU_TEST(CMP,)
|
||||||
@ -613,10 +673,31 @@ A_IMPLEMENT_ALU_TEST(CMP,)
|
|||||||
#define A_CMN(c) \
|
#define A_CMN(c) \
|
||||||
u32 a = cpu->R[(cpu->CurInstr>>16) & 0xF]; \
|
u32 a = cpu->R[(cpu->CurInstr>>16) & 0xF]; \
|
||||||
u32 res = a + b; \
|
u32 res = a + b; \
|
||||||
cpu->SetNZCV(res & 0x80000000, \
|
if (((cpu->CurInstr>>12) & 0xF) == 15) [[unlikely]] /* this seems to trigger alu rd==15 behavior for arm7 and legacy instruction behavior for arm9 */ \
|
||||||
!res, \
|
{ \
|
||||||
CarryAdd(a, b), \
|
if (cpu->Num == 1) \
|
||||||
OverflowAdd(a, b)); \
|
{ \
|
||||||
|
cpu->SetNZCV(res & 0x80000000, \
|
||||||
|
!res, \
|
||||||
|
CarryAdd(a, b), \
|
||||||
|
OverflowAdd(a, b)); \
|
||||||
|
u32 oldpsr = cpu->CPSR; \
|
||||||
|
cpu->RestoreCPSR(); /* ARM7TDMI restores cpsr and does ___not___ flush the pipeline. */ \
|
||||||
|
if (cpu->CPSR & 0x20) \
|
||||||
|
{ \
|
||||||
|
Platform::Log(Platform::LogLevel::Warn, "UNIMPLEMENTED: CMN T bit change on ARM7\n"); \
|
||||||
|
cpu->CPSR &= ~0x20; /* keep it from crashing the emulator at least */ \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
else cpu->JumpTo(res & ~1, true); /* CMNP dna, doesn't update flags */ \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
cpu->SetNZCV(res & 0x80000000, \
|
||||||
|
!res, \
|
||||||
|
CarryAdd(a, b), \
|
||||||
|
OverflowAdd(a, b)); \
|
||||||
|
} \
|
||||||
if (c) cpu->AddCycles_CI(c); else cpu->AddCycles_C();
|
if (c) cpu->AddCycles_CI(c); else cpu->AddCycles_C();
|
||||||
|
|
||||||
A_IMPLEMENT_ALU_TEST(CMN,)
|
A_IMPLEMENT_ALU_TEST(CMN,)
|
||||||
@ -766,12 +847,14 @@ void A_MUL(ARM* cpu)
|
|||||||
|
|
||||||
u32 res = rm * rs;
|
u32 res = rm * rs;
|
||||||
|
|
||||||
cpu->R[(cpu->CurInstr >> 16) & 0xF] = res;
|
// all multiply instructions fail writes to r15 on arm7/9
|
||||||
|
if (((cpu->CurInstr >> 16) & 0xF) != 15)
|
||||||
|
cpu->R[(cpu->CurInstr >> 16) & 0xF] = res;
|
||||||
|
|
||||||
if (cpu->CurInstr & (1<<20))
|
if (cpu->CurInstr & (1<<20))
|
||||||
{
|
{
|
||||||
cpu->SetNZ(res & 0x80000000,
|
cpu->SetNZ(res & 0x80000000,
|
||||||
!res);
|
!res);
|
||||||
if (cpu->Num==1) cpu->SetC(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 cycles;
|
u32 cycles;
|
||||||
@ -783,6 +866,7 @@ void A_MUL(ARM* cpu)
|
|||||||
else if ((rs & 0xFFFF0000) == 0x00000000 || (rs & 0xFFFF0000) == 0xFFFF0000) cycles = 2;
|
else if ((rs & 0xFFFF0000) == 0x00000000 || (rs & 0xFFFF0000) == 0xFFFF0000) cycles = 2;
|
||||||
else if ((rs & 0xFF000000) == 0x00000000 || (rs & 0xFF000000) == 0xFF000000) cycles = 3;
|
else if ((rs & 0xFF000000) == 0x00000000 || (rs & 0xFF000000) == 0xFF000000) cycles = 3;
|
||||||
else cycles = 4;
|
else cycles = 4;
|
||||||
|
if (cpu->CurInstr & (1<<20)) cpu->SetC(MULSCarry(rm, rs, 0, cycles==4));
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu->AddCycles_CI(cycles);
|
cpu->AddCycles_CI(cycles);
|
||||||
@ -795,13 +879,14 @@ void A_MLA(ARM* cpu)
|
|||||||
u32 rn = cpu->R[(cpu->CurInstr >> 12) & 0xF];
|
u32 rn = cpu->R[(cpu->CurInstr >> 12) & 0xF];
|
||||||
|
|
||||||
u32 res = (rm * rs) + rn;
|
u32 res = (rm * rs) + rn;
|
||||||
|
|
||||||
|
if (((cpu->CurInstr >> 16) & 0xF) != 15)
|
||||||
|
cpu->R[(cpu->CurInstr >> 16) & 0xF] = res;
|
||||||
|
|
||||||
cpu->R[(cpu->CurInstr >> 16) & 0xF] = res;
|
|
||||||
if (cpu->CurInstr & (1<<20))
|
if (cpu->CurInstr & (1<<20))
|
||||||
{
|
{
|
||||||
cpu->SetNZ(res & 0x80000000,
|
cpu->SetNZ(res & 0x80000000,
|
||||||
!res);
|
!res);
|
||||||
if (cpu->Num==1) cpu->SetC(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 cycles;
|
u32 cycles;
|
||||||
@ -813,6 +898,7 @@ void A_MLA(ARM* cpu)
|
|||||||
else if ((rs & 0xFFFF0000) == 0x00000000 || (rs & 0xFFFF0000) == 0xFFFF0000) cycles = 3;
|
else if ((rs & 0xFFFF0000) == 0x00000000 || (rs & 0xFFFF0000) == 0xFFFF0000) cycles = 3;
|
||||||
else if ((rs & 0xFF000000) == 0x00000000 || (rs & 0xFF000000) == 0xFF000000) cycles = 4;
|
else if ((rs & 0xFF000000) == 0x00000000 || (rs & 0xFF000000) == 0xFF000000) cycles = 4;
|
||||||
else cycles = 5;
|
else cycles = 5;
|
||||||
|
if (cpu->CurInstr & (1<<20)) cpu->SetC(MULSCarry(rm, rs, rn, cycles==5));
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu->AddCycles_CI(cycles);
|
cpu->AddCycles_CI(cycles);
|
||||||
@ -825,24 +911,27 @@ void A_UMULL(ARM* cpu)
|
|||||||
|
|
||||||
u64 res = (u64)rm * (u64)rs;
|
u64 res = (u64)rm * (u64)rs;
|
||||||
|
|
||||||
cpu->R[(cpu->CurInstr >> 12) & 0xF] = (u32)res;
|
if (((cpu->CurInstr >> 12) & 0xF) != 15)
|
||||||
cpu->R[(cpu->CurInstr >> 16) & 0xF] = (u32)(res >> 32ULL);
|
cpu->R[(cpu->CurInstr >> 12) & 0xF] = (u32)res;
|
||||||
|
if (((cpu->CurInstr >> 16) & 0xF) != 15)
|
||||||
|
cpu->R[(cpu->CurInstr >> 16) & 0xF] = (u32)(res >> 32ULL);
|
||||||
|
|
||||||
if (cpu->CurInstr & (1<<20))
|
if (cpu->CurInstr & (1<<20))
|
||||||
{
|
{
|
||||||
cpu->SetNZ((u32)(res >> 63ULL),
|
cpu->SetNZ((u32)(res >> 63ULL),
|
||||||
!res);
|
!res);
|
||||||
if (cpu->Num==1) cpu->SetC(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 cycles;
|
u32 cycles;
|
||||||
if (cpu->Num == 0)
|
if (cpu->Num == 0)
|
||||||
cycles = (cpu->CurInstr & (1<<20)) ? 3 : 1;
|
cycles = (cpu->CurInstr & (1<<20)) ? 4 : 2;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((rs & 0xFFFFFF00) == 0x00000000) cycles = 2;
|
if ((rs & 0xFFFFFF00) == 0x00000000) cycles = 2;
|
||||||
else if ((rs & 0xFFFF0000) == 0x00000000) cycles = 3;
|
else if ((rs & 0xFFFF0000) == 0x00000000) cycles = 3;
|
||||||
else if ((rs & 0xFF000000) == 0x00000000) cycles = 4;
|
else if ((rs & 0xFF000000) == 0x00000000) cycles = 4;
|
||||||
else cycles = 5;
|
else cycles = 5;
|
||||||
|
if (cpu->CurInstr & (1<<20)) cpu->SetC(UMULLSCarry(0, rm, rs, cycles==5));
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu->AddCycles_CI(cycles);
|
cpu->AddCycles_CI(cycles);
|
||||||
@ -857,25 +946,28 @@ void A_UMLAL(ARM* cpu)
|
|||||||
|
|
||||||
u64 rd = (u64)cpu->R[(cpu->CurInstr >> 12) & 0xF] | ((u64)cpu->R[(cpu->CurInstr >> 16) & 0xF] << 32ULL);
|
u64 rd = (u64)cpu->R[(cpu->CurInstr >> 12) & 0xF] | ((u64)cpu->R[(cpu->CurInstr >> 16) & 0xF] << 32ULL);
|
||||||
res += rd;
|
res += rd;
|
||||||
|
|
||||||
|
if (((cpu->CurInstr >> 12) & 0xF) != 15)
|
||||||
|
cpu->R[(cpu->CurInstr >> 12) & 0xF] = (u32)res;
|
||||||
|
if (((cpu->CurInstr >> 16) & 0xF) != 15)
|
||||||
|
cpu->R[(cpu->CurInstr >> 16) & 0xF] = (u32)(res >> 32ULL);
|
||||||
|
|
||||||
cpu->R[(cpu->CurInstr >> 12) & 0xF] = (u32)res;
|
|
||||||
cpu->R[(cpu->CurInstr >> 16) & 0xF] = (u32)(res >> 32ULL);
|
|
||||||
if (cpu->CurInstr & (1<<20))
|
if (cpu->CurInstr & (1<<20))
|
||||||
{
|
{
|
||||||
cpu->SetNZ((u32)(res >> 63ULL),
|
cpu->SetNZ((u32)(res >> 63ULL),
|
||||||
!res);
|
!res);
|
||||||
if (cpu->Num==1) cpu->SetC(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 cycles;
|
u32 cycles;
|
||||||
if (cpu->Num == 0)
|
if (cpu->Num == 0)
|
||||||
cycles = (cpu->CurInstr & (1<<20)) ? 3 : 1;
|
cycles = (cpu->CurInstr & (1<<20)) ? 4 : 2;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((rs & 0xFFFFFF00) == 0x00000000) cycles = 2;
|
if ((rs & 0xFFFFFF00) == 0x00000000) cycles = 2;
|
||||||
else if ((rs & 0xFFFF0000) == 0x00000000) cycles = 3;
|
else if ((rs & 0xFFFF0000) == 0x00000000) cycles = 3;
|
||||||
else if ((rs & 0xFF000000) == 0x00000000) cycles = 4;
|
else if ((rs & 0xFF000000) == 0x00000000) cycles = 4;
|
||||||
else cycles = 5;
|
else cycles = 5;
|
||||||
|
if (cpu->CurInstr & (1<<20)) cpu->SetC(UMULLSCarry(rd, rm, rs, cycles==5));
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu->AddCycles_CI(cycles);
|
cpu->AddCycles_CI(cycles);
|
||||||
@ -887,25 +979,28 @@ void A_SMULL(ARM* cpu)
|
|||||||
u32 rs = cpu->R[(cpu->CurInstr >> 8) & 0xF];
|
u32 rs = cpu->R[(cpu->CurInstr >> 8) & 0xF];
|
||||||
|
|
||||||
s64 res = (s64)(s32)rm * (s64)(s32)rs;
|
s64 res = (s64)(s32)rm * (s64)(s32)rs;
|
||||||
|
|
||||||
|
if (((cpu->CurInstr >> 12) & 0xF) != 15)
|
||||||
|
cpu->R[(cpu->CurInstr >> 12) & 0xF] = (u32)res;
|
||||||
|
if (((cpu->CurInstr >> 16) & 0xF) != 15)
|
||||||
|
cpu->R[(cpu->CurInstr >> 16) & 0xF] = (u32)(res >> 32ULL);
|
||||||
|
|
||||||
cpu->R[(cpu->CurInstr >> 12) & 0xF] = (u32)res;
|
|
||||||
cpu->R[(cpu->CurInstr >> 16) & 0xF] = (u32)(res >> 32ULL);
|
|
||||||
if (cpu->CurInstr & (1<<20))
|
if (cpu->CurInstr & (1<<20))
|
||||||
{
|
{
|
||||||
cpu->SetNZ((u32)(res >> 63ULL),
|
cpu->SetNZ((u32)(res >> 63ULL),
|
||||||
!res);
|
!res);
|
||||||
if (cpu->Num==1) cpu->SetC(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 cycles;
|
u32 cycles;
|
||||||
if (cpu->Num == 0)
|
if (cpu->Num == 0)
|
||||||
cycles = (cpu->CurInstr & (1<<20)) ? 3 : 1;
|
cycles = (cpu->CurInstr & (1<<20)) ? 4 : 2;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((rs & 0xFFFFFF00) == 0x00000000 || (rs & 0xFFFFFF00) == 0xFFFFFF00) cycles = 2;
|
if ((rs & 0xFFFFFF00) == 0x00000000 || (rs & 0xFFFFFF00) == 0xFFFFFF00) cycles = 2;
|
||||||
else if ((rs & 0xFFFF0000) == 0x00000000 || (rs & 0xFFFF0000) == 0xFFFF0000) cycles = 3;
|
else if ((rs & 0xFFFF0000) == 0x00000000 || (rs & 0xFFFF0000) == 0xFFFF0000) cycles = 3;
|
||||||
else if ((rs & 0xFF000000) == 0x00000000 || (rs & 0xFF000000) == 0xFF000000) cycles = 4;
|
else if ((rs & 0xFF000000) == 0x00000000 || (rs & 0xFF000000) == 0xFF000000) cycles = 4;
|
||||||
else cycles = 5;
|
else cycles = 5;
|
||||||
|
if (cpu->CurInstr & (1<<20)) cpu->SetC(SMULLSCarry(0, rm, rs, cycles==5));
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu->AddCycles_CI(cycles);
|
cpu->AddCycles_CI(cycles);
|
||||||
@ -920,25 +1015,28 @@ void A_SMLAL(ARM* cpu)
|
|||||||
|
|
||||||
s64 rd = (s64)((u64)cpu->R[(cpu->CurInstr >> 12) & 0xF] | ((u64)cpu->R[(cpu->CurInstr >> 16) & 0xF] << 32ULL));
|
s64 rd = (s64)((u64)cpu->R[(cpu->CurInstr >> 12) & 0xF] | ((u64)cpu->R[(cpu->CurInstr >> 16) & 0xF] << 32ULL));
|
||||||
res += rd;
|
res += rd;
|
||||||
|
|
||||||
|
if (((cpu->CurInstr >> 12) & 0xF) != 15)
|
||||||
|
cpu->R[(cpu->CurInstr >> 12) & 0xF] = (u32)res;
|
||||||
|
if (((cpu->CurInstr >> 16) & 0xF) != 15)
|
||||||
|
cpu->R[(cpu->CurInstr >> 16) & 0xF] = (u32)(res >> 32ULL);
|
||||||
|
|
||||||
cpu->R[(cpu->CurInstr >> 12) & 0xF] = (u32)res;
|
|
||||||
cpu->R[(cpu->CurInstr >> 16) & 0xF] = (u32)(res >> 32ULL);
|
|
||||||
if (cpu->CurInstr & (1<<20))
|
if (cpu->CurInstr & (1<<20))
|
||||||
{
|
{
|
||||||
cpu->SetNZ((u32)(res >> 63ULL),
|
cpu->SetNZ((u32)(res >> 63ULL),
|
||||||
!res);
|
!res);
|
||||||
if (cpu->Num==1) cpu->SetC(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 cycles;
|
u32 cycles;
|
||||||
if (cpu->Num == 0)
|
if (cpu->Num == 0)
|
||||||
cycles = (cpu->CurInstr & (1<<20)) ? 3 : 1;
|
cycles = (cpu->CurInstr & (1<<20)) ? 4 : 2;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((rs & 0xFFFFFF00) == 0x00000000 || (rs & 0xFFFFFF00) == 0xFFFFFF00) cycles = 2;
|
if ((rs & 0xFFFFFF00) == 0x00000000 || (rs & 0xFFFFFF00) == 0xFFFFFF00) cycles = 2;
|
||||||
else if ((rs & 0xFFFF0000) == 0x00000000 || (rs & 0xFFFF0000) == 0xFFFF0000) cycles = 3;
|
else if ((rs & 0xFFFF0000) == 0x00000000 || (rs & 0xFFFF0000) == 0xFFFF0000) cycles = 3;
|
||||||
else if ((rs & 0xFF000000) == 0x00000000 || (rs & 0xFF000000) == 0xFF000000) cycles = 4;
|
else if ((rs & 0xFF000000) == 0x00000000 || (rs & 0xFF000000) == 0xFF000000) cycles = 4;
|
||||||
else cycles = 5;
|
else cycles = 5;
|
||||||
|
if (cpu->CurInstr & (1<<20)) cpu->SetC(SMULLSCarry(rd, rm, rs, cycles==5));
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu->AddCycles_CI(cycles);
|
cpu->AddCycles_CI(cycles);
|
||||||
@ -959,8 +1057,10 @@ void A_SMLAxy(ARM* cpu)
|
|||||||
|
|
||||||
u32 res_mul = ((s16)rm * (s16)rs);
|
u32 res_mul = ((s16)rm * (s16)rs);
|
||||||
u32 res = res_mul + rn;
|
u32 res = res_mul + rn;
|
||||||
|
|
||||||
|
if (((cpu->CurInstr >> 16) & 0xF) != 15)
|
||||||
|
cpu->R[(cpu->CurInstr >> 16) & 0xF] = res;
|
||||||
|
|
||||||
cpu->R[(cpu->CurInstr >> 16) & 0xF] = res;
|
|
||||||
if (OverflowAdd(res_mul, rn))
|
if (OverflowAdd(res_mul, rn))
|
||||||
cpu->CPSR |= 0x08000000;
|
cpu->CPSR |= 0x08000000;
|
||||||
|
|
||||||
@ -980,8 +1080,9 @@ void A_SMLAWy(ARM* cpu)
|
|||||||
|
|
||||||
u32 res_mul = ((s64)(s32)rm * (s16)rs) >> 16;
|
u32 res_mul = ((s64)(s32)rm * (s16)rs) >> 16;
|
||||||
u32 res = res_mul + rn;
|
u32 res = res_mul + rn;
|
||||||
|
|
||||||
cpu->R[(cpu->CurInstr >> 16) & 0xF] = res;
|
if (((cpu->CurInstr >> 16) & 0xF) != 15)
|
||||||
|
cpu->R[(cpu->CurInstr >> 16) & 0xF] = res;
|
||||||
if (OverflowAdd(res_mul, rn))
|
if (OverflowAdd(res_mul, rn))
|
||||||
cpu->CPSR |= 0x08000000;
|
cpu->CPSR |= 0x08000000;
|
||||||
|
|
||||||
@ -1001,8 +1102,9 @@ void A_SMULxy(ARM* cpu)
|
|||||||
else rs &= 0xFFFF;
|
else rs &= 0xFFFF;
|
||||||
|
|
||||||
u32 res = ((s16)rm * (s16)rs);
|
u32 res = ((s16)rm * (s16)rs);
|
||||||
|
|
||||||
cpu->R[(cpu->CurInstr >> 16) & 0xF] = res;
|
if (((cpu->CurInstr >> 16) & 0xF) != 15)
|
||||||
|
cpu->R[(cpu->CurInstr >> 16) & 0xF] = res;
|
||||||
cpu->AddCycles_C(); // TODO: interlock??
|
cpu->AddCycles_C(); // TODO: interlock??
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1017,8 +1119,9 @@ void A_SMULWy(ARM* cpu)
|
|||||||
else rs &= 0xFFFF;
|
else rs &= 0xFFFF;
|
||||||
|
|
||||||
u32 res = ((s64)(s32)rm * (s16)rs) >> 16;
|
u32 res = ((s64)(s32)rm * (s16)rs) >> 16;
|
||||||
|
|
||||||
cpu->R[(cpu->CurInstr >> 16) & 0xF] = res;
|
if (((cpu->CurInstr >> 16) & 0xF) != 15)
|
||||||
|
cpu->R[(cpu->CurInstr >> 16) & 0xF] = res;
|
||||||
cpu->AddCycles_C(); // TODO: interlock??
|
cpu->AddCycles_C(); // TODO: interlock??
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1039,8 +1142,11 @@ void A_SMLALxy(ARM* cpu)
|
|||||||
s64 rd = (s64)((u64)cpu->R[(cpu->CurInstr >> 12) & 0xF] | ((u64)cpu->R[(cpu->CurInstr >> 16) & 0xF] << 32ULL));
|
s64 rd = (s64)((u64)cpu->R[(cpu->CurInstr >> 12) & 0xF] | ((u64)cpu->R[(cpu->CurInstr >> 16) & 0xF] << 32ULL));
|
||||||
res += rd;
|
res += rd;
|
||||||
|
|
||||||
cpu->R[(cpu->CurInstr >> 12) & 0xF] = (u32)res;
|
if (((cpu->CurInstr >> 12) & 0xF) != 15)
|
||||||
cpu->R[(cpu->CurInstr >> 16) & 0xF] = (u32)(res >> 32ULL);
|
cpu->R[(cpu->CurInstr >> 12) & 0xF] = (u32)res;
|
||||||
|
|
||||||
|
if (((cpu->CurInstr >> 16) & 0xF) != 15)
|
||||||
|
cpu->R[(cpu->CurInstr >> 16) & 0xF] = (u32)(res >> 32ULL);
|
||||||
|
|
||||||
cpu->AddCycles_CI(1); // TODO: interlock??
|
cpu->AddCycles_CI(1); // TODO: interlock??
|
||||||
}
|
}
|
||||||
@ -1067,7 +1173,8 @@ void A_CLZ(ARM* cpu)
|
|||||||
val |= 0x1;
|
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();
|
cpu->AddCycles_C();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1085,7 +1192,10 @@ void A_QADD(ARM* cpu)
|
|||||||
cpu->CPSR |= 0x08000000;
|
cpu->CPSR |= 0x08000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu->R[(cpu->CurInstr >> 12) & 0xF] = res;
|
// all saturated math instructions fail writes to r15
|
||||||
|
if (((cpu->CurInstr >> 12) & 0xF) != 15)
|
||||||
|
cpu->R[(cpu->CurInstr >> 12) & 0xF] = res;
|
||||||
|
|
||||||
cpu->AddCycles_C(); // TODO: interlock??
|
cpu->AddCycles_C(); // TODO: interlock??
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1102,8 +1212,10 @@ void A_QSUB(ARM* cpu)
|
|||||||
res = (res & 0x80000000) ? 0x7FFFFFFF : 0x80000000;
|
res = (res & 0x80000000) ? 0x7FFFFFFF : 0x80000000;
|
||||||
cpu->CPSR |= 0x08000000;
|
cpu->CPSR |= 0x08000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (((cpu->CurInstr >> 12) & 0xF) != 15)
|
||||||
|
cpu->R[(cpu->CurInstr >> 12) & 0xF] = res;
|
||||||
|
|
||||||
cpu->R[(cpu->CurInstr >> 12) & 0xF] = res;
|
|
||||||
cpu->AddCycles_C(); // TODO: interlock??
|
cpu->AddCycles_C(); // TODO: interlock??
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1128,8 +1240,10 @@ void A_QDADD(ARM* cpu)
|
|||||||
res = (res & 0x80000000) ? 0x7FFFFFFF : 0x80000000;
|
res = (res & 0x80000000) ? 0x7FFFFFFF : 0x80000000;
|
||||||
cpu->CPSR |= 0x08000000;
|
cpu->CPSR |= 0x08000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (((cpu->CurInstr >> 12) & 0xF) != 15)
|
||||||
|
cpu->R[(cpu->CurInstr >> 12) & 0xF] = res;
|
||||||
|
|
||||||
cpu->R[(cpu->CurInstr >> 12) & 0xF] = res;
|
|
||||||
cpu->AddCycles_C(); // TODO: interlock??
|
cpu->AddCycles_C(); // TODO: interlock??
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1154,8 +1268,10 @@ void A_QDSUB(ARM* cpu)
|
|||||||
res = (res & 0x80000000) ? 0x7FFFFFFF : 0x80000000;
|
res = (res & 0x80000000) ? 0x7FFFFFFF : 0x80000000;
|
||||||
cpu->CPSR |= 0x08000000;
|
cpu->CPSR |= 0x08000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (((cpu->CurInstr >> 12) & 0xF) != 15)
|
||||||
|
cpu->R[(cpu->CurInstr >> 12) & 0xF] = res;
|
||||||
|
|
||||||
cpu->R[(cpu->CurInstr >> 12) & 0xF] = res;
|
|
||||||
cpu->AddCycles_C(); // TODO: interlock??
|
cpu->AddCycles_C(); // TODO: interlock??
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1460,18 +1576,18 @@ void T_MUL_REG(ARM* cpu)
|
|||||||
cpu->SetNZ(res & 0x80000000,
|
cpu->SetNZ(res & 0x80000000,
|
||||||
!res);
|
!res);
|
||||||
|
|
||||||
s32 cycles = 0;
|
s32 cycles;
|
||||||
if (cpu->Num == 0)
|
if (cpu->Num == 0)
|
||||||
{
|
{
|
||||||
cycles += 3;
|
cycles = 3;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cpu->SetC(0); // carry flag destroyed, they say. whatever that means...
|
if ((a & 0xFFFFFF00) == 0x00000000 || (a & 0xFFFFFF00) == 0xFFFFFF00) cycles = 1;
|
||||||
if (a & 0xFF000000) cycles += 4;
|
else if ((a & 0xFFFF0000) == 0x00000000 || (a & 0xFFFF0000) == 0xFFFF0000) cycles = 2;
|
||||||
else if (a & 0x00FF0000) cycles += 3;
|
else if ((a & 0xFF000000) == 0x00000000 || (a & 0xFF000000) == 0xFF000000) cycles = 3;
|
||||||
else if (a & 0x0000FF00) cycles += 2;
|
else cycles = 4;
|
||||||
else cycles += 1;
|
cpu->SetC(MULSCarry(b, a, 0, cycles==4)); // carry flag destroyed, they say. whatever that means...
|
||||||
}
|
}
|
||||||
cpu->AddCycles_CI(cycles);
|
cpu->AddCycles_CI(cycles);
|
||||||
}
|
}
|
||||||
@ -1534,6 +1650,18 @@ void T_CMP_HIREG(ARM* cpu)
|
|||||||
!res,
|
!res,
|
||||||
CarrySub(a, b),
|
CarrySub(a, b),
|
||||||
OverflowSub(a, b));
|
OverflowSub(a, b));
|
||||||
|
|
||||||
|
if ((cpu->Num == 1) && (rd == 15))
|
||||||
|
{
|
||||||
|
u32 oldpsr = cpu->CPSR;
|
||||||
|
cpu->RestoreCPSR(); // ARM7TDMI restores cpsr and does ___not___ flush the pipeline.
|
||||||
|
if (!(cpu->CPSR & 0x20))
|
||||||
|
{
|
||||||
|
Platform::Log(Platform::LogLevel::Warn, "UNIMPLEMENTED: MSR REG T bit change on ARM7\n");
|
||||||
|
cpu->CPSR |= 0x20; // keep it from crashing the emulator at least
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cpu->AddCycles_C();
|
cpu->AddCycles_C();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,6 +104,9 @@ void T_BL_LONG_1(ARM* cpu)
|
|||||||
|
|
||||||
void T_BL_LONG_2(ARM* cpu)
|
void T_BL_LONG_2(ARM* cpu)
|
||||||
{
|
{
|
||||||
|
if ((cpu->CurInstr & 0x1801) == 0x0801) // "BLX" with bit 0 set is an undefined instruction.
|
||||||
|
return T_UNK(cpu); // TODO: Check ARM7 for exceptions
|
||||||
|
|
||||||
s32 offset = (cpu->CurInstr & 0x7FF) << 1;
|
s32 offset = (cpu->CurInstr & 0x7FF) << 1;
|
||||||
u32 pc = cpu->R[14] + offset;
|
u32 pc = cpu->R[14] + offset;
|
||||||
cpu->R[14] = (cpu->R[15] - 2) | 1;
|
cpu->R[14] = (cpu->R[15] - 2) | 1;
|
||||||
|
File diff suppressed because it is too large
Load Diff
136
src/ARMInterpreter_MultiplySuperLLE.h
Normal file
136
src/ARMInterpreter_MultiplySuperLLE.h
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
#ifndef ARMINTERPRETER_MULTIPLYSUPERLLE_H
|
||||||
|
#define ARMINTERPRETER_MULTIPLYSUPERLLE_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
using namespace melonDS;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright (c) 2024 zaydlang
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
|
||||||
|
If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// code taken from: (also features a few alternative implementations that could maybe be worth looking at?)
|
||||||
|
// https://github.com/calc84maniac/multiplication-algorithm/blob/master/impl_opt.h
|
||||||
|
// based on research that can be found here: https://bmchtech.github.io/post/multiply/
|
||||||
|
|
||||||
|
// the code in this file is dedicated to handling the calculation of the carry flag for multiplication (S variant) instructions on the ARM7TDMI.
|
||||||
|
|
||||||
|
|
||||||
|
// Takes a multiplier between -0x01000000 and 0x00FFFFFF, cycles between 0 and 2
|
||||||
|
static inline bool booths_multiplication32_opt(u32 multiplicand, u32 multiplier, u32 accumulator) {
|
||||||
|
// Set the low bit of the multiplicand to cause negation to invert the upper bits, this bit can't propagate to bit 31
|
||||||
|
multiplicand |= 1;
|
||||||
|
|
||||||
|
// Optimized first iteration
|
||||||
|
u32 booth = (s32)(multiplier << 31) >> 31;
|
||||||
|
u32 carry = booth * multiplicand;
|
||||||
|
// Pre-populate accumulator for output
|
||||||
|
u32 output = accumulator;
|
||||||
|
|
||||||
|
u32 sum = output + carry;
|
||||||
|
int shift = 29;
|
||||||
|
do {
|
||||||
|
for (int i = 0; i < 4; i++, shift -= 2) {
|
||||||
|
// Get next booth factor (-2 to 2, shifted left by 30-shift)
|
||||||
|
u32 next_booth = (s32)(multiplier << shift) >> shift;
|
||||||
|
u32 factor = next_booth - booth;
|
||||||
|
booth = next_booth;
|
||||||
|
// Get scaled value of booth addend
|
||||||
|
u32 addend = multiplicand * factor;
|
||||||
|
// Combine the addend with the CSA
|
||||||
|
// Not performing any masking seems to work because the lower carries can't propagate to bit 31
|
||||||
|
output ^= carry ^ addend;
|
||||||
|
sum += addend;
|
||||||
|
carry = sum - output;
|
||||||
|
}
|
||||||
|
} while (booth != multiplier);
|
||||||
|
|
||||||
|
return carry >> 31;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Takes a multiplicand shifted right by 6 and a multiplier shifted right by 26 (zero or sign extended)
|
||||||
|
static inline bool booths_multiplication64_opt(u32 multiplicand, u32 multiplier, u32 accum_hi) {
|
||||||
|
// Skipping the first 14 iterations seems to work because the lower carries can't propagate to bit 63
|
||||||
|
// This means only magic bits 62-61 are needed (which requires decoding 3 booth chunks),
|
||||||
|
// and only the last two booth iterations are needed
|
||||||
|
|
||||||
|
// Set the low bit of the multiplicand to cause negation to invert the upper bits
|
||||||
|
multiplicand |= 1;
|
||||||
|
|
||||||
|
// Pre-populate magic bit 61 for carry
|
||||||
|
u32 carry = ~accum_hi & UINT32_C(0x20000000);
|
||||||
|
// Pre-populate magic bits 63-60 for output (with carry magic pre-added in)
|
||||||
|
u32 output = accum_hi - UINT32_C(0x08000000);
|
||||||
|
|
||||||
|
// Get factors from the top 3 booth chunks
|
||||||
|
u32 booth0 = (s32)(multiplier << 27) >> 27;
|
||||||
|
u32 booth1 = (s32)(multiplier << 29) >> 29;
|
||||||
|
u32 booth2 = (s32)(multiplier << 31) >> 31;
|
||||||
|
u32 factor0 = multiplier - booth0;
|
||||||
|
u32 factor1 = booth0 - booth1;
|
||||||
|
u32 factor2 = booth1 - booth2;
|
||||||
|
|
||||||
|
// Get scaled value of the 3rd top booth addend
|
||||||
|
u32 addend = multiplicand * factor2;
|
||||||
|
// Finalize bits 61-60 of output magic using its sign
|
||||||
|
output -= addend & UINT32_C(0x10000000);
|
||||||
|
// Get scaled value of the 2nd top booth addend
|
||||||
|
addend = multiplicand * factor1;
|
||||||
|
// Finalize bits 63-62 of output magic using its sign
|
||||||
|
output -= addend & UINT32_C(0x40000000);
|
||||||
|
|
||||||
|
// Get the carry from the CSA in bit 61 and propagate it to bit 62, which is not processed in this iteration
|
||||||
|
u32 sum = output + (addend & UINT32_C(0x20000000));
|
||||||
|
// Subtract out the carry magic to get the actual output magic
|
||||||
|
output -= carry;
|
||||||
|
|
||||||
|
// Get scaled value of the 1st top booth addend
|
||||||
|
addend = multiplicand * factor0;
|
||||||
|
// Add to bit 62 and propagate the carry
|
||||||
|
sum += addend & UINT32_C(0x40000000);
|
||||||
|
|
||||||
|
// Cancel out the output magic bit 63 to get the carry bit 63
|
||||||
|
return (sum ^ output) >> 31;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// also for MLAS and MUL (thumb ver.)
|
||||||
|
inline bool MULSCarry(s32 rm, s32 rs, u32 rn, bool lastcycle)
|
||||||
|
{
|
||||||
|
if (lastcycle)
|
||||||
|
return (rs >> 30) == -2;
|
||||||
|
else
|
||||||
|
return booths_multiplication32_opt(rm, rs, rn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// also for UMLALS
|
||||||
|
inline bool UMULLSCarry(u64 rd, u32 rm, u32 rs, bool lastcycle)
|
||||||
|
{
|
||||||
|
if (lastcycle)
|
||||||
|
return booths_multiplication64_opt(rm >> 6, rs >> 26, rd >> 32);
|
||||||
|
else
|
||||||
|
return booths_multiplication32_opt(rm, rs, rd & 0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// also for SMLALS
|
||||||
|
inline bool SMULLSCarry(u64 rd, s32 rm, s32 rs, bool lastcycle)
|
||||||
|
{
|
||||||
|
if (lastcycle)
|
||||||
|
return booths_multiplication64_opt(rm >> 6, rs >> 26, rd >> 32);
|
||||||
|
else
|
||||||
|
return booths_multiplication32_opt(rm, rs, rd & 0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -588,7 +588,7 @@ void ARMJIT::CompileBlock(ARM* cpu) noexcept
|
|||||||
u32 numWriteAddrs = 0, writeAddrsTranslated = 0;
|
u32 numWriteAddrs = 0, writeAddrsTranslated = 0;
|
||||||
|
|
||||||
cpu->FillPipeline();
|
cpu->FillPipeline();
|
||||||
u32 nextInstr[2] = {cpu->NextInstr[0], cpu->NextInstr[1]};
|
u32 nextInstr[2] = {(u32)cpu->NextInstr[0], (u32)cpu->NextInstr[1]};
|
||||||
u32 nextInstrAddr[2] = {blockAddr, r15};
|
u32 nextInstrAddr[2] = {blockAddr, r15};
|
||||||
|
|
||||||
JIT_DEBUGPRINT("start block %x %08x (%x)\n", blockAddr, cpu->CPSR, localAddr);
|
JIT_DEBUGPRINT("start block %x %08x (%x)\n", blockAddr, cpu->CPSR, localAddr);
|
||||||
|
@ -194,6 +194,7 @@ const u32 A_BX = A_BranchAlways | A_Read0 | ak(ak_BX);
|
|||||||
const u32 A_BLX_REG = A_BranchAlways | A_Link | A_Read0 | ak(ak_BLX_REG);
|
const u32 A_BLX_REG = A_BranchAlways | A_Link | A_Read0 | ak(ak_BLX_REG);
|
||||||
|
|
||||||
const u32 A_UNK = A_BranchAlways | A_Link | ak(ak_UNK);
|
const u32 A_UNK = A_BranchAlways | A_Link | ak(ak_UNK);
|
||||||
|
const u32 A_BKPT = A_BranchAlways | A_Link | ak(ak_UNK);
|
||||||
const u32 A_MSR_IMM = ak(ak_MSR_IMM);
|
const u32 A_MSR_IMM = ak(ak_MSR_IMM);
|
||||||
const u32 A_MSR_REG = A_Read0 | ak(ak_MSR_REG);
|
const u32 A_MSR_REG = A_Read0 | ak(ak_MSR_REG);
|
||||||
const u32 A_MRS = A_Write12 | ak(ak_MRS);
|
const u32 A_MRS = A_Write12 | ak(ak_MRS);
|
||||||
|
@ -130,7 +130,7 @@ INSTRFUNC_PROTO(ARMInstrTable[4096]) =
|
|||||||
|
|
||||||
// 0001 0010 0000
|
// 0001 0010 0000
|
||||||
A_MSR_REG, A_BX, A_UNK, A_BLX_REG,
|
A_MSR_REG, A_BX, A_UNK, A_BLX_REG,
|
||||||
A_UNK, A_QSUB, A_UNK, A_UNK,
|
A_UNK, A_QSUB, A_UNK, A_BKPT,
|
||||||
A_SMLAWy, A_UNK, A_SMULWy, A_STRH_REG,
|
A_SMLAWy, A_UNK, A_SMULWy, A_STRH_REG,
|
||||||
A_SMLAWy, A_LDRD_REG, A_SMULWy, A_STRD_REG,
|
A_SMLAWy, A_LDRD_REG, A_SMULWy, A_STRD_REG,
|
||||||
|
|
||||||
|
155
src/CP15.cpp
155
src/CP15.cpp
@ -266,8 +266,6 @@ void ARMv5::UpdatePURegions(bool update_all)
|
|||||||
// PU disabled
|
// PU disabled
|
||||||
|
|
||||||
u8 mask = 0x07;
|
u8 mask = 0x07;
|
||||||
if (CP15Control & (1<<2)) mask |= 0x30;
|
|
||||||
if (CP15Control & (1<<12)) mask |= 0x40;
|
|
||||||
|
|
||||||
memset(PU_UserMap, mask, 0x100000);
|
memset(PU_UserMap, mask, 0x100000);
|
||||||
memset(PU_PrivMap, mask, 0x100000);
|
memset(PU_PrivMap, mask, 0x100000);
|
||||||
@ -579,7 +577,7 @@ void ARMv5::CP15Write(u32 id, u32 val)
|
|||||||
case 0x670:
|
case 0x670:
|
||||||
case 0x671:
|
case 0x671:
|
||||||
char log_output[1024];
|
char log_output[1024];
|
||||||
PU_Region[(id >> 4) & 0xF] = val;
|
PU_Region[(id >> 4) & 0xF] = val & ~(0x3F<<6);
|
||||||
|
|
||||||
std::snprintf(log_output,
|
std::snprintf(log_output,
|
||||||
sizeof(log_output),
|
sizeof(log_output),
|
||||||
@ -773,16 +771,15 @@ u32 ARMv5::CP15Read(u32 id) const
|
|||||||
// TCM are handled here.
|
// TCM are handled here.
|
||||||
// TODO: later on, handle PU, and maybe caches
|
// TODO: later on, handle PU, and maybe caches
|
||||||
|
|
||||||
u32 ARMv5::CodeRead32(u32 addr, bool branch)
|
u64 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))
|
CodeCycles = 1;
|
||||||
{
|
return ((u64)1<<63);
|
||||||
PrefetchAbort();
|
}
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if (addr < ITCMSize)
|
if (addr < ITCMSize)
|
||||||
{
|
{
|
||||||
@ -807,150 +804,163 @@ 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))
|
// Data Aborts
|
||||||
|
// Exception is handled in the actual instruction implementation
|
||||||
|
if (!(PU_Map[addr>>12] & 0x01)) [[unlikely]]
|
||||||
{
|
{
|
||||||
DataAbort();
|
DataCycles = 1;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataRegion = addr;
|
|
||||||
|
|
||||||
if (addr < ITCMSize)
|
if (addr < ITCMSize)
|
||||||
{
|
{
|
||||||
DataCycles = 1;
|
DataCycles = 1;
|
||||||
*val = *(u8*)&ITCM[addr & (ITCMPhysicalSize - 1)];
|
*val = *(u8*)&ITCM[addr & (ITCMPhysicalSize - 1)];
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
if ((addr & DTCMMask) == DTCMBase)
|
if ((addr & DTCMMask) == DTCMBase)
|
||||||
{
|
{
|
||||||
DataCycles = 1;
|
DataCycles = 1;
|
||||||
*val = *(u8*)&DTCM[addr & (DTCMPhysicalSize - 1)];
|
*val = *(u8*)&DTCM[addr & (DTCMPhysicalSize - 1)];
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
*val = BusRead8(addr);
|
*val = BusRead8(addr);
|
||||||
DataCycles = MemTimings[addr >> 12][1];
|
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))
|
// Data Aborts
|
||||||
|
// Exception is handled in the actual instruction implementation
|
||||||
|
if (!(PU_Map[addr>>12] & 0x01)) [[unlikely]]
|
||||||
{
|
{
|
||||||
DataAbort();
|
DataCycles = 1;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataRegion = addr;
|
|
||||||
|
|
||||||
addr &= ~1;
|
addr &= ~1;
|
||||||
|
|
||||||
if (addr < ITCMSize)
|
if (addr < ITCMSize)
|
||||||
{
|
{
|
||||||
DataCycles = 1;
|
DataCycles = 1;
|
||||||
*val = *(u16*)&ITCM[addr & (ITCMPhysicalSize - 1)];
|
*val = *(u16*)&ITCM[addr & (ITCMPhysicalSize - 1)];
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
if ((addr & DTCMMask) == DTCMBase)
|
if ((addr & DTCMMask) == DTCMBase)
|
||||||
{
|
{
|
||||||
DataCycles = 1;
|
DataCycles = 1;
|
||||||
*val = *(u16*)&DTCM[addr & (DTCMPhysicalSize - 1)];
|
*val = *(u16*)&DTCM[addr & (DTCMPhysicalSize - 1)];
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
*val = BusRead16(addr);
|
*val = BusRead16(addr);
|
||||||
DataCycles = MemTimings[addr >> 12][1];
|
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))
|
// Data Aborts
|
||||||
|
// Exception is handled in the actual instruction implementation
|
||||||
|
if (!(PU_Map[addr>>12] & 0x01)) [[unlikely]]
|
||||||
{
|
{
|
||||||
DataAbort();
|
DataCycles = 1;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataRegion = addr;
|
|
||||||
|
|
||||||
addr &= ~3;
|
addr &= ~3;
|
||||||
|
|
||||||
if (addr < ITCMSize)
|
if (addr < ITCMSize)
|
||||||
{
|
{
|
||||||
DataCycles = 1;
|
DataCycles = 1;
|
||||||
*val = *(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)];
|
*val = *(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)];
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
if ((addr & DTCMMask) == DTCMBase)
|
if ((addr & DTCMMask) == DTCMBase)
|
||||||
{
|
{
|
||||||
DataCycles = 1;
|
DataCycles = 1;
|
||||||
*val = *(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)];
|
*val = *(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)];
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
*val = BusRead32(addr);
|
*val = BusRead32(addr);
|
||||||
DataCycles = MemTimings[addr >> 12][2];
|
DataCycles = MemTimings[addr >> 12][2];
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARMv5::DataRead32S(u32 addr, u32* val)
|
bool ARMv5::DataRead32S(u32 addr, u32* val)
|
||||||
{
|
{
|
||||||
|
// Data Aborts
|
||||||
|
// Exception is handled in the actual instruction implementation
|
||||||
|
if (!(PU_Map[addr>>12] & 0x01)) [[unlikely]]
|
||||||
|
{
|
||||||
|
DataCycles += 1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
addr &= ~3;
|
addr &= ~3;
|
||||||
|
|
||||||
if (addr < ITCMSize)
|
if (addr < ITCMSize)
|
||||||
{
|
{
|
||||||
DataCycles += 1;
|
DataCycles += 1;
|
||||||
*val = *(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)];
|
*val = *(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)];
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
if ((addr & DTCMMask) == DTCMBase)
|
if ((addr & DTCMMask) == DTCMBase)
|
||||||
{
|
{
|
||||||
DataCycles += 1;
|
DataCycles += 1;
|
||||||
*val = *(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)];
|
*val = *(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)];
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
*val = BusRead32(addr);
|
*val = BusRead32(addr);
|
||||||
DataCycles += MemTimings[addr >> 12][3];
|
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))
|
// Data Aborts
|
||||||
|
// Exception is handled in the actual instruction implementation
|
||||||
|
if (!(PU_Map[addr>>12] & 0x02)) [[unlikely]]
|
||||||
{
|
{
|
||||||
DataAbort();
|
DataCycles = 1;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataRegion = addr;
|
|
||||||
|
|
||||||
if (addr < ITCMSize)
|
if (addr < ITCMSize)
|
||||||
{
|
{
|
||||||
DataCycles = 1;
|
DataCycles = 1;
|
||||||
*(u8*)&ITCM[addr & (ITCMPhysicalSize - 1)] = val;
|
*(u8*)&ITCM[addr & (ITCMPhysicalSize - 1)] = val;
|
||||||
NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr);
|
NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
if ((addr & DTCMMask) == DTCMBase)
|
if ((addr & DTCMMask) == DTCMBase)
|
||||||
{
|
{
|
||||||
DataCycles = 1;
|
DataCycles = 1;
|
||||||
*(u8*)&DTCM[addr & (DTCMPhysicalSize - 1)] = val;
|
*(u8*)&DTCM[addr & (DTCMPhysicalSize - 1)] = val;
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
BusWrite8(addr, val);
|
BusWrite8(addr, val);
|
||||||
DataCycles = MemTimings[addr >> 12][1];
|
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))
|
// Data Aborts
|
||||||
|
// Exception is handled in the actual instruction implementation
|
||||||
|
if (!(PU_Map[addr>>12] & 0x02)) [[unlikely]]
|
||||||
{
|
{
|
||||||
DataAbort();
|
DataCycles = 1;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataRegion = addr;
|
|
||||||
|
|
||||||
addr &= ~1;
|
addr &= ~1;
|
||||||
|
|
||||||
if (addr < ITCMSize)
|
if (addr < ITCMSize)
|
||||||
@ -958,29 +968,30 @@ void ARMv5::DataWrite16(u32 addr, u16 val)
|
|||||||
DataCycles = 1;
|
DataCycles = 1;
|
||||||
*(u16*)&ITCM[addr & (ITCMPhysicalSize - 1)] = val;
|
*(u16*)&ITCM[addr & (ITCMPhysicalSize - 1)] = val;
|
||||||
NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr);
|
NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
if ((addr & DTCMMask) == DTCMBase)
|
if ((addr & DTCMMask) == DTCMBase)
|
||||||
{
|
{
|
||||||
DataCycles = 1;
|
DataCycles = 1;
|
||||||
*(u16*)&DTCM[addr & (DTCMPhysicalSize - 1)] = val;
|
*(u16*)&DTCM[addr & (DTCMPhysicalSize - 1)] = val;
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
BusWrite16(addr, val);
|
BusWrite16(addr, val);
|
||||||
DataCycles = MemTimings[addr >> 12][1];
|
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))
|
// Data Aborts
|
||||||
|
// Exception is handled in the actual instruction implementation
|
||||||
|
if (!(PU_Map[addr>>12] & 0x02)) [[unlikely]]
|
||||||
{
|
{
|
||||||
DataAbort();
|
DataCycles = 1;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataRegion = addr;
|
|
||||||
|
|
||||||
addr &= ~3;
|
addr &= ~3;
|
||||||
|
|
||||||
if (addr < ITCMSize)
|
if (addr < ITCMSize)
|
||||||
@ -988,21 +999,30 @@ void ARMv5::DataWrite32(u32 addr, u32 val)
|
|||||||
DataCycles = 1;
|
DataCycles = 1;
|
||||||
*(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)] = val;
|
*(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)] = val;
|
||||||
NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr);
|
NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
if ((addr & DTCMMask) == DTCMBase)
|
if ((addr & DTCMMask) == DTCMBase)
|
||||||
{
|
{
|
||||||
DataCycles = 1;
|
DataCycles = 1;
|
||||||
*(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)] = val;
|
*(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)] = val;
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
BusWrite32(addr, val);
|
BusWrite32(addr, val);
|
||||||
DataCycles = MemTimings[addr >> 12][2];
|
DataCycles = MemTimings[addr >> 12][2];
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARMv5::DataWrite32S(u32 addr, u32 val)
|
bool ARMv5::DataWrite32S(u32 addr, u32 val)
|
||||||
{
|
{
|
||||||
|
// Data Aborts
|
||||||
|
// Exception is handled in the actual instruction implementation
|
||||||
|
if (!(PU_Map[addr>>12] & 0x02)) [[unlikely]]
|
||||||
|
{
|
||||||
|
DataCycles += 1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
addr &= ~3;
|
addr &= ~3;
|
||||||
|
|
||||||
if (addr < ITCMSize)
|
if (addr < ITCMSize)
|
||||||
@ -1012,17 +1032,18 @@ void ARMv5::DataWrite32S(u32 addr, u32 val)
|
|||||||
#ifdef JIT_ENABLED
|
#ifdef JIT_ENABLED
|
||||||
NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr);
|
NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr);
|
||||||
#endif
|
#endif
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
if ((addr & DTCMMask) == DTCMBase)
|
if ((addr & DTCMMask) == DTCMBase)
|
||||||
{
|
{
|
||||||
DataCycles += 1;
|
DataCycles += 1;
|
||||||
*(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)] = val;
|
*(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)] = val;
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
BusWrite32(addr, val);
|
BusWrite32(addr, val);
|
||||||
DataCycles += MemTimings[addr >> 12][3];
|
DataCycles += MemTimings[addr >> 12][3];
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARMv5::GetCodeMemRegion(u32 addr, MemRegion* region)
|
void ARMv5::GetCodeMemRegion(u32 addr, MemRegion* region)
|
||||||
|
18
src/DSi.cpp
18
src/DSi.cpp
@ -162,6 +162,7 @@ void DSi::Reset()
|
|||||||
SCFG_Clock9 = 0x0187; // CHECKME
|
SCFG_Clock9 = 0x0187; // CHECKME
|
||||||
SCFG_Clock7 = 0x0187;
|
SCFG_Clock7 = 0x0187;
|
||||||
SCFG_EXT[0] = 0x8307F100;
|
SCFG_EXT[0] = 0x8307F100;
|
||||||
|
SetVRAMTimings(true);
|
||||||
SCFG_EXT[1] = 0x93FFFB06;
|
SCFG_EXT[1] = 0x93FFFB06;
|
||||||
SCFG_MC = 0x0010 | (~((u32)(NDSCartSlot.GetCart() != nullptr))&1);//0x0011;
|
SCFG_MC = 0x0010 | (~((u32)(NDSCartSlot.GetCart() != nullptr))&1);//0x0011;
|
||||||
SCFG_RST = 0;
|
SCFG_RST = 0;
|
||||||
@ -235,6 +236,7 @@ void DSi::DoSavestateExtra(Savestate* file)
|
|||||||
Set_SCFG_Clock9(SCFG_Clock9);
|
Set_SCFG_Clock9(SCFG_Clock9);
|
||||||
Set_SCFG_MC(SCFG_MC);
|
Set_SCFG_MC(SCFG_MC);
|
||||||
DSP.SetRstLine(SCFG_RST & 0x0001);
|
DSP.SetRstLine(SCFG_RST & 0x0001);
|
||||||
|
SetVRAMTimings(SCFG_EXT[0] & (1<<13));
|
||||||
|
|
||||||
MBK[0][8] = 0;
|
MBK[0][8] = 0;
|
||||||
MBK[1][8] = 0;
|
MBK[1][8] = 0;
|
||||||
@ -713,6 +715,7 @@ void DSi::SoftReset()
|
|||||||
SCFG_Clock9 = 0x0187; // CHECKME
|
SCFG_Clock9 = 0x0187; // CHECKME
|
||||||
SCFG_Clock7 = 0x0187;
|
SCFG_Clock7 = 0x0187;
|
||||||
SCFG_EXT[0] = 0x8307F100;
|
SCFG_EXT[0] = 0x8307F100;
|
||||||
|
SetVRAMTimings(true);
|
||||||
SCFG_EXT[1] = 0x93FFFB06;
|
SCFG_EXT[1] = 0x93FFFB06;
|
||||||
SCFG_MC = 0x0010;//0x0011;
|
SCFG_MC = 0x0010;//0x0011;
|
||||||
// TODO: is this actually reset?
|
// 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)
|
u8 DSi::ARM9Read8(u32 addr)
|
||||||
{
|
{
|
||||||
@ -2541,11 +2552,18 @@ void DSi::ARM9IOWrite32(u32 addr, u32 val)
|
|||||||
u32 oldram = (SCFG_EXT[0] >> 14) & 0x3;
|
u32 oldram = (SCFG_EXT[0] >> 14) & 0x3;
|
||||||
u32 newram = (val >> 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] &= ~0x8007F19F;
|
||||||
SCFG_EXT[0] |= (val & 0x8007F19F);
|
SCFG_EXT[0] |= (val & 0x8007F19F);
|
||||||
SCFG_EXT[1] &= ~0x0000F080;
|
SCFG_EXT[1] &= ~0x0000F080;
|
||||||
SCFG_EXT[1] |= (val & 0x0000F080);
|
SCFG_EXT[1] |= (val & 0x0000F080);
|
||||||
Log(LogLevel::Debug, "SCFG_EXT = %08X / %08X (val9 %08X)\n", SCFG_EXT[0], SCFG_EXT[1], val);
|
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)
|
/*switch ((SCFG_EXT[0] >> 14) & 0x3)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -96,6 +96,7 @@ public:
|
|||||||
void MapNWRAM_B(u32 num, u8 val);
|
void MapNWRAM_B(u32 num, u8 val);
|
||||||
void MapNWRAM_C(u32 num, u8 val);
|
void MapNWRAM_C(u32 num, u8 val);
|
||||||
void MapNWRAMRange(u32 cpu, u32 num, u32 val);
|
void MapNWRAMRange(u32 cpu, u32 num, u32 val);
|
||||||
|
void SetVRAMTimings(bool extrabuswidth);
|
||||||
|
|
||||||
u8 ARM9Read8(u32 addr) override;
|
u8 ARM9Read8(u32 addr) override;
|
||||||
u16 ARM9Read16(u32 addr) override;
|
u16 ARM9Read16(u32 addr) override;
|
||||||
|
Loading…
Reference in New Issue
Block a user