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:
parent
edd795e991
commit
55eaa16615
6 changed files with 38 additions and 1 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 <typename FunctionPointer>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -94,6 +94,6 @@ public:
|
|||
return ticks_left;
|
||||
}
|
||||
std::uint64_t GetCNTPCT() override {
|
||||
ASSERT_MSG(false, "GetCNTPCT()");
|
||||
return 0x10000000000 - ticks_left;
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue