From 8728444af895ffcd59017fb57a03e6c658e334c9 Mon Sep 17 00:00:00 2001 From: emuplz <3116769+emuplz@users.noreply.github.com> Date: Wed, 28 Oct 2020 22:58:20 +0000 Subject: [PATCH 1/3] added support for instruction ic ivau --- include/dynarmic/A64/config.h | 6 +++++ src/CMakeLists.txt | 1 + src/backend/x64/a64_emit_x64.cpp | 6 +++++ src/frontend/A64/decoder/a64.inc | 5 ++++ src/frontend/A64/ir_emitter.cpp | 4 ++++ src/frontend/A64/ir_emitter.h | 1 + src/frontend/A64/translate/impl/impl.h | 5 ++++ src/frontend/A64/translate/impl/sys_ic.cpp | 27 ++++++++++++++++++++++ src/frontend/ir/opcodes.inc | 1 + tests/A64/a64.cpp | 17 ++++++++++++++ 10 files changed, 73 insertions(+) create mode 100644 src/frontend/A64/translate/impl/sys_ic.cpp diff --git a/include/dynarmic/A64/config.h b/include/dynarmic/A64/config.h index 6a029d97..2511b65b 100644 --- a/include/dynarmic/A64/config.h +++ b/include/dynarmic/A64/config.h @@ -68,6 +68,11 @@ enum class DataCacheOperation { ZeroByVA, }; +enum class InstructionCacheOperation { + // IC IVAU + InvalidateByVAToPoU, +}; + struct UserCallbacks { virtual ~UserCallbacks() = default; @@ -110,6 +115,7 @@ struct UserCallbacks { virtual void ExceptionRaised(VAddr pc, Exception exception) = 0; virtual void DataCacheOperationRaised(DataCacheOperation /*op*/, VAddr /*value*/) {} + virtual void InstructionCacheOperationRaised(InstructionCacheOperation /*op*/, VAddr /*value*/) {} virtual void InstructionSynchronizationBarrierRaised() {} // Timing-related callbacks diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c99dec73..f8eb7b61 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -233,6 +233,7 @@ if ("A64" IN_LIST DYNARMIC_FRONTENDS) frontend/A64/translate/impl/simd_two_register_misc.cpp frontend/A64/translate/impl/simd_vector_x_indexed_element.cpp frontend/A64/translate/impl/sys_dc.cpp + frontend/A64/translate/impl/sys_ic.cpp frontend/A64/translate/impl/system.cpp frontend/A64/translate/impl/system_flag_format.cpp frontend/A64/translate/impl/system_flag_manipulation.cpp diff --git a/src/backend/x64/a64_emit_x64.cpp b/src/backend/x64/a64_emit_x64.cpp index c89f4e91..c834ee87 100644 --- a/src/backend/x64/a64_emit_x64.cpp +++ b/src/backend/x64/a64_emit_x64.cpp @@ -651,6 +651,12 @@ void A64EmitX64::EmitA64DataCacheOperationRaised(A64EmitContext& ctx, IR::Inst* Devirtualize<&A64::UserCallbacks::DataCacheOperationRaised>(conf.callbacks).EmitCall(code); } +void A64EmitX64::EmitA64InstructionCacheOperationRaised(A64EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + ctx.reg_alloc.HostCall(nullptr, args[0], args[1]); + Devirtualize<&A64::UserCallbacks::InstructionCacheOperationRaised>(conf.callbacks).EmitCall(code); +} + void A64EmitX64::EmitA64DataSynchronizationBarrier(A64EmitContext&, IR::Inst*) { code.mfence(); } diff --git a/src/frontend/A64/decoder/a64.inc b/src/frontend/A64/decoder/a64.inc index 7d68ccec..b9d83af6 100644 --- a/src/frontend/A64/decoder/a64.inc +++ b/src/frontend/A64/decoder/a64.inc @@ -108,6 +108,11 @@ INST(DC_CVAU, "DC CVAU", "11010 INST(DC_CVAP, "DC CVAP", "110101010000101101111100001ttttt") INST(DC_CIVAC, "DC CIVAC", "110101010000101101111110001ttttt") +// SYS: Instruction Cache +INST(IC_IALLU, "IC IALLU", "11010101000010000111010100011111") +INST(IC_IALLUIS, "IC IALLUIS", "11010101000010000111000100011111") +INST(IC_IVAU, "IC IVAU", "110101010000101101110101001ttttt") + // Unconditional branch (Register) INST(BLR, "BLR", "1101011000111111000000nnnnn00000") INST(BR, "BR", "1101011000011111000000nnnnn00000") diff --git a/src/frontend/A64/ir_emitter.cpp b/src/frontend/A64/ir_emitter.cpp index cfd0acaa..a8506b64 100644 --- a/src/frontend/A64/ir_emitter.cpp +++ b/src/frontend/A64/ir_emitter.cpp @@ -56,6 +56,10 @@ void IREmitter::DataCacheOperationRaised(DataCacheOperation op, const IR::U64& v Inst(Opcode::A64DataCacheOperationRaised, Imm64(static_cast(op)), value); } +void IREmitter::InstructionCacheOperationRaised(InstructionCacheOperation op, const IR::U64& value) { + Inst(Opcode::A64InstructionCacheOperationRaised, Imm64(static_cast(op)), value); +} + void IREmitter::DataSynchronizationBarrier() { Inst(Opcode::A64DataSynchronizationBarrier); } diff --git a/src/frontend/A64/ir_emitter.h b/src/frontend/A64/ir_emitter.h index 8d463b7b..b6fcf523 100644 --- a/src/frontend/A64/ir_emitter.h +++ b/src/frontend/A64/ir_emitter.h @@ -42,6 +42,7 @@ public: void CallSupervisor(u32 imm); void ExceptionRaised(Exception exception); void DataCacheOperationRaised(DataCacheOperation op, const IR::U64& value); + void InstructionCacheOperationRaised(InstructionCacheOperation op, const IR::U64& value); void DataSynchronizationBarrier(); void DataMemoryBarrier(); void InstructionSynchronizationBarrier(); diff --git a/src/frontend/A64/translate/impl/impl.h b/src/frontend/A64/translate/impl/impl.h index d6ed6a59..e7f22136 100644 --- a/src/frontend/A64/translate/impl/impl.h +++ b/src/frontend/A64/translate/impl/impl.h @@ -174,6 +174,11 @@ struct TranslatorVisitor final { bool DC_CVAP(Reg Rt); bool DC_CIVAC(Reg Rt); + // SYS: Instruction Cache + bool IC_IALLU(); + bool IC_IALLUIS(); + bool IC_IVAU(Reg Rt); + // Unconditional branch (Register) bool BR(Reg Rn); bool BRA(bool Z, bool M, Reg Rn, Reg Rm); diff --git a/src/frontend/A64/translate/impl/sys_ic.cpp b/src/frontend/A64/translate/impl/sys_ic.cpp new file mode 100644 index 00000000..d2f557f5 --- /dev/null +++ b/src/frontend/A64/translate/impl/sys_ic.cpp @@ -0,0 +1,27 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2018 MerryMage + * SPDX-License-Identifier: 0BSD + */ + +#include "frontend/A64/translate/impl/impl.h" + +namespace Dynarmic::A64 { + +static bool InstructionCacheInstruction(TranslatorVisitor& v, InstructionCacheOperation op, const Reg Rt) { + v.ir.InstructionCacheOperationRaised(op, v.X(64, Rt)); + return true; +} + +bool TranslatorVisitor::IC_IALLU() { + return false; +} + +bool TranslatorVisitor::IC_IALLUIS() { + return false; +} + +bool TranslatorVisitor::IC_IVAU(Reg Rt) { + return InstructionCacheInstruction(*this, InstructionCacheOperation::InvalidateByVAToPoU, Rt); +} + +} // namespace Dynarmic::A64 diff --git a/src/frontend/ir/opcodes.inc b/src/frontend/ir/opcodes.inc index d68a5f5c..d8a0fd6e 100644 --- a/src/frontend/ir/opcodes.inc +++ b/src/frontend/ir/opcodes.inc @@ -69,6 +69,7 @@ A64OPC(SetPC, Void, U64 A64OPC(CallSupervisor, Void, U32 ) A64OPC(ExceptionRaised, Void, U64, U64 ) A64OPC(DataCacheOperationRaised, Void, U64, U64 ) +A64OPC(InstructionCacheOperationRaised, Void, U64, U64 ) A64OPC(DataSynchronizationBarrier, Void, ) A64OPC(DataMemoryBarrier, Void, ) A64OPC(InstructionSynchronizationBarrier, Void, ) diff --git a/tests/A64/a64.cpp b/tests/A64/a64.cpp index 1cdb7628..5db20ebe 100644 --- a/tests/A64/a64.cpp +++ b/tests/A64/a64.cpp @@ -634,3 +634,20 @@ TEST_CASE("A64: Optimization failure when folding ADD", "[a64]") { REQUIRE(jit.GetPstate() == 0x20000000); REQUIRE(jit.GetVector(30) == Vector{0xf7f6f5f4, 0}); } + +TEST_CASE("A64: IC", "[a64]") { + A64TestEnv env; + A64::Jit jit{A64::UserConfig{&env}}; + + env.code_mem.emplace_back(0xd50b7520); // ic ivau, x0 + env.code_mem.emplace_back(0x14000000); // B . + + jit.SetRegister(0, 0); + jit.SetPC(0); + + env.ticks_left = 2; + jit.Run(); + + REQUIRE(jit.GetRegister(0) == 0); + REQUIRE(jit.GetPC() == 4); +} From 77621a844801bb8eaee949b3815e39bafae69cb7 Mon Sep 17 00:00:00 2001 From: rufi <3116769+rufiplz@users.noreply.github.com> Date: Mon, 9 Nov 2020 09:01:20 +0000 Subject: [PATCH 2/3] implemented other ic instructions --- include/dynarmic/A64/config.h | 6 +++++- src/frontend/A64/translate/impl/sys_ic.cpp | 14 ++++++------ src/frontend/ir/microinstruction.cpp | 25 +++++++++++----------- tests/A64/a64.cpp | 17 --------------- 4 files changed, 24 insertions(+), 38 deletions(-) diff --git a/include/dynarmic/A64/config.h b/include/dynarmic/A64/config.h index 2511b65b..9846f70a 100644 --- a/include/dynarmic/A64/config.h +++ b/include/dynarmic/A64/config.h @@ -69,8 +69,12 @@ enum class DataCacheOperation { }; enum class InstructionCacheOperation { - // IC IVAU + /// IC IVAU InvalidateByVAToPoU, + /// IC IALLU + InvalidateAllToPoU, + /// IC IALLUIS + InvalidateAllToPoUInnerSharable }; struct UserCallbacks { diff --git a/src/frontend/A64/translate/impl/sys_ic.cpp b/src/frontend/A64/translate/impl/sys_ic.cpp index d2f557f5..de54121e 100644 --- a/src/frontend/A64/translate/impl/sys_ic.cpp +++ b/src/frontend/A64/translate/impl/sys_ic.cpp @@ -7,21 +7,19 @@ namespace Dynarmic::A64 { -static bool InstructionCacheInstruction(TranslatorVisitor& v, InstructionCacheOperation op, const Reg Rt) { - v.ir.InstructionCacheOperationRaised(op, v.X(64, Rt)); +bool TranslatorVisitor::IC_IALLU() { + ir.InstructionCacheOperationRaised(InstructionCacheOperation::InvalidateAllToPoU, ir.Imm64(0)); return true; } -bool TranslatorVisitor::IC_IALLU() { - return false; -} - bool TranslatorVisitor::IC_IALLUIS() { - return false; + ir.InstructionCacheOperationRaised(InstructionCacheOperation::InvalidateAllToPoUInnerSharable, ir.Imm64(0)); + return true; } bool TranslatorVisitor::IC_IVAU(Reg Rt) { - return InstructionCacheInstruction(*this, InstructionCacheOperation::InvalidateByVAToPoU, Rt); + ir.InstructionCacheOperationRaised(InstructionCacheOperation::InvalidateByVAToPoU, X(64, Rt)); + return true; } } // namespace Dynarmic::A64 diff --git a/src/frontend/ir/microinstruction.cpp b/src/frontend/ir/microinstruction.cpp index 3658aa74..f1f381df 100644 --- a/src/frontend/ir/microinstruction.cpp +++ b/src/frontend/ir/microinstruction.cpp @@ -520,18 +520,19 @@ bool Inst::IsSetCheckBitOperation() const { } bool Inst::MayHaveSideEffects() const { - return op == Opcode::PushRSB || - op == Opcode::A64DataCacheOperationRaised || - IsSetCheckBitOperation() || - IsBarrier() || - CausesCPUException() || - WritesToCoreRegister() || - WritesToSystemRegister() || - WritesToCPSR() || - WritesToFPCR() || - WritesToFPSR() || - AltersExclusiveState() || - IsMemoryWrite() || + return op == Opcode::PushRSB || + op == Opcode::A64DataCacheOperationRaised || + op == Opcode::A64InstructionCacheOperationRaised || + IsSetCheckBitOperation() || + IsBarrier() || + CausesCPUException() || + WritesToCoreRegister() || + WritesToSystemRegister() || + WritesToCPSR() || + WritesToFPCR() || + WritesToFPSR() || + AltersExclusiveState() || + IsMemoryWrite() || IsCoprocessorInstruction(); } diff --git a/tests/A64/a64.cpp b/tests/A64/a64.cpp index 5db20ebe..1cdb7628 100644 --- a/tests/A64/a64.cpp +++ b/tests/A64/a64.cpp @@ -634,20 +634,3 @@ TEST_CASE("A64: Optimization failure when folding ADD", "[a64]") { REQUIRE(jit.GetPstate() == 0x20000000); REQUIRE(jit.GetVector(30) == Vector{0xf7f6f5f4, 0}); } - -TEST_CASE("A64: IC", "[a64]") { - A64TestEnv env; - A64::Jit jit{A64::UserConfig{&env}}; - - env.code_mem.emplace_back(0xd50b7520); // ic ivau, x0 - env.code_mem.emplace_back(0x14000000); // B . - - jit.SetRegister(0, 0); - jit.SetPC(0); - - env.ticks_left = 2; - jit.Run(); - - REQUIRE(jit.GetRegister(0) == 0); - REQUIRE(jit.GetPC() == 4); -} From 6d4333c78efcfb4e56f1c4652ed98e7f84239ca7 Mon Sep 17 00:00:00 2001 From: emuplz <3116769+emuplz@users.noreply.github.com> Date: Thu, 12 Nov 2020 16:15:33 +0000 Subject: [PATCH 3/3] fixed data + instruction cache callbacks (w/ tests) --- src/backend/x64/a64_emit_x64.cpp | 4 ++-- tests/A64/a64.cpp | 28 ++++++++++++++++++++++++++++ tests/A64/testenv.h | 2 +- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/backend/x64/a64_emit_x64.cpp b/src/backend/x64/a64_emit_x64.cpp index c834ee87..20514599 100644 --- a/src/backend/x64/a64_emit_x64.cpp +++ b/src/backend/x64/a64_emit_x64.cpp @@ -647,13 +647,13 @@ void A64EmitX64::EmitA64ExceptionRaised(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64DataCacheOperationRaised(A64EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - ctx.reg_alloc.HostCall(nullptr, args[0], args[1]); + ctx.reg_alloc.HostCall(nullptr, {}, args[0], args[1]); Devirtualize<&A64::UserCallbacks::DataCacheOperationRaised>(conf.callbacks).EmitCall(code); } void A64EmitX64::EmitA64InstructionCacheOperationRaised(A64EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - ctx.reg_alloc.HostCall(nullptr, args[0], args[1]); + ctx.reg_alloc.HostCall(nullptr, {}, args[0], args[1]); Devirtualize<&A64::UserCallbacks::InstructionCacheOperationRaised>(conf.callbacks).EmitCall(code); } diff --git a/tests/A64/a64.cpp b/tests/A64/a64.cpp index 1cdb7628..524be36e 100644 --- a/tests/A64/a64.cpp +++ b/tests/A64/a64.cpp @@ -634,3 +634,31 @@ TEST_CASE("A64: Optimization failure when folding ADD", "[a64]") { REQUIRE(jit.GetPstate() == 0x20000000); REQUIRE(jit.GetVector(30) == Vector{0xf7f6f5f4, 0}); } + +TEST_CASE("A64: Cache Maintenance Instructions", "[a64]") { + class CacheMaintenanceTestEnv final : public A64TestEnv { + void InstructionCacheOperationRaised(A64::InstructionCacheOperation op, VAddr value) override { + REQUIRE(op == A64::InstructionCacheOperation::InvalidateByVAToPoU); + REQUIRE(value == 0xcafed00d); + } + void DataCacheOperationRaised(A64::DataCacheOperation op, VAddr value) override { + REQUIRE(op == A64::DataCacheOperation::InvalidateByVAToPoC); + REQUIRE(value == 0xcafebabe); + } + }; + + CacheMaintenanceTestEnv env; + A64::UserConfig conf{&env}; + conf.hook_data_cache_operations = true; + A64::Jit jit{conf}; + + jit.SetRegister(0, 0xcafed00d); + jit.SetRegister(1, 0xcafebabe); + + env.code_mem.emplace_back(0xd50b7520); // ic ivau, x0 + env.code_mem.emplace_back(0xd5087621); // dc ivac, x1 + env.code_mem.emplace_back(0x14000000); // B . + + env.ticks_left = 3; + jit.Run(); +} diff --git a/tests/A64/testenv.h b/tests/A64/testenv.h index 6f416888..0eaf68ed 100644 --- a/tests/A64/testenv.h +++ b/tests/A64/testenv.h @@ -15,7 +15,7 @@ using Vector = Dynarmic::A64::Vector; -class A64TestEnv final : public Dynarmic::A64::UserCallbacks { +class A64TestEnv : public Dynarmic::A64::UserCallbacks { public: u64 ticks_left = 0;