IOS: optimize Starlet LLE and accurate CPU cache
Retain ARM926 FCSE translations, accelerate common Starlet JIT blocks and cache sparse Hollywood register reads. Inline the hot Broadway write-back cache path while preserving exact cache miss, locking and split-access behavior.
This commit is contained in:
@@ -83,8 +83,7 @@ public:
|
||||
if (offset + 3 >= SRAM_SIZE)
|
||||
return 0;
|
||||
const u8* const sram = SRAMData();
|
||||
return (static_cast<u32>(sram[offset]) << 24) |
|
||||
(static_cast<u32>(sram[offset + 1]) << 16) |
|
||||
return (static_cast<u32>(sram[offset]) << 24) | (static_cast<u32>(sram[offset + 1]) << 16) |
|
||||
(static_cast<u32>(sram[offset + 2]) << 8) | sram[offset + 3];
|
||||
}
|
||||
const size_t offset = ToOffset(address);
|
||||
@@ -197,8 +196,7 @@ public:
|
||||
{
|
||||
EXPECT_LT(offset + 3, SRAM_SIZE);
|
||||
const u8* const sram = SRAMData();
|
||||
return (static_cast<u32>(sram[offset]) << 24) |
|
||||
(static_cast<u32>(sram[offset + 1]) << 16) |
|
||||
return (static_cast<u32>(sram[offset]) << 24) | (static_cast<u32>(sram[offset + 1]) << 16) |
|
||||
(static_cast<u32>(sram[offset + 2]) << 8) | sram[offset + 3];
|
||||
}
|
||||
|
||||
@@ -288,6 +286,73 @@ TEST(WiiIPCCtrlRegister, ProducerBitsRemainLatchedUntilPeerAcknowledges)
|
||||
EXPECT_EQ(control.ppc() & 0x06, 0x00);
|
||||
}
|
||||
|
||||
TEST(StarletSRAM, WideAccessesPreserveAliasesSplitMappingAndBoot0Protection)
|
||||
{
|
||||
constexpr u32 sram_low = StarletMemory::SRAM_BASE;
|
||||
constexpr u32 sram_high = StarletMemory::SRAM_MIRROR_BASE;
|
||||
constexpr u32 hardware_srnprot = 0x0d800060;
|
||||
constexpr u32 sram_split_mode = 1U << 5;
|
||||
Core::DeclareAsCPUThread();
|
||||
auto& system = Core::System::GetInstance();
|
||||
system.GetWiiIPC().Reset();
|
||||
StarletMemory memory(system);
|
||||
memory.Reset();
|
||||
|
||||
memory.Write32(sram_low + 0x20, 0x11223344);
|
||||
EXPECT_EQ(memory.Read32(sram_high + 0x20), 0x11223344u);
|
||||
memory.Write16(sram_high + 0x24, 0xa1b2);
|
||||
EXPECT_EQ(memory.Read16(sram_low + 0x24), 0xa1b2u);
|
||||
memory.Write8(sram_low + 0x26, 0x5a);
|
||||
EXPECT_EQ(memory.Read8(sram_high + 0x26), 0x5au);
|
||||
|
||||
// With the reset (non-split) mapping, boot0 overlays the upper half of the top aperture.
|
||||
const u32 boot0_word = memory.Read32(0xffff0020);
|
||||
memory.Write32(0xffff0020, 0xdeadbeef);
|
||||
EXPECT_EQ(memory.Read32(0xffff0020), boot0_word);
|
||||
|
||||
memory.Write32(hardware_srnprot, sram_split_mode);
|
||||
memory.Write32(sram_low + 0x20, 0x55667788); // Logical page zero now selects SRAM B.
|
||||
EXPECT_EQ(memory.Read32(sram_high + 0x20), 0x55667788u);
|
||||
EXPECT_EQ(memory.Read32(0xffff0020), 0x11223344u); // Upper aperture selects SRAM A.
|
||||
memory.Write32(0xffff0020, 0xaabbccdd);
|
||||
|
||||
// The split gap remains unmapped and ignores writes.
|
||||
memory.Write32(sram_high + 0x8000, 0xcafebabe);
|
||||
EXPECT_EQ(memory.Read32(sram_high + 0x8000), 0u);
|
||||
|
||||
memory.Write32(hardware_srnprot, 0);
|
||||
EXPECT_EQ(memory.Read32(sram_low + 0x20), 0xaabbccddu);
|
||||
}
|
||||
|
||||
TEST(StarletRegisters, CachePreservesSparseValuesAndCollisions)
|
||||
{
|
||||
constexpr u32 address_a = 0x0d900100;
|
||||
constexpr u32 address_b = address_a ^ 0x1001;
|
||||
constexpr auto cache_index = [](u32 address) { return (address ^ (address >> 12)) & 0xfff; };
|
||||
static_assert(cache_index(address_a) == cache_index(address_b));
|
||||
|
||||
Core::DeclareAsCPUThread();
|
||||
auto& system = Core::System::GetInstance();
|
||||
system.GetWiiIPC().Reset();
|
||||
StarletMemory memory(system);
|
||||
memory.Reset();
|
||||
|
||||
EXPECT_EQ(memory.Read8(address_a), 0u);
|
||||
EXPECT_EQ(memory.Read8(address_b), 0u);
|
||||
memory.Write8(address_a, 0x12);
|
||||
EXPECT_EQ(memory.Read8(address_a), 0x12u);
|
||||
memory.Write8(address_b, 0x34);
|
||||
EXPECT_EQ(memory.Read8(address_b), 0x34u);
|
||||
EXPECT_EQ(memory.Read8(address_a), 0x12u);
|
||||
memory.Write8(address_a, 0x56);
|
||||
EXPECT_EQ(memory.Read8(address_a), 0x56u);
|
||||
EXPECT_EQ(memory.Read8(address_b), 0x34u);
|
||||
|
||||
memory.Reset();
|
||||
EXPECT_EQ(memory.Read8(address_a), 0u);
|
||||
EXPECT_EQ(memory.Read8(address_b), 0u);
|
||||
}
|
||||
|
||||
TEST(StarletTimer, ZeroDelayAlarmMatchesImmediatelyAndUsesIRQW1C)
|
||||
{
|
||||
constexpr u32 hardware_base = 0x0d800000;
|
||||
@@ -956,6 +1021,133 @@ TEST(StarletARMCore, JitPreservedBlocksUseCurrentTLBGenerationForFastmem)
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(StarletARMCore, FCSESwitchPreservesTaggedTLBTranslations)
|
||||
{
|
||||
TestBus bus(0x10000);
|
||||
ARMCore core(bus);
|
||||
bus.WriteARM(0x0000, 0xe5921000); // ldr r1, [r2]
|
||||
bus.WriteARM(0x0004, 0xe3a00402); // mov r0, #0x02000000
|
||||
bus.WriteARM(0x0008, 0xee0d0f10); // mcr p15, 0, r0, c13, c0, 0
|
||||
bus.WriteARM(0x000c, 0xe5923000); // ldr r3, [r2]
|
||||
bus.WriteARM(0x0010, 0xe3a00000); // mov r0, #0
|
||||
bus.WriteARM(0x0014, 0xee0d0f10); // mcr p15, 0, r0, c13, c0, 0
|
||||
bus.WriteARM(0x0018, 0xe5924000); // ldr r4, [r2]
|
||||
bus.WriteARM(0x0100, 0x12345678);
|
||||
bus.WriteARM(0x4000, 0x00000c02); // FCSE PID 0 low section -> PA 0
|
||||
bus.WriteARM(0x4080, 0x00000c02); // FCSE PID 1 low section -> PA 0
|
||||
bus.WriteARM(0x6000, 0x00000c02); // VA 0x80000000 section -> PA 0
|
||||
core.GetCP15State().translation_table_base = 0x4000;
|
||||
core.GetCP15State().domain_access_control = 3;
|
||||
core.GetCP15State().control |= 1;
|
||||
core.SetRegister(2, 0x100);
|
||||
core.SetRegister(15, 0x80000000);
|
||||
bus.ResetReadCounts();
|
||||
|
||||
EXPECT_EQ(core.RunCycles(7), 7u);
|
||||
EXPECT_EQ(core.GetRegister(1), 0x12345678u);
|
||||
EXPECT_EQ(core.GetRegister(3), 0x12345678u);
|
||||
EXPECT_EQ(core.GetRegister(4), 0x12345678u);
|
||||
// Seven instruction fetches, three data reads, and exactly three first-level walks: kernel,
|
||||
// PID 0 and PID 1. Switching back to PID 0 must reuse its MVA-tagged TLB entry.
|
||||
EXPECT_EQ(bus.GetRead32Count(), 13u);
|
||||
}
|
||||
|
||||
TEST(StarletARMCore, JitFastCacheSeparatesFCSEProcesses)
|
||||
{
|
||||
#if defined(_M_X86_64)
|
||||
TestBus bus(0x204000);
|
||||
ARMCore core(bus);
|
||||
bus.WriteARM(0x000000, 0xe3a01001); // PID 0: mov r1, #1
|
||||
bus.WriteARM(0x000004, 0xea00003d); // b 0x100
|
||||
bus.WriteARM(0x100000, 0xe3a01002); // PID 1: mov r1, #2
|
||||
bus.WriteARM(0x100004, 0xea00003d); // b 0x100
|
||||
bus.WriteARM(0x200000, 0x00000c02); // FCSE PID 0 section -> PA 0
|
||||
bus.WriteARM(0x200080, 0x00100c02); // FCSE PID 1 section -> PA 0x00100000
|
||||
core.GetCP15State().translation_table_base = 0x200000;
|
||||
core.GetCP15State().domain_access_control = 3;
|
||||
core.GetCP15State().control |= 1;
|
||||
core.SetJitEnabled(true);
|
||||
|
||||
core.SetRegister(15, 0);
|
||||
EXPECT_EQ(core.RunCycles(2), 2u);
|
||||
EXPECT_EQ(core.GetRegister(1), 1u);
|
||||
|
||||
core.GetCP15State().process_id = 0x02000000;
|
||||
core.SetRegister(15, 0);
|
||||
EXPECT_EQ(core.RunCycles(2), 2u);
|
||||
EXPECT_EQ(core.GetRegister(1), 2u);
|
||||
EXPECT_EQ(core.GetJitCompiledBlockCount(), 2u);
|
||||
|
||||
// Both the software TLB and native fast-entry cache retain distinct MVA-tagged entries. Returning
|
||||
// to PID 0 therefore needs neither a page-table read nor another block compilation.
|
||||
bus.ResetReadCounts();
|
||||
core.GetCP15State().process_id = 0;
|
||||
core.SetRegister(15, 0);
|
||||
EXPECT_EQ(core.RunCycles(2), 2u);
|
||||
EXPECT_EQ(core.GetRegister(1), 1u);
|
||||
EXPECT_EQ(bus.GetRead32Count(), 0u);
|
||||
EXPECT_EQ(core.GetJitCompiledBlockCount(), 2u);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(StarletARMCore, ARMJitCompilesConditionalBranchExchange)
|
||||
{
|
||||
#if defined(_M_X86_64)
|
||||
TestBus bus(0x100);
|
||||
ARMCore core(bus);
|
||||
bus.WriteARM(0x00, 0x012fff1e); // bxeq lr
|
||||
core.SetJitEnabled(true);
|
||||
core.SetRegister(14, 0x20);
|
||||
core.SetCPSR(core.GetCPSR() | ARMCore::CPSR_Z);
|
||||
|
||||
EXPECT_EQ(core.RunCycles(1), 1u);
|
||||
EXPECT_EQ(core.GetRegister(15), 0x20u);
|
||||
|
||||
core.SetRegister(15, 0);
|
||||
core.SetCPSR(core.GetCPSR() & ~ARMCore::CPSR_Z);
|
||||
EXPECT_EQ(core.RunCycles(1), 1u);
|
||||
EXPECT_EQ(core.GetRegister(15), 4u);
|
||||
EXPECT_EQ(core.GetJitFallbackInstructionCount(), 0u);
|
||||
EXPECT_EQ(core.GetJitNativeExecutedInstructions(), 2u);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(StarletARMCore, ARMJitCompilesConditionalSingleDataTransfers)
|
||||
{
|
||||
#if defined(_M_X86_64)
|
||||
TestBus bus(0x200);
|
||||
ARMCore core(bus);
|
||||
bus.SetFastmemEnabled(true);
|
||||
bus.WriteARM(0x00, 0x05921000); // ldreq r1, [r2]
|
||||
bus.WriteARM(0x04, 0xea00003d); // b 0x100
|
||||
bus.WriteARM(0x20, 0x15823004); // strne r3, [r2, #4]
|
||||
bus.WriteARM(0x24, 0xea000035); // b 0x100
|
||||
bus.WriteARM(0x100, 0x11223344);
|
||||
bus.WriteARM(0x104, 0xaabbccdd);
|
||||
core.SetJitEnabled(true);
|
||||
core.SetRegister(2, 0x100);
|
||||
core.SetRegister(3, 0x55667788);
|
||||
core.SetCPSR(core.GetCPSR() | ARMCore::CPSR_Z);
|
||||
|
||||
EXPECT_EQ(core.RunCycles(2), 2u);
|
||||
EXPECT_EQ(core.GetRegister(1), 0x11223344u);
|
||||
|
||||
core.SetRegister(15, 0x20);
|
||||
EXPECT_EQ(core.RunCycles(2), 2u);
|
||||
EXPECT_EQ(bus[0x104], 0xaau);
|
||||
|
||||
core.SetRegister(15, 0x20);
|
||||
core.SetCPSR(core.GetCPSR() & ~ARMCore::CPSR_Z);
|
||||
EXPECT_EQ(core.RunCycles(2), 2u);
|
||||
EXPECT_EQ(bus[0x104], 0x55u);
|
||||
EXPECT_EQ(bus[0x105], 0x66u);
|
||||
EXPECT_EQ(bus[0x106], 0x77u);
|
||||
EXPECT_EQ(bus[0x107], 0x88u);
|
||||
EXPECT_EQ(core.GetJitFallbackInstructionCount(), 0u);
|
||||
EXPECT_EQ(core.GetJitNativeExecutedInstructions(), 6u);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(StarletARMCore, WaitForInterruptFastForwardsAndWakesOnMaskedIRQ)
|
||||
{
|
||||
TestBus bus;
|
||||
@@ -1223,7 +1415,7 @@ TEST(StarletARMCore, ARMJitConditionalBranchesMatchInterpreter)
|
||||
{
|
||||
const u32 address = condition * 0x20;
|
||||
const u32 branch = (condition << 28) | 0x0a000000;
|
||||
interpreter_bus.WriteARM(address, branch); // b<cond> address + 8
|
||||
interpreter_bus.WriteARM(address, branch); // b<cond> address + 8
|
||||
jit_bus.WriteARM(address, branch);
|
||||
interpreter_bus.WriteARM(address + 4, 0xe3a00001); // mov r0, #1
|
||||
jit_bus.WriteARM(address + 4, 0xe3a00001);
|
||||
@@ -1233,10 +1425,8 @@ TEST(StarletARMCore, ARMJitConditionalBranchesMatchInterpreter)
|
||||
for (u32 flags = 0; flags < 16; ++flags)
|
||||
{
|
||||
const u32 cpsr = static_cast<u32>(ARMCore::Mode::Supervisor) |
|
||||
((flags & 1) ? ARMCore::CPSR_N : 0) |
|
||||
((flags & 2) ? ARMCore::CPSR_Z : 0) |
|
||||
((flags & 4) ? ARMCore::CPSR_C : 0) |
|
||||
((flags & 8) ? ARMCore::CPSR_V : 0);
|
||||
((flags & 1) ? ARMCore::CPSR_N : 0) | ((flags & 2) ? ARMCore::CPSR_Z : 0) |
|
||||
((flags & 4) ? ARMCore::CPSR_C : 0) | ((flags & 8) ? ARMCore::CPSR_V : 0);
|
||||
interpreter.SetCPSR(cpsr);
|
||||
jit.SetCPSR(cpsr);
|
||||
interpreter.SetRegister(15, address);
|
||||
@@ -1272,7 +1462,7 @@ TEST(StarletARMCore, ARMJitCompilesPredicatedDataProcessing)
|
||||
bus.WriteARM(address + 0x04, (condition << 28) | 0x03530002); // cmp<cond> r3, #2
|
||||
bus.WriteARM(address + 0x08, (condition << 28) | 0x03c44018); // bic<cond> r4, r4, #0x18
|
||||
bus.WriteARM(address + 0x0c, (condition << 28) | 0x03a05007); // mov<cond> r5, #7
|
||||
bus.WriteARM(address + 0x10, 0xea000000); // b address + 0x18
|
||||
bus.WriteARM(address + 0x10, 0xea000000); // b address + 0x18
|
||||
};
|
||||
install_program(interpreter_bus);
|
||||
install_program(jit_bus);
|
||||
@@ -1280,10 +1470,8 @@ TEST(StarletARMCore, ARMJitCompilesPredicatedDataProcessing)
|
||||
for (u32 flags = 0; flags < 16; ++flags)
|
||||
{
|
||||
const u32 cpsr = static_cast<u32>(ARMCore::Mode::Supervisor) |
|
||||
((flags & 1) ? ARMCore::CPSR_N : 0) |
|
||||
((flags & 2) ? ARMCore::CPSR_Z : 0) |
|
||||
((flags & 4) ? ARMCore::CPSR_C : 0) |
|
||||
((flags & 8) ? ARMCore::CPSR_V : 0);
|
||||
((flags & 1) ? ARMCore::CPSR_N : 0) | ((flags & 2) ? ARMCore::CPSR_Z : 0) |
|
||||
((flags & 4) ? ARMCore::CPSR_C : 0) | ((flags & 8) ? ARMCore::CPSR_V : 0);
|
||||
interpreter.SetCPSR(cpsr);
|
||||
jit.SetCPSR(cpsr);
|
||||
for (ARMCore* core : {&interpreter, &jit})
|
||||
@@ -1443,8 +1631,8 @@ TEST(StarletARMCore, ThumbJitCompilesRegisterLSREdgeCases)
|
||||
interpreter_bus.WriteThumb(0x02, 0xe7fe); // b .
|
||||
jit_bus.WriteThumb(0x02, 0xe7fe);
|
||||
|
||||
constexpr std::array<u32, 7> values = {0, 1, 0x80000000, 0xffffffff, 0x12345678,
|
||||
0x7fffffff, 0xa5a5a5a5};
|
||||
constexpr std::array<u32, 7> values = {0, 1, 0x80000000, 0xffffffff,
|
||||
0x12345678, 0x7fffffff, 0xa5a5a5a5};
|
||||
constexpr std::array<u32, 8> shifts = {0, 1, 2, 31, 32, 33, 63, 255};
|
||||
for (const u32 value : values)
|
||||
{
|
||||
@@ -1775,8 +1963,50 @@ TEST(StarletARMCore, ARMJitDoesNotCrossFromSRAMIntoBoot0)
|
||||
core.SetJitEnabled(true);
|
||||
|
||||
EXPECT_EQ(core.RunCycles(2), 2u);
|
||||
EXPECT_EQ(core.GetJitFallbackInstructionCount(), 1u);
|
||||
EXPECT_EQ(core.GetJitNativeExecutedInstructions(), 1u);
|
||||
EXPECT_EQ(core.GetJitFallbackInstructionCount(), 0u);
|
||||
EXPECT_EQ(core.GetJitNativeExecutedInstructions(), 2u);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(StarletARMCore, ARMJitKeepsSRAMStackBlockTransfersInsideNativeBlock)
|
||||
{
|
||||
#if defined(_M_X86_64)
|
||||
TestBus interpreter_bus(0x1000);
|
||||
TestBus jit_bus(0x1000);
|
||||
interpreter_bus.SetFastmemEnabled(true);
|
||||
interpreter_bus.SetSRAMFastmemEnabled(true);
|
||||
jit_bus.SetFastmemEnabled(true);
|
||||
jit_bus.SetSRAMFastmemEnabled(true);
|
||||
ARMCore interpreter(interpreter_bus);
|
||||
ARMCore jit(jit_bus);
|
||||
jit.SetJitEnabled(true);
|
||||
const auto install_program = [](TestBus& bus) {
|
||||
bus.WriteARM(0x00, 0xe92d4070); // push {r4-r6, lr}
|
||||
bus.WriteARM(0x04, 0xe3a04000); // mov r4, #0
|
||||
bus.WriteARM(0x08, 0xe3a05000); // mov r5, #0
|
||||
bus.WriteARM(0x0c, 0xe3a06000); // mov r6, #0
|
||||
bus.WriteARM(0x10, 0xe3a0e000); // mov lr, #0
|
||||
bus.WriteARM(0x14, 0xe8bd4070); // pop {r4-r6, lr}
|
||||
bus.WriteARM(0x18, 0xeafffffe); // b .
|
||||
};
|
||||
install_program(interpreter_bus);
|
||||
install_program(jit_bus);
|
||||
for (ARMCore* core : {&interpreter, &jit})
|
||||
{
|
||||
core->SetRegister(4, 0x11223344);
|
||||
core->SetRegister(5, 0x55667788);
|
||||
core->SetRegister(6, 0x99aabbcc);
|
||||
core->SetRegister(13, 0xfff12000);
|
||||
core->SetRegister(14, 0xddeeff00);
|
||||
}
|
||||
|
||||
ASSERT_EQ(interpreter.RunCycles(7), 7u);
|
||||
ASSERT_EQ(jit.RunCycles(7), 7u);
|
||||
for (u32 reg = 0; reg < 16; ++reg)
|
||||
EXPECT_EQ(jit.GetRegister(reg), interpreter.GetRegister(reg)) << "r" << reg;
|
||||
EXPECT_EQ(jit.GetCPSR(), interpreter.GetCPSR());
|
||||
EXPECT_EQ(jit.GetJitFallbackInstructionCount(), 0u);
|
||||
EXPECT_EQ(jit.GetJitNativeExecutedInstructions(), 7u);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2042,6 +2272,53 @@ TEST(StarletARMCore, RunCyclesStopsAtBudget)
|
||||
2u); // Both words stay resident across loop iterations.
|
||||
}
|
||||
|
||||
TEST(StarletARMCore, ARMJitConditionalBackEdgeKeepsExactBudgetAndFallthrough)
|
||||
{
|
||||
#if defined(_M_X86_64)
|
||||
TestBus bus;
|
||||
bus.SetFastmemEnabled(true);
|
||||
ARMCore core(bus);
|
||||
core.SetJitEnabled(true);
|
||||
bus.WriteARM(0x00, 0xe2800001); // add r0, r0, #1
|
||||
bus.WriteARM(0x04, 0xe3500003); // cmp r0, #3
|
||||
bus.WriteARM(0x08, 0x1afffffc); // bne 0x00
|
||||
bus.WriteARM(0x0c, 0xe3a0102a); // mov r1, #42
|
||||
|
||||
EXPECT_EQ(core.RunCycles(9), 9u);
|
||||
EXPECT_EQ(core.GetExecutedInstructions(), 9u);
|
||||
EXPECT_EQ(core.GetRegister(0), 3u);
|
||||
EXPECT_EQ(core.GetRegister(15), 0x0cu);
|
||||
EXPECT_EQ(core.GetJitNativeExecutedInstructions(), 9u);
|
||||
|
||||
EXPECT_EQ(core.RunCycles(1), 1u);
|
||||
EXPECT_EQ(core.GetRegister(1), 42u);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(StarletARMCore, ThumbJitConditionalBackEdgeKeepsExactBudgetAndFallthrough)
|
||||
{
|
||||
#if defined(_M_X86_64)
|
||||
TestBus bus;
|
||||
bus.SetFastmemEnabled(true);
|
||||
ARMCore core(bus);
|
||||
core.SetJitEnabled(true);
|
||||
core.SetCPSR(static_cast<u32>(ARMCore::Mode::Supervisor) | ARMCore::CPSR_T);
|
||||
bus.WriteThumb(0x00, 0x3001); // add r0, #1
|
||||
bus.WriteThumb(0x02, 0x2803); // cmp r0, #3
|
||||
bus.WriteThumb(0x04, 0xd1fc); // bne 0x00
|
||||
bus.WriteThumb(0x06, 0x212a); // mov r1, #42
|
||||
|
||||
EXPECT_EQ(core.RunCycles(9), 9u);
|
||||
EXPECT_EQ(core.GetExecutedInstructions(), 9u);
|
||||
EXPECT_EQ(core.GetRegister(0), 3u);
|
||||
EXPECT_EQ(core.GetRegister(15), 0x06u);
|
||||
EXPECT_EQ(core.GetJitNativeExecutedInstructions(), 9u);
|
||||
|
||||
EXPECT_EQ(core.RunCycles(1), 1u);
|
||||
EXPECT_EQ(core.GetRegister(1), 42u);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(StarletARMCore, ARMJitFastForwardsSliceStableHollywoodTimerPoll)
|
||||
{
|
||||
TestBus bus;
|
||||
@@ -2073,14 +2350,14 @@ TEST(StarletARMCore, ARMJitFastForwardsSliceStableHollywoodTimerPoll)
|
||||
TEST(StarletARMCore, ARMJitKeepsNonblockingReceiveMessagePollGuestVisible)
|
||||
{
|
||||
const auto install_program = [](TestBus& bus, bool non_blocking) {
|
||||
bus.WriteARM(0x00, 0xe5960000); // ldr r0, [r6]
|
||||
bus.WriteARM(0x04, 0xe1a01008); // mov r1, r8
|
||||
bus.WriteARM(0x00, 0xe5960000); // ldr r0, [r6]
|
||||
bus.WriteARM(0x04, 0xe1a01008); // mov r1, r8
|
||||
bus.WriteARM(0x08, non_blocking ? 0xe3a02000 : 0xe3a02001); // mov r2, #block
|
||||
bus.WriteARM(0x0c, 0xeb00000b); // bl 0x40
|
||||
bus.WriteARM(0x10, 0xe2505000); // subs r5, r0, #0
|
||||
bus.WriteARM(0x14, 0x1afffff9); // bne 0x00
|
||||
bus.WriteARM(0x40, 0xe60001d0); // IOS ReceiveMessage syscall 0x0e
|
||||
bus.WriteARM(0x44, 0xe12fff1e); // bx lr
|
||||
bus.WriteARM(0x0c, 0xeb00000b); // bl 0x40
|
||||
bus.WriteARM(0x10, 0xe2505000); // subs r5, r0, #0
|
||||
bus.WriteARM(0x14, 0x1afffff9); // bne 0x00
|
||||
bus.WriteARM(0x40, 0xe60001d0); // IOS ReceiveMessage syscall 0x0e
|
||||
bus.WriteARM(0x44, 0xe12fff1e); // bx lr
|
||||
};
|
||||
|
||||
TestBus bus;
|
||||
|
||||
Reference in New Issue
Block a user