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.
This commit is contained in:
MerryMage 2018-07-22 16:16:26 +01:00
parent edd795e991
commit 55eaa16615
6 changed files with 38 additions and 1 deletions

View file

@ -522,6 +522,7 @@ void A64EmitX64::EmitA64DataMemoryBarrier(A64EmitContext&, IR::Inst*) {
void A64EmitX64::EmitA64GetCNTPCT(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64GetCNTPCT(A64EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.HostCall(inst); ctx.reg_alloc.HostCall(inst);
code.UpdateTicks();
DEVIRT(conf.callbacks, &A64::UserCallbacks::GetCNTPCT).EmitCall(code); DEVIRT(conf.callbacks, &A64::UserCallbacks::GetCNTPCT).EmitCall(code);
} }

View file

@ -189,6 +189,17 @@ void BlockOfCode::SwitchMxcsrOnExit() {
ldmxcsr(dword[r15 + jsi.offsetof_save_host_MXCSR]); 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) { Xbyak::Address BlockOfCode::MConst(const Xbyak::AddressFrame& frame, u64 lower, u64 upper) {
return constant_pool.GetConstant(frame, lower, upper); return constant_pool.GetConstant(frame, lower, upper);
} }

View file

@ -51,6 +51,9 @@ public:
void SwitchMxcsrOnEntry(); void SwitchMxcsrOnEntry();
/// Code emitter: Makes saved host MXCSR the current MXCSR /// Code emitter: Makes saved host MXCSR the current MXCSR
void SwitchMxcsrOnExit(); 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 /// Code emitter: Calls the function
template <typename FunctionPointer> template <typename FunctionPointer>

View file

@ -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: 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. // 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()) { if (!ir.block.empty()) {
ir.block.CycleCount()--;
ir.SetTerm(IR::Term::LinkBlock{*ir.current_location}); ir.SetTerm(IR::Term::LinkBlock{*ir.current_location});
return false; return false;
} }

View file

@ -313,3 +313,24 @@ TEST_CASE("A64: 128-bit exclusive read/write", "[a64]") {
REQUIRE(env.MemoryRead64(0x1234567812345678) == 0xaf00d1e5badcafe0); REQUIRE(env.MemoryRead64(0x1234567812345678) == 0xaf00d1e5badcafe0);
REQUIRE(env.MemoryRead64(0x1234567812345680) == 0xd0d0cacad0d0caca); 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);
}

View file

@ -94,6 +94,6 @@ public:
return ticks_left; return ticks_left;
} }
std::uint64_t GetCNTPCT() override { std::uint64_t GetCNTPCT() override {
ASSERT_MSG(false, "GetCNTPCT()"); return 0x10000000000 - ticks_left;
} }
}; };