From 55eaa166153133d2aa1b79d9a805005385843d05 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sun, 22 Jul 2018 16:16:26 +0100 Subject: [PATCH] a64_emit_x64: Ensure host has updated ticks in EmitA64GetCNTPCT Discovered by @Subv. Fixes incomplete fix begun in 5a91c94dca47c9702dee20fbd5ae1f4c07eef9df. That fix fails to take into account that LinkBlock doesn't update ticks until there are no remaining ticks to be executed. Test added to confirm fix. --- src/backend_x64/a64_emit_x64.cpp | 1 + src/backend_x64/block_of_code.cpp | 11 +++++++++++ src/backend_x64/block_of_code.h | 3 +++ src/frontend/A64/translate/impl/system.cpp | 1 + tests/A64/a64.cpp | 21 +++++++++++++++++++++ tests/A64/testenv.h | 2 +- 6 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/backend_x64/a64_emit_x64.cpp b/src/backend_x64/a64_emit_x64.cpp index 188cf0f0..26aec5ea 100644 --- a/src/backend_x64/a64_emit_x64.cpp +++ b/src/backend_x64/a64_emit_x64.cpp @@ -522,6 +522,7 @@ void A64EmitX64::EmitA64DataMemoryBarrier(A64EmitContext&, IR::Inst*) { void A64EmitX64::EmitA64GetCNTPCT(A64EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.HostCall(inst); + code.UpdateTicks(); DEVIRT(conf.callbacks, &A64::UserCallbacks::GetCNTPCT).EmitCall(code); } diff --git a/src/backend_x64/block_of_code.cpp b/src/backend_x64/block_of_code.cpp index 505998ea..b7c4035f 100644 --- a/src/backend_x64/block_of_code.cpp +++ b/src/backend_x64/block_of_code.cpp @@ -189,6 +189,17 @@ void BlockOfCode::SwitchMxcsrOnExit() { ldmxcsr(dword[r15 + jsi.offsetof_save_host_MXCSR]); } +void BlockOfCode::UpdateTicks() { + cb.AddTicks->EmitCall(*this, [this](RegList param) { + mov(param[0], qword[r15 + jsi.offsetof_cycles_to_run]); + sub(param[0], qword[r15 + jsi.offsetof_cycles_remaining]); + }); + + cb.GetTicksRemaining->EmitCall(*this); + mov(qword[r15 + jsi.offsetof_cycles_to_run], ABI_RETURN); + mov(qword[r15 + jsi.offsetof_cycles_remaining], ABI_RETURN); +} + Xbyak::Address BlockOfCode::MConst(const Xbyak::AddressFrame& frame, u64 lower, u64 upper) { return constant_pool.GetConstant(frame, lower, upper); } diff --git a/src/backend_x64/block_of_code.h b/src/backend_x64/block_of_code.h index 6b6eb6e0..95a247e3 100644 --- a/src/backend_x64/block_of_code.h +++ b/src/backend_x64/block_of_code.h @@ -51,6 +51,9 @@ public: void SwitchMxcsrOnEntry(); /// Code emitter: Makes saved host MXCSR the current MXCSR void SwitchMxcsrOnExit(); + /// Code emitter: Updates cycles remaining my calling cb.AddTicks and cb.GetTicksRemaining + /// @note this clobbers ABI callee-save registers + void UpdateTicks(); /// Code emitter: Calls the function template diff --git a/src/frontend/A64/translate/impl/system.cpp b/src/frontend/A64/translate/impl/system.cpp index 9368d537..859bc44e 100644 --- a/src/frontend/A64/translate/impl/system.cpp +++ b/src/frontend/A64/translate/impl/system.cpp @@ -107,6 +107,7 @@ bool TranslatorVisitor::MRS(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3 case SystemRegisterEncoding::CNTPCT_EL0: // HACK: Ensure that this is the first instruction in the block it's emitted in, so the cycle count is most up-to-date. if (!ir.block.empty()) { + ir.block.CycleCount()--; ir.SetTerm(IR::Term::LinkBlock{*ir.current_location}); return false; } diff --git a/tests/A64/a64.cpp b/tests/A64/a64.cpp index 9f71eb95..90c38f63 100644 --- a/tests/A64/a64.cpp +++ b/tests/A64/a64.cpp @@ -313,3 +313,24 @@ TEST_CASE("A64: 128-bit exclusive read/write", "[a64]") { REQUIRE(env.MemoryRead64(0x1234567812345678) == 0xaf00d1e5badcafe0); REQUIRE(env.MemoryRead64(0x1234567812345680) == 0xd0d0cacad0d0caca); } + +TEST_CASE("A64: CNTPCT_EL0", "[a64]") { + TestEnv env; + Dynarmic::A64::Jit jit{Dynarmic::A64::UserConfig{&env}}; + + env.code_mem[0] = 0xd53be021; // MRS X1, CNTPCT_EL0 + env.code_mem[1] = 0xd503201f; // NOP + env.code_mem[2] = 0xd503201f; // NOP + env.code_mem[3] = 0xd503201f; // NOP + env.code_mem[4] = 0xd503201f; // NOP + env.code_mem[5] = 0xd503201f; // NOP + env.code_mem[6] = 0xd503201f; // NOP + env.code_mem[7] = 0xd53be022; // MRS X2, CNTPCT_EL0 + env.code_mem[8] = 0xcb010043; // SUB X3, X2, X1 + env.code_mem[9] = 0x14000000; // B . + + env.ticks_left = 10; + jit.Run(); + + REQUIRE(jit.GetRegister(3) == 7); +} diff --git a/tests/A64/testenv.h b/tests/A64/testenv.h index 10a32b05..5c2bb29e 100644 --- a/tests/A64/testenv.h +++ b/tests/A64/testenv.h @@ -94,6 +94,6 @@ public: return ticks_left; } std::uint64_t GetCNTPCT() override { - ASSERT_MSG(false, "GetCNTPCT()"); + return 0x10000000000 - ticks_left; } };