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); +}