Compare commits

...

123 Commits

Author SHA1 Message Date
Jakly
fa9dd271e2
Merge 9d92b8708a into 5e8beb3ab7 2024-11-13 18:13:13 +02:00
Nadia Holmquist Pedersen
5e8beb3ab7 fix a typo
Some checks are pending
macOS / ${{ matrix.arch }} (arm64) (push) Waiting to run
macOS / ${{ matrix.arch }} (x86_64) (push) Waiting to run
macOS / Universal binary (push) Blocked by required conditions
Ubuntu / x86_64 (push) Waiting to run
Ubuntu / aarch64 (push) Waiting to run
Windows / build (push) Waiting to run
2024-11-13 15:23:59 +01:00
Jaklyy
9d92b8708a r15 writeback is very weird with ldr/str 2024-11-10 02:56:16 -05:00
Jaklyy
fce0555a09 slightly fix error in writeback handling 2024-11-09 22:07:17 -05:00
Jaklyy
ec241a8224 im smrat :D 2024-11-09 16:18:48 -05:00
Jaklyy
bdc315198f T_LDR_SPREL does ROR + misc cleanup 2024-11-09 16:12:19 -05:00
Jaklyy
e4dd913ba3 arm7 RORs unaligned ldr(s)h
ty mgba discord
2024-11-09 15:38:08 -05:00
Jaklyy
9f8cf8dad2 ldm base writeback fails with r15 2024-11-09 14:49:34 -05:00
Jaklyy
676f471ebe fix edge case with thumb prefetch aborts 2024-11-08 01:36:14 -05:00
Jaklyy
60a819c1ed correct handling of T bit changes w/o pipeline flush on arm9 2024-11-08 01:02:36 -05:00
Jaklyy
5091061a39 improve accuracy of prefetch abort handling slightly
prefetch aborts should be handled on executing an instruction by a flag set when the instruction is fetched
2024-11-07 20:16:19 -05:00
Jaklyy
ef5de6091b t blx long with bit 0 set should raise an exception
fixes a bug with gbarunner3
2024-11-07 13:16:39 -05:00
Jaklyy
3bd6274477 Merge remote-tracking branch 'upstream/master' into interpreter-fixes 2024-11-06 08:27:50 -05:00
Jaklyy
3d49f5f256 arm7 muls carry flag emulation. 2024-11-06 00:18:29 -05:00
Jaklyy
3c7db9b21f correct thumb multiply timings 2024-11-05 21:57:11 -05:00
Jaklyy
5f003eb967 fix builds with jit disabled 2024-10-15 20:23:03 -04:00
Jaklyy
e0e78a2bc8 make empty r-list instructions a bit nicer
pass bools as a single u8 instead and combine thumb and restore cpsr flags since they're mutually exclusive
2024-10-12 11:10:06 -04:00
Jaklyy
787d0c9afc mrc r15 updates flags
also my prior implementation made mrc w/ r15 raise an exception by accident
oops!
2024-10-10 11:09:07 -04:00
Jaklyy
93dce82b07 implement cmp with "rd == 15" on arm9
cmp and friends with bits 12-15 set to 1 borrow characteristics from their legacy 26 bit p variants
thumb version does nothing of note
2024-10-10 10:48:17 -04:00
Jaklyy
3870216fd0 correction: 2024-10-10 03:53:51 -04:00
Jaklyy
53b38c363f ok no it didn't lie to me 2024-10-10 03:32:53 -04:00
Jaklyy
19e0b18d15 Merge remote-tracking branch 'upstream/master' into interpreter-fixes 2024-09-29 22:41:52 -04:00
Jaklyy
a11208ec6d oops 2024-09-24 21:02:17 -04:00
Jaklyy
3065141ed7 probably not faster 2024-09-24 17:04:52 -04:00
Jaklyy
e1d4fbef75 i can't reproduce this anymore 2024-09-24 09:47:32 -04:00
Jaklyy
7fb18b1155 clean up code 2024-09-23 20:03:58 -04:00
Jaklyy
3b73f21bb7 str r15 is incremented by +2/+4 oop 2024-09-23 16:12:23 -04:00
Jaklyy
8af790beee ldm/str with empty rlist 2024-09-23 15:00:35 -04:00
Jaklyy
7b0d71dbbe Revert T bit changing support for arm7
i cannot comprehend what is happening currently
2024-09-22 19:57:33 -04:00
Jaklyy
8d451dff48 misaligned pc.......... 2024-09-20 23:47:40 -04:00
Jaklyy
157e9c5b04 reimplement changing t bit with arm7
kinda slow though?
2024-09-20 13:37:58 -04:00
Jaklyy
7afa805afc slightly better code 2024-09-20 05:37:51 -04:00
Jaklyy
c133814713 some day i will remember to test before pushing 2024-09-20 04:39:16 -04:00
Jaklyy
45f87a1c8d prevent t bit changes without pipeline flush on arm7
idk what's happening fully and its gonna be slow to emulate most likely
we'll figure this out later
2024-09-19 21:02:54 -04:00
Jaklyy
6ebabde392 implement changing thumb bit. and bkpt ig
probably wrong
2024-09-19 04:37:01 -04:00
Jaklyy
89e8549a55 implement comparison instrs w/ rd == 15 2024-09-17 21:01:02 -04:00
Jaklyy
e5654ec541 r15 mrc mrs 2024-09-16 17:50:09 -04:00
Jaklyy
e2f3dd1e6f clarify 2024-09-16 14:34:03 -04:00
Jaklyy
ac8c942565 sat add/sub also fail to jump 2024-09-16 13:17:38 -04:00
Jaklyy
3b9a9e4eb3 multiply instructions can't write to r15 2024-09-16 10:23:15 -04:00
Jaklyy
a0d71135a1 very minor optimization attempt 2024-09-13 07:33:18 -04:00
Jaklyy
c5ac682f04 improve data abort handling further 2024-09-12 18:25:54 -04:00
Jaklyy
f0bd2b9051 Merge remote-tracking branch 'upstream/master' into interpreter-fixes 2024-08-30 19:33:16 -04:00
Jaklyy
0003821738 apparently i never tested this 2024-08-28 22:04:22 -04:00
Jaklyy
685c4828a2 try not forgetting about stores lol 2024-08-28 13:45:46 -04:00
Jaklyy
be290da23c de-duplicate swp(b) 2024-08-27 17:23:18 -04:00
Jaklyy
a9aad74539 implement user mode load/stores 2024-08-26 20:43:27 -04:00
Jaklyy
f692e7391a the docs lied to me (again) 2024-08-26 19:48:42 -04:00
Jaklyy
40e8e8e7bd rework single load/stores to use a shared instruction 2024-08-24 11:46:23 -04:00
Jaklyy
332a39dbaf fix JIT being borked 2024-08-05 16:14:17 -04:00
Jaklyy
a85b2bfb56 tweak when irqs are triggered and fix prefetch aborts
also ig add some comments next to the svc funcs so that someone searching for "swi" can find them easier
2024-08-05 14:57:17 -04:00
Jaklyy
eedd2806f9 Reapply "Improve accuracy of prefetch aborts"
This reverts commit 0dc619d615.
2024-08-05 12:37:42 -04:00
Jaklyy
0dc619d615 Revert "Improve accuracy of prefetch aborts"
This reverts commit 587958e678.
2024-08-05 11:41:25 -04:00
Jaklyy
587958e678 Improve accuracy of prefetch aborts
comes with a small-ish performance hit
2024-08-04 23:31:20 -04:00
Jaklyy
fe69cfac7d Merge remote-tracking branch 'upstream/master' into interpreter-fixes 2024-08-04 21:28:32 -04:00
Jaklyy
346ac1380f forgot to remove a thingy when removing timing reworks 2024-08-04 15:21:23 -04:00
Jaklyy
ab2a8f128f revert timing tweaks, finish thumb interwork code 2024-08-04 14:54:36 -04:00
Jaklyy
4b703d24b5 improve msr timings for arm9 2024-08-03 16:22:14 -04:00
Jaklyy
2e421e29e3 cache should be disabled when pu is disabled 2024-08-03 16:21:17 -04:00
Jaklyy
3c936d84b3 improve mrs, mrc timings 2024-08-03 16:20:50 -04:00
Jaklyy
7cd50e7b56 fix some multiply timings 2024-07-19 17:56:43 -04:00
Jaklyy
13578a3cc9 Revert "improve timings for S variants of multiply instructions on arm9"
This reverts commit 789ef21c70.
2024-07-19 17:52:28 -04:00
Jaklyy
36f4f2c5d3 Revert "improve timings further"
This reverts commit 764ee9ea1a.
2024-07-19 17:52:26 -04:00
Jaklyy
4f6db5a173 Merge remote-tracking branch 'upstream/master' into jump-after-writeback 2024-07-17 21:42:21 -04:00
Jaklyy
764ee9ea1a improve timings further 2024-07-13 09:35:12 -04:00
Jaklyy
789ef21c70 improve timings for S variants of multiply instructions on arm9
behavior seems to be a quirk of the way they made the interlock cycle mandatory
2024-07-12 23:11:46 -04:00
Jaklyy
4fcd52ed16 someday i will learn to test things before pushing them 2024-07-11 20:19:25 -04:00
Jaklyy
038ffa3a35 revert the *entire* interlock implemention
too slow, not accurate enough.
we need to do a *lot* more research into the specifics of how this works with all the various aspects of the cpu's timings before we can make a good implementation
2024-07-11 20:08:35 -04:00
Jaklyy
1fdac1d489 ...why am i checking for dtcm? 2024-07-11 16:18:55 -04:00
Jaklyy
e2be0b4f93 actually no it was not more correct
undo previous commit because actually code cycles *do* matter
2024-07-07 15:42:10 -04:00
Jaklyy
383750692e doesn't really matter but idk it's more correct? 2024-07-06 12:38:39 -04:00
Jaklyy
0f02c0bbba disable interlock emulation again again
our understanding of how it works is just too incomplete to be worth implementing yet
2024-07-06 12:14:35 -04:00
Jaklyy
ea429a1b8d improve interlock emulation
add cycles to the instruction execution time rather than the timestamp directly.
2024-07-04 12:58:58 -04:00
Jaklyy
bd1665c1d3 minor timing tweaks 2024-07-04 12:41:09 -04:00
Jaklyy
a549977eb0 fix clz for realsies 2024-07-04 11:04:38 -04:00
Jaklyy
0060958fed Merge remote-tracking branch 'upstream/master' into jump-after-writeback 2024-07-03 15:26:58 -04:00
Jaklyy
88e5584b5f fix clz r15 2024-06-27 15:33:24 -04:00
Jaklyy
c5b035a973 SWP and SWPB use the same behavior as STR on the ARM9 2024-06-25 11:20:01 -04:00
Jaklyy
541e1e6388 proper timings for ldr/str 2024-06-25 09:08:11 -04:00
Jaklyy
dbe00e72dd improve stm timings
need to verify if they apply to all store instructions
2024-06-24 22:50:04 -04:00
Jaklyy
109bbed3d0 improve ldm timings
I believe this also applies to other loads as well, but currently untested.
2024-06-24 20:22:38 -04:00
Jaklyy
3583d8222f disable interlock emulation, needs more research 2024-06-24 16:17:04 -04:00
Jaklyy
f1b71fe5a9 implement configurable vram bus width
not implemented for direct boot
2024-06-24 16:15:04 -04:00
Jaklyy
e6ba4075b9 correct interlocked reg for umlal 2024-06-18 11:12:05 -04:00
Jaklyy
c5258d6377 verify interlocks for alu and load/store
remove some checks for interlock that im pretty sure can't trigger
2024-06-17 18:07:53 -04:00
Jaklyy
a9e2c7e047 implement two regs i missed 2024-06-16 23:24:20 -04:00
Jaklyy
f00f1f6ca4 im smart 2024-06-16 20:50:42 -04:00
Jaklyy
5b37ca70d1 implement correct/guess interlocks for remaining instructions 2024-06-16 20:47:01 -04:00
Jaklyy
debaaa0425 fix performance regression for disabling interlock emulation path 2024-06-15 21:16:12 -04:00
Jaklyy
449557624d don't do interlocks for the arm7 2024-06-15 18:37:31 -04:00
Jaklyy
a973c0bf5b initial implementation of interlock cycles 2024-06-15 16:07:36 -04:00
Jaklyy
aa1217af0a track interlock cycles for the ALU 2024-06-14 11:47:42 -04:00
Jaklyy
5a174a2ce3 track interlock cycles for load instructions 2024-06-14 00:51:55 -04:00
Jaklyy
42218106b0 verify writable msr bits 2024-06-11 10:30:30 -04:00
Jaklyy
048b0b8878 swp/swpb jumps work on the arm 7? 2024-06-10 18:03:56 -04:00
Jaklyy
3ddccde5b9 verified
also remove no longer needed variable
2024-06-10 13:23:18 -04:00
Jaklyy
ca04710deb ldrd is just ldm 2024-06-09 22:31:10 -04:00
Jaklyy
ae0824fdd3 it all makes sense now... 2024-06-09 19:10:43 -04:00
Jaklyy
b90d5c2320 what the actual F*** is going on 2024-06-09 12:18:31 -04:00
Jaklyy
be60c68aeb more weirdness 2024-06-09 07:25:42 -04:00
Jaklyy
b846c6f100 remove out of date comments 2024-06-08 22:17:07 -04:00
Jaklyy
849d4e51ac imma be real, i have no idea what is going on here 2024-06-08 22:12:44 -04:00
Jaklyy
659763f903 clarification 2024-06-08 16:15:02 -04:00
Jaklyy
3699768ac9 most cpsr bits can't actually be updated (or at least can't be read?) 2024-06-08 14:01:54 -04:00
Jaklyy
5f97dfc1ab fix bits fixed to 0 for pu region sizing being set 2024-06-08 10:53:22 -04:00
Jaklyy
8191f92bb6 mcr is also affected 2024-06-08 10:42:19 -04:00
Jaklyy
0c887202e7 fix some more instructions? 2024-06-08 10:40:23 -04:00
Jaklyy
73507621f5 idk why it took me two tries to get these instructions to work properly 2024-06-07 23:50:31 -04:00
Jaklyy
2b0ed459e1 fully implement r15 stores being +12 of addr 2024-06-07 23:46:49 -04:00
Jaklyy
bd3611b51d unaligned registers with strd/ldrd raise an exception 2024-06-07 20:43:02 -04:00
Jaklyy
8bc7e4591c thumb ldmia/pop data aborts 2024-06-06 19:05:28 -04:00
Jaklyy
d6cd189455 rework data abort handling for ldm/stm; implement thumb stmia+push 2024-06-06 18:58:43 -04:00
Jaklyy
13ae96b4e3 simple thumb instructions (untested but probably right) 2024-06-05 14:32:12 -04:00
Jaklyy
7c3108e20f handle swp instruction aborts 2024-06-05 14:31:44 -04:00
Jaklyy
1871c48849 fix double data aborts with strd 2024-06-05 10:28:51 -04:00
Jaklyy
317a8c61e5 data abort handling for (almost) all (arm) instructions
full list: strb, ldrb, strh, ldrd, strd, ldrh, ldrsb, ldrsh
2024-06-05 00:14:14 -04:00
Jaklyy
1e8194e367 fix ldr and str 2024-06-04 19:06:54 -04:00
Jaklyy
c2a57b79a0 fix stmd(a/b) writeback 2024-06-02 22:41:01 -04:00
Jaklyy
5e760a1536 slightly cleaner code 2024-06-02 19:34:29 -04:00
Jaklyy
b5c1ee33fb implement stm 2024-06-02 10:33:29 -04:00
Jaklyy
63d4b78733 improve implementation 2024-06-02 10:13:50 -04:00
Jaklyy
960f063eaa improve data aborts for ldm 2024-06-02 00:11:01 -04:00
Jaklyy
065573f316 fix writebacks overwriting registers swapped with spsr
fixes gbarunner3
2024-05-31 18:09:45 -04:00
15 changed files with 1075 additions and 473 deletions

View File

@ -47,7 +47,7 @@
1. Install Qt: `pacman -S <prefix>-{qt6-base,qt6-svg,qt6-multimedia,qt6-svg,qt6-tools}`
2. Set up the build directory with `cmake -B build`
* Static builds (without DLLs, standalone executable)
1. Install Qt: `pacman -S <prefi>-qt5-static`
1. Install Qt: `pacman -S <prefix>-qt5-static`
(Note: As of writing, the `qt6-static` package does not work.)
2. Set up the build directory with `cmake -B build -DBUILD_STATIC=ON -DUSE_QT6=OFF -DCMAKE_PREFIX_PATH=$MSYSTEM_PREFIX/qt5-static`
7. Compile: `cmake --build build`

View File

@ -222,7 +222,7 @@ void ARM::DoSavestate(Savestate* file)
file->VarArray(R_ABT, 3*sizeof(u32));
file->VarArray(R_IRQ, 3*sizeof(u32));
file->VarArray(R_UND, 3*sizeof(u32));
file->Var32(&CurInstr);
file->Var64(&CurInstr);
#ifdef JIT_ENABLED
if (file->Saving && NDS.IsJITEnabled())
{
@ -232,7 +232,7 @@ void ARM::DoSavestate(Savestate* file)
FillPipeline();
}
#endif
file->VarArray(NextInstr, 2*sizeof(u32));
file->VarArray(NextInstr, 2*sizeof(u64));
file->Var32(&ExceptionBase);
@ -344,12 +344,6 @@ void ARMv5::JumpTo(u32 addr, bool restorecpsr)
CPSR &= ~0x20;
}
if (!(PU_Map[addr>>12] & 0x04))
{
PrefetchAbort();
return;
}
NDS.MonitorARM9Jump(addr);
}
@ -518,6 +512,7 @@ void ARM::UpdateMode(u32 oldmode, u32 newmode, bool phony)
}
}
template <CPUExecuteMode mode>
void ARM::TriggerIRQ()
{
if (CPSR & 0x80)
@ -529,7 +524,12 @@ void ARM::TriggerIRQ()
UpdateMode(oldcpsr, CPSR);
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);
// ARDS cheat support
@ -540,6 +540,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()
{
@ -550,17 +555,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);
}
@ -599,7 +595,13 @@ void ARMv5::Execute()
{
Halted = 0;
if (NDS.IME[0] & 0x1)
TriggerIRQ();
{
#ifdef JIT_ENABLED
if constexpr (mode == CPUExecuteMode::JIT) TriggerIRQ<mode>();
else
#endif
IRQ = 1;
}
}
else
{
@ -634,7 +636,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)
{
@ -662,10 +664,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 (CurInstr > 0xFFFFFFFF) [[unlikely]] // handle aborted instructions
{
PrefetchAbort();
}
else [[likely]] // actually execute
{
u32 icode = (CurInstr >> 6) & 0x3FF;
ARMInterpreter::THUMBInstrTable[icode](this);
}
}
else
{
@ -677,9 +687,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 (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);
ARMInterpreter::ARMInstrTable[icode](this);
@ -688,6 +703,10 @@ void ARMv5::Execute()
{
ARMInterpreter::A_BLX_IMM(this);
}
else if ((CurInstr & 0x0FF000F0) == 0x01200070)
{
ARMInterpreter::A_BKPT(this); // always passes regardless of condition code
}
else
AddCycles_C();
}
@ -704,10 +723,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;
@ -739,7 +756,10 @@ void ARMv4::Execute()
{
Halted = 0;
if (NDS.IME[1] & 0x1)
TriggerIRQ();
{
if constexpr (mode == CPUExecuteMode::JIT) TriggerIRQ<mode>();
else IRQ = 1;
}
}
else
{
@ -773,7 +793,7 @@ void ARMv4::Execute()
if (StopExecution)
{
if (IRQ)
TriggerIRQ();
TriggerIRQ<mode>();
if (Halted || IdleLoop)
{
@ -801,9 +821,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
{
@ -816,8 +840,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);
@ -838,9 +862,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;
@ -1113,70 +1136,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)
{
addr &= ~3;
BusWrite32(addr, val);
DataCycles += NDS.ARM7MemTimings[addr >> 15][3];
return true;
}

View File

@ -128,19 +128,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) = 0;
virtual void AddCycles_C() = 0;
virtual void AddCycles_CI(s32 numI) = 0;
@ -176,8 +177,8 @@ public:
u32 R_ABT[3];
u32 R_IRQ[3];
u32 R_UND[3];
u32 CurInstr;
u32 NextInstr[2];
u64 CurInstr;
u64 NextInstr[2];
u32 ExceptionBase;
@ -250,16 +251,16 @@ public:
void Execute();
// 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;
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) override;
void AddCycles_C() override
{
@ -399,18 +400,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) 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;

View File

@ -69,6 +69,14 @@ void T_UNK(ARM* cpu)
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)
@ -90,7 +98,8 @@ void A_MSR_IMM(ARM* cpu)
case 0x1A:
case 0x1B: psr = &cpu->R_UND[2]; break;
default:
cpu->AddCycles_C();
if (cpu->Num != 1) cpu->AddCycles_C(); // arm 7
else cpu->AddCycles_CI(2); // arm 9
return;
}
}
@ -101,12 +110,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<<22)))
mask &= 0xFFFFFFDF;
//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->CPSR & 0x1F) == 0x10) mask &= 0xFFFFFF00;
@ -121,7 +127,26 @@ void A_MSR_IMM(ARM* cpu)
if (!(cpu->CurInstr & (1<<22)))
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)
@ -143,7 +168,8 @@ void A_MSR_REG(ARM* cpu)
case 0x1A:
case 0x1B: psr = &cpu->R_UND[2]; break;
default:
cpu->AddCycles_C();
if (cpu->Num != 1) cpu->AddCycles_C(); // arm 7
else cpu->AddCycles_CI(2); // arm 9
return;
}
}
@ -154,12 +180,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<<22)))
mask &= 0xFFFFFFDF;
//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->CPSR & 0x1F) == 0x10) mask &= 0xFFFFFF00;
@ -174,7 +197,26 @@ void A_MSR_REG(ARM* cpu)
if (!(cpu->CurInstr & (1<<22)))
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)
@ -201,8 +243,15 @@ void A_MRS(ARM* cpu)
else
psr = cpu->CPSR;
cpu->R[(cpu->CurInstr>>12) & 0xF] = psr;
cpu->AddCycles_C();
if (((cpu->CurInstr>>12) & 0xF) == 15)
{
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 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)
{
@ -244,10 +295,17 @@ void A_MRC(ARM* cpu)
u32 cn = (cpu->CurInstr >> 16) & 0xF;
u32 cm = cpu->CurInstr & 0xF;
u32 cpinfo = (cpu->CurInstr >> 5) & 0x7;
u32 rd = (cpu->CurInstr>>12) & 0xF;
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)
{
@ -259,12 +317,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 +335,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;

View File

@ -36,6 +36,7 @@ void A_MRS(ARM* cpu);
void A_MCR(ARM* cpu);
void A_MRC(ARM* cpu);
void A_SVC(ARM* cpu);
void A_BKPT(ARM* cpu);
void T_SVC(ARM* cpu);

View File

@ -19,6 +19,7 @@
#include <stdio.h>
#include "ARM.h"
#include "NDS.h"
#include "ARMInterpreter_MultiplySuperLLE.h"
namespace melonDS::ARMInterpreter
{
@ -581,8 +582,27 @@ A_IMPLEMENT_ALU_OP(RSC,)
#define A_TST(c) \
u32 a = cpu->R[(cpu->CurInstr>>16) & 0xF]; \
u32 res = a & b; \
cpu->SetNZ(res & 0x80000000, \
!res); \
if (((cpu->CurInstr>>12) & 0xF) == 15) [[unlikely]] /* this seems to trigger alu rd==15 behavior for arm7 and legacy instruction behavior for arm9 */ \
{ \
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();
A_IMPLEMENT_ALU_TEST(TST,_S)
@ -591,8 +611,27 @@ A_IMPLEMENT_ALU_TEST(TST,_S)
#define A_TEQ(c) \
u32 a = cpu->R[(cpu->CurInstr>>16) & 0xF]; \
u32 res = a ^ b; \
cpu->SetNZ(res & 0x80000000, \
!res); \
if (((cpu->CurInstr>>12) & 0xF) == 15) [[unlikely]] /* this seems to trigger alu rd==15 behavior for arm7 and legacy instruction behavior for arm9 */ \
{ \
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();
A_IMPLEMENT_ALU_TEST(TEQ,_S)
@ -601,10 +640,31 @@ A_IMPLEMENT_ALU_TEST(TEQ,_S)
#define A_CMP(c) \
u32 a = cpu->R[(cpu->CurInstr>>16) & 0xF]; \
u32 res = a - b; \
cpu->SetNZCV(res & 0x80000000, \
!res, \
CarrySub(a, b), \
OverflowSub(a, b)); \
if (((cpu->CurInstr>>12) & 0xF) == 15) [[unlikely]] /* this seems to trigger alu rd==15 behavior for arm7 and legacy instruction behavior for arm9 */ \
{ \
if (cpu->Num == 1) \
{ \
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();
A_IMPLEMENT_ALU_TEST(CMP,)
@ -613,10 +673,31 @@ A_IMPLEMENT_ALU_TEST(CMP,)
#define A_CMN(c) \
u32 a = cpu->R[(cpu->CurInstr>>16) & 0xF]; \
u32 res = a + b; \
cpu->SetNZCV(res & 0x80000000, \
!res, \
CarryAdd(a, b), \
OverflowAdd(a, b)); \
if (((cpu->CurInstr>>12) & 0xF) == 15) [[unlikely]] /* this seems to trigger alu rd==15 behavior for arm7 and legacy instruction behavior for arm9 */ \
{ \
if (cpu->Num == 1) \
{ \
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();
A_IMPLEMENT_ALU_TEST(CMN,)
@ -766,12 +847,14 @@ void A_MUL(ARM* cpu)
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))
{
cpu->SetNZ(res & 0x80000000,
!res);
if (cpu->Num==1) cpu->SetC(0);
}
u32 cycles;
@ -783,6 +866,7 @@ void A_MUL(ARM* cpu)
else if ((rs & 0xFFFF0000) == 0x00000000 || (rs & 0xFFFF0000) == 0xFFFF0000) cycles = 2;
else if ((rs & 0xFF000000) == 0x00000000 || (rs & 0xFF000000) == 0xFF000000) cycles = 3;
else cycles = 4;
if (cpu->CurInstr & (1<<20)) cpu->SetC(MULSCarry(rm, rs, 0, cycles==4));
}
cpu->AddCycles_CI(cycles);
@ -795,13 +879,14 @@ void A_MLA(ARM* cpu)
u32 rn = cpu->R[(cpu->CurInstr >> 12) & 0xF];
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))
{
cpu->SetNZ(res & 0x80000000,
!res);
if (cpu->Num==1) cpu->SetC(0);
}
u32 cycles;
@ -813,6 +898,7 @@ void A_MLA(ARM* cpu)
else if ((rs & 0xFFFF0000) == 0x00000000 || (rs & 0xFFFF0000) == 0xFFFF0000) cycles = 3;
else if ((rs & 0xFF000000) == 0x00000000 || (rs & 0xFF000000) == 0xFF000000) cycles = 4;
else cycles = 5;
if (cpu->CurInstr & (1<<20)) cpu->SetC(MULSCarry(rm, rs, rn, cycles==5));
}
cpu->AddCycles_CI(cycles);
@ -825,24 +911,27 @@ void A_UMULL(ARM* cpu)
u64 res = (u64)rm * (u64)rs;
cpu->R[(cpu->CurInstr >> 12) & 0xF] = (u32)res;
cpu->R[(cpu->CurInstr >> 16) & 0xF] = (u32)(res >> 32ULL);
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);
if (cpu->CurInstr & (1<<20))
{
cpu->SetNZ((u32)(res >> 63ULL),
!res);
if (cpu->Num==1) cpu->SetC(0);
}
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;
else if ((rs & 0xFFFF0000) == 0x00000000) cycles = 3;
else if ((rs & 0xFF000000) == 0x00000000) cycles = 4;
else cycles = 5;
if (cpu->CurInstr & (1<<20)) cpu->SetC(UMULLSCarry(0, rm, rs, cycles==5));
}
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);
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))
{
cpu->SetNZ((u32)(res >> 63ULL),
!res);
if (cpu->Num==1) cpu->SetC(0);
}
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;
else if ((rs & 0xFFFF0000) == 0x00000000) cycles = 3;
else if ((rs & 0xFF000000) == 0x00000000) cycles = 4;
else cycles = 5;
if (cpu->CurInstr & (1<<20)) cpu->SetC(UMULLSCarry(rd, rm, rs, cycles==5));
}
cpu->AddCycles_CI(cycles);
@ -887,25 +979,28 @@ void A_SMULL(ARM* cpu)
u32 rs = cpu->R[(cpu->CurInstr >> 8) & 0xF];
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))
{
cpu->SetNZ((u32)(res >> 63ULL),
!res);
if (cpu->Num==1) cpu->SetC(0);
}
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;
else if ((rs & 0xFFFF0000) == 0x00000000 || (rs & 0xFFFF0000) == 0xFFFF0000) cycles = 3;
else if ((rs & 0xFF000000) == 0x00000000 || (rs & 0xFF000000) == 0xFF000000) cycles = 4;
else cycles = 5;
if (cpu->CurInstr & (1<<20)) cpu->SetC(SMULLSCarry(0, rm, rs, cycles==5));
}
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));
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))
{
cpu->SetNZ((u32)(res >> 63ULL),
!res);
if (cpu->Num==1) cpu->SetC(0);
}
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;
else if ((rs & 0xFFFF0000) == 0x00000000 || (rs & 0xFFFF0000) == 0xFFFF0000) cycles = 3;
else if ((rs & 0xFF000000) == 0x00000000 || (rs & 0xFF000000) == 0xFF000000) cycles = 4;
else cycles = 5;
if (cpu->CurInstr & (1<<20)) cpu->SetC(SMULLSCarry(rd, rm, rs, cycles==5));
}
cpu->AddCycles_CI(cycles);
@ -959,8 +1057,10 @@ void A_SMLAxy(ARM* cpu)
u32 res_mul = ((s16)rm * (s16)rs);
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))
cpu->CPSR |= 0x08000000;
@ -980,8 +1080,9 @@ void A_SMLAWy(ARM* cpu)
u32 res_mul = ((s64)(s32)rm * (s16)rs) >> 16;
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))
cpu->CPSR |= 0x08000000;
@ -1001,8 +1102,9 @@ void A_SMULxy(ARM* cpu)
else rs &= 0xFFFF;
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??
}
@ -1017,8 +1119,9 @@ void A_SMULWy(ARM* cpu)
else rs &= 0xFFFF;
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??
}
@ -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));
res += rd;
cpu->R[(cpu->CurInstr >> 12) & 0xF] = (u32)res;
cpu->R[(cpu->CurInstr >> 16) & 0xF] = (u32)(res >> 32ULL);
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->AddCycles_CI(1); // TODO: interlock??
}
@ -1067,7 +1173,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();
}
@ -1085,7 +1192,10 @@ void A_QADD(ARM* cpu)
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??
}
@ -1102,8 +1212,10 @@ void A_QSUB(ARM* cpu)
res = (res & 0x80000000) ? 0x7FFFFFFF : 0x80000000;
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??
}
@ -1128,8 +1240,10 @@ void A_QDADD(ARM* cpu)
res = (res & 0x80000000) ? 0x7FFFFFFF : 0x80000000;
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??
}
@ -1154,8 +1268,10 @@ void A_QDSUB(ARM* cpu)
res = (res & 0x80000000) ? 0x7FFFFFFF : 0x80000000;
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??
}
@ -1460,18 +1576,18 @@ void T_MUL_REG(ARM* cpu)
cpu->SetNZ(res & 0x80000000,
!res);
s32 cycles = 0;
s32 cycles;
if (cpu->Num == 0)
{
cycles += 3;
cycles = 3;
}
else
{
cpu->SetC(0); // carry flag destroyed, they say. whatever that means...
if (a & 0xFF000000) cycles += 4;
else if (a & 0x00FF0000) cycles += 3;
else if (a & 0x0000FF00) cycles += 2;
else cycles += 1;
if ((a & 0xFFFFFF00) == 0x00000000 || (a & 0xFFFFFF00) == 0xFFFFFF00) cycles = 1;
else if ((a & 0xFFFF0000) == 0x00000000 || (a & 0xFFFF0000) == 0xFFFF0000) cycles = 2;
else if ((a & 0xFF000000) == 0x00000000 || (a & 0xFF000000) == 0xFF000000) cycles = 3;
else cycles = 4;
cpu->SetC(MULSCarry(b, a, 0, cycles==4)); // carry flag destroyed, they say. whatever that means...
}
cpu->AddCycles_CI(cycles);
}
@ -1534,6 +1650,18 @@ void T_CMP_HIREG(ARM* cpu)
!res,
CarrySub(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();
}

View File

@ -104,6 +104,9 @@ void T_BL_LONG_1(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;
u32 pc = cpu->R[14] + offset;
cpu->R[14] = (cpu->R[15] - 2) | 1;

File diff suppressed because it is too large Load Diff

View 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

View File

@ -588,7 +588,7 @@ void ARMJIT::CompileBlock(ARM* cpu) noexcept
u32 numWriteAddrs = 0, writeAddrsTranslated = 0;
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};
JIT_DEBUGPRINT("start block %x %08x (%x)\n", blockAddr, cpu->CPSR, localAddr);

View File

@ -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_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_REG = A_Read0 | ak(ak_MSR_REG);
const u32 A_MRS = A_Write12 | ak(ak_MRS);

View File

@ -130,7 +130,7 @@ INSTRFUNC_PROTO(ARMInstrTable[4096]) =
// 0001 0010 0000
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_LDRD_REG, A_SMULWy, A_STRD_REG,

View File

@ -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),
@ -773,16 +771,15 @@ u32 ARMv5::CP15Read(u32 id) const
// TCM are handled here.
// 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))
{
PrefetchAbort();
return 0;
}
}*/
CodeCycles = 1;
return ((u64)1<<63);
}
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();
return;
DataCycles = 1;
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))
// Data Aborts
// Exception is handled in the actual instruction implementation
if (!(PU_Map[addr>>12] & 0x01)) [[unlikely]]
{
DataAbort();
return;
DataCycles = 1;
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))
// Data Aborts
// Exception is handled in the actual instruction implementation
if (!(PU_Map[addr>>12] & 0x01)) [[unlikely]]
{
DataAbort();
return;
DataCycles = 1;
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)
{
// Data Aborts
// Exception is handled in the actual instruction implementation
if (!(PU_Map[addr>>12] & 0x01)) [[unlikely]]
{
DataCycles += 1;
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))
// Data Aborts
// Exception is handled in the actual instruction implementation
if (!(PU_Map[addr>>12] & 0x02)) [[unlikely]]
{
DataAbort();
return;
DataCycles = 1;
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))
// Data Aborts
// Exception is handled in the actual instruction implementation
if (!(PU_Map[addr>>12] & 0x02)) [[unlikely]]
{
DataAbort();
return;
DataCycles = 1;
return false;
}
DataRegion = addr;
addr &= ~1;
if (addr < ITCMSize)
@ -958,29 +968,30 @@ 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))
// Data Aborts
// Exception is handled in the actual instruction implementation
if (!(PU_Map[addr>>12] & 0x02)) [[unlikely]]
{
DataAbort();
return;
DataCycles = 1;
return false;
}
DataRegion = addr;
addr &= ~3;
if (addr < ITCMSize)
@ -988,21 +999,30 @@ 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)
{
// Data Aborts
// Exception is handled in the actual instruction implementation
if (!(PU_Map[addr>>12] & 0x02)) [[unlikely]]
{
DataCycles += 1;
return false;
}
addr &= ~3;
if (addr < ITCMSize)
@ -1012,17 +1032,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)

View File

@ -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:

View File

@ -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;