diff --git a/include/dynarmic/A64/config.h b/include/dynarmic/A64/config.h index 534f909c..3edbf0f8 100644 --- a/include/dynarmic/A64/config.h +++ b/include/dynarmic/A64/config.h @@ -92,6 +92,8 @@ struct UserCallbacks { virtual void AddTicks(std::uint64_t ticks) = 0; // How many more ticks am I allowed to execute? virtual std::uint64_t GetTicksRemaining() = 0; + // Get value in the emulated counter-timer physical count register. + virtual std::uint64_t GetCNTPCT() = 0; }; struct UserConfig { diff --git a/src/backend_x64/a64_emit_x64.cpp b/src/backend_x64/a64_emit_x64.cpp index 6a257d90..b229a188 100644 --- a/src/backend_x64/a64_emit_x64.cpp +++ b/src/backend_x64/a64_emit_x64.cpp @@ -472,6 +472,11 @@ void A64EmitX64::EmitA64DataMemoryBarrier(A64EmitContext&, IR::Inst*) { code.lfence(); } +void A64EmitX64::EmitA64GetCNTPCT(A64EmitContext& ctx, IR::Inst* inst) { + ctx.reg_alloc.HostCall(inst); + DEVIRT(conf.callbacks, &A64::UserCallbacks::GetCNTPCT).EmitCall(code); +} + void A64EmitX64::EmitA64GetCTR(A64EmitContext& ctx, IR::Inst* inst) { Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32(); code.mov(result, conf.ctr_el0); diff --git a/src/frontend/A64/ir_emitter.cpp b/src/frontend/A64/ir_emitter.cpp index 89894e7e..8f094d39 100644 --- a/src/frontend/A64/ir_emitter.cpp +++ b/src/frontend/A64/ir_emitter.cpp @@ -53,6 +53,10 @@ void IREmitter::DataMemoryBarrier() { Inst(Opcode::A64DataMemoryBarrier); } +IR::U64 IREmitter::GetCNTPCT() { + return Inst(Opcode::A64GetCNTPCT); +} + IR::U32 IREmitter::GetCTR() { return Inst(Opcode::A64GetCTR); } diff --git a/src/frontend/A64/ir_emitter.h b/src/frontend/A64/ir_emitter.h index d99312e9..867b4ba7 100644 --- a/src/frontend/A64/ir_emitter.h +++ b/src/frontend/A64/ir_emitter.h @@ -44,6 +44,7 @@ public: void DataCacheOperationRaised(DataCacheOperation op, const IR::U64& value); void DataSynchronizationBarrier(); void DataMemoryBarrier(); + IR::U64 GetCNTPCT(); // TODO: Ensure sub-basic-block cycle counts are updated before this. IR::U32 GetCTR(); IR::U32 GetDCZID(); IR::U64 GetTPIDRRO(); diff --git a/src/frontend/A64/translate/impl/system.cpp b/src/frontend/A64/translate/impl/system.cpp index da644652..cd6fc2dc 100644 --- a/src/frontend/A64/translate/impl/system.cpp +++ b/src/frontend/A64/translate/impl/system.cpp @@ -63,6 +63,9 @@ bool TranslatorVisitor::MRS(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3 case 0b11'011'0000'0000'001: // CTR_EL0 X(32, Rt, ir.GetCTR()); return true; + case 0b11'011'1110'0000'001: // CNTPCT_EL0 + X(64, Rt, ir.GetCNTPCT()); + return true; } return InterpretThisInstruction(); } diff --git a/src/frontend/ir/opcodes.inc b/src/frontend/ir/opcodes.inc index 8815423d..2edd8a7c 100644 --- a/src/frontend/ir/opcodes.inc +++ b/src/frontend/ir/opcodes.inc @@ -61,6 +61,7 @@ A64OPC(ExceptionRaised, T::Void, T::U64, T::U64 A64OPC(DataCacheOperationRaised, T::Void, T::U64, T::U64 ) A64OPC(DataSynchronizationBarrier, T::Void, ) A64OPC(DataMemoryBarrier, T::Void, ) +A64OPC(GetCNTPCT, T::U64, ) A64OPC(GetCTR, T::U32, ) A64OPC(GetDCZID, T::U32, ) A64OPC(GetTPIDRRO, T::U64, ) diff --git a/tests/A64/fuzz_with_unicorn.cpp b/tests/A64/fuzz_with_unicorn.cpp index 429affe4..fce2771d 100644 --- a/tests/A64/fuzz_with_unicorn.cpp +++ b/tests/A64/fuzz_with_unicorn.cpp @@ -45,9 +45,17 @@ static bool ShouldTestInst(u32 instruction, u64 pc, bool is_last_inst) { return false; if (auto terminal = block.GetTerminal(); boost::get(&terminal)) return false; - for (const auto& ir_inst : block) - if (ir_inst.GetOpcode() == IR::Opcode::A64ExceptionRaised || ir_inst.GetOpcode() == IR::Opcode::A64CallSupervisor || ir_inst.GetOpcode() == IR::Opcode::A64DataCacheOperationRaised) + for (const auto& ir_inst : block) { + switch (ir_inst.GetOpcode()) { + case IR::Opcode::A64ExceptionRaised: + case IR::Opcode::A64CallSupervisor: + case IR::Opcode::A64DataCacheOperationRaised: + case IR::Opcode::A64GetCNTPCT: return false; + default: + continue; + } + } return true; } diff --git a/tests/A64/testenv.h b/tests/A64/testenv.h index 47bc20cb..15bc1f1a 100644 --- a/tests/A64/testenv.h +++ b/tests/A64/testenv.h @@ -92,4 +92,7 @@ public: std::uint64_t GetTicksRemaining() override { return ticks_left; } + std::uint64_t GetCNTPCT() override { + ASSERT_MSG(false, "GetCNTPCT()"); + } };