diff --git a/include/dynarmic/A64/config.h b/include/dynarmic/A64/config.h
index 6a029d97..9846f70a 100644
--- a/include/dynarmic/A64/config.h
+++ b/include/dynarmic/A64/config.h
@@ -68,6 +68,15 @@ enum class DataCacheOperation {
     ZeroByVA,
 };
 
+enum class InstructionCacheOperation {
+    /// IC IVAU
+    InvalidateByVAToPoU,
+    /// IC IALLU
+    InvalidateAllToPoU,
+    /// IC IALLUIS
+    InvalidateAllToPoUInnerSharable
+};
+
 struct UserCallbacks {
     virtual ~UserCallbacks() = default;
 
@@ -110,6 +119,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 7a12f2e1..c9983f5a 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -234,6 +234,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..20514599 100644
--- a/src/backend/x64/a64_emit_x64.cpp
+++ b/src/backend/x64/a64_emit_x64.cpp
@@ -647,10 +647,16 @@ 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]);
+    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<u64>(op)), value);
 }
 
+void IREmitter::InstructionCacheOperationRaised(InstructionCacheOperation op, const IR::U64& value) {
+    Inst(Opcode::A64InstructionCacheOperationRaised, Imm64(static_cast<u64>(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..de54121e
--- /dev/null
+++ b/src/frontend/A64/translate/impl/sys_ic.cpp
@@ -0,0 +1,25 @@
+/* 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 {
+
+bool TranslatorVisitor::IC_IALLU() {
+    ir.InstructionCacheOperationRaised(InstructionCacheOperation::InvalidateAllToPoU, ir.Imm64(0));
+    return true;
+}
+
+bool TranslatorVisitor::IC_IALLUIS() {
+    ir.InstructionCacheOperationRaised(InstructionCacheOperation::InvalidateAllToPoUInnerSharable, ir.Imm64(0));
+    return true;
+}
+
+bool TranslatorVisitor::IC_IVAU(Reg 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/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..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;