IOS LLE: execute ARMv5TE enhanced DSP instructions (StarletOS phase 11 I1)
SMLAxy, SMLAWy, SMULWy, SMLALxy, SMULxy, QADD, QSUB, QDADD and QDSUB were decoded as compare data processing that writes no register; the ARM926EJ-S implements them. The interpreter now executes them with the Q flag and the JIT leaves them to it. Adds ARMv5TEEnhancedDSPInstructions. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
ba5b6de0d0
commit
3d12571127
6 files changed
+209
-7
No files matched your search
@@ -1755,6 +1755,83 @@ TEST(StarletARMCore, ARMJitCompilesLongMultiplyFamily)
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(StarletARMCore, ARMv5TEEnhancedDSPInstructions)
|
||||
{
|
||||
// StarletOS phase 11 (I1): encodings from GNU as (-march=armv5te); results from the ARM
|
||||
// Architecture Reference Manual. r0 = Rm, r1 = Rs or Rn, r7 = accumulator, r3/r4 results.
|
||||
struct Case
|
||||
{
|
||||
u32 instruction;
|
||||
u32 r0;
|
||||
u32 r1;
|
||||
u32 r3;
|
||||
u32 r4;
|
||||
u32 r7;
|
||||
u32 expected_r3;
|
||||
u32 expected_r4;
|
||||
bool expected_q;
|
||||
};
|
||||
constexpr std::array cases = {
|
||||
// smlabb r4, r0, r1, r7: a 88-byte entry 9 of a table (Revolution's RAM layer).
|
||||
Case{0xe1047180, 9, 88, 0, 0, 0x13780000, 0, 0x13780318, false},
|
||||
Case{0xe1640180, 0xffff0003, 0x0002fffe, 0, 0, 0, 0, 0xfffffffa, false}, // smulbb
|
||||
Case{0xe16401a0, 0xffff0003, 0x0002fffe, 0, 0, 0, 0, 2, false}, // smultb
|
||||
// smlatt r4, r0, r1, r7: 0x3fff0001 + 0x7fffffff overflows, wraps and sets Q.
|
||||
Case{0xe10471e0, 0x7fff0000, 0x7fff0000, 0, 0, 0x7fffffff, 0, 0xbfff0000, true},
|
||||
Case{0xe1247180, 0x00020000, 0x00000003, 0, 0, 10, 0, 16, false}, // smlawb
|
||||
Case{0xe12401e0, 0xfffe0000, 0x00030000, 0, 0, 0, 0, 0xfffffffa, false}, // smulwt
|
||||
// smlalbb r3, r4, r0, r1: 0x00000000_ffffffff + 1 carries into RdHi.
|
||||
Case{0xe1443180, 1, 1, 0xffffffff, 0, 0, 0, 1, false},
|
||||
Case{0xe1014050, 0x7fffffff, 1, 0, 0, 0, 0, 0x7fffffff, true}, // qadd
|
||||
Case{0xe1214050, 0x80000000, 1, 0, 0, 0, 0, 0x80000000, true}, // qsub
|
||||
Case{0xe1414050, 1, 0x40000000, 0, 0, 0, 0, 0x7fffffff, true}, // qdadd
|
||||
Case{0xe1614050, 0, 3, 0, 0, 0, 0, 0xfffffffa, false}, // qdsub
|
||||
};
|
||||
|
||||
for (const Case& test : cases)
|
||||
{
|
||||
TestBus interpreter_bus;
|
||||
ARMCore interpreter(interpreter_bus);
|
||||
#if defined(_M_X86_64)
|
||||
TestBus jit_bus;
|
||||
ARMCore jit(jit_bus);
|
||||
std::array<ARMCore*, 2> cores = {&interpreter, &jit};
|
||||
jit_bus.WriteARM(0, test.instruction);
|
||||
jit_bus.WriteARM(4, 0xeafffffe); // b .
|
||||
#else
|
||||
std::array<ARMCore*, 1> cores = {&interpreter};
|
||||
#endif
|
||||
interpreter_bus.WriteARM(0, test.instruction);
|
||||
interpreter_bus.WriteARM(4, 0xeafffffe); // b .
|
||||
for (ARMCore* core : cores)
|
||||
{
|
||||
core->SetCPSR(static_cast<u32>(ARMCore::Mode::System));
|
||||
core->SetRegister(0, test.r0);
|
||||
core->SetRegister(1, test.r1);
|
||||
core->SetRegister(3, test.r3);
|
||||
core->SetRegister(4, test.r4);
|
||||
core->SetRegister(7, test.r7);
|
||||
core->SetRegister(15, 0);
|
||||
}
|
||||
#if defined(_M_X86_64)
|
||||
jit.SetJitEnabled(true);
|
||||
#endif
|
||||
for (ARMCore* core : cores)
|
||||
{
|
||||
ASSERT_EQ(core->RunCycles(2), 2u);
|
||||
EXPECT_EQ(core->GetRegister(4), test.expected_r4) << std::hex << test.instruction;
|
||||
if (test.instruction == 0xe1443180)
|
||||
EXPECT_EQ(core->GetRegister(3), test.expected_r3);
|
||||
EXPECT_EQ((core->GetCPSR() & ARMCore::CPSR_Q) != 0, test.expected_q)
|
||||
<< std::hex << test.instruction;
|
||||
// The DSP instruction must not touch the condition flags (it is not a compare).
|
||||
EXPECT_EQ(core->GetCPSR() & (ARMCore::CPSR_N | ARMCore::CPSR_Z | ARMCore::CPSR_C |
|
||||
ARMCore::CPSR_V),
|
||||
0u);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StarletARMCore, FCSESwitchPreservesTaggedTLBTranslations)
|
||||
{
|
||||
TestBus bus(0x10000);
|
||||
|
||||
Reference in new issue
Block a user