diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3e47ce00..2fd3d93c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -124,6 +124,7 @@ if ("A32" IN_LIST DYNARMIC_FRONTENDS) frontend/A32/PSR.h frontend/A32/translate/impl/asimd_load_store_structures.cpp frontend/A32/translate/impl/asimd_three_same.cpp + frontend/A32/translate/impl/asimd_two_regs_misc.cpp frontend/A32/translate/impl/barrier.cpp frontend/A32/translate/impl/branch.cpp frontend/A32/translate/impl/coprocessor.cpp diff --git a/src/frontend/A32/decoder/asimd.inc b/src/frontend/A32/decoder/asimd.inc index 41031b7f..774c0b75 100644 --- a/src/frontend/A32/decoder/asimd.inc +++ b/src/frontend/A32/decoder/asimd.inc @@ -94,7 +94,7 @@ INST(asimd_VBIF, "VBIF", "111100110D11nnnndddd000 //INST(asimd_VCLT_zero, "VCLT (zero)", "111100111-11--01----0x100x-0----") // ASIMD //INST(asimd_VABS, "VABS", "111100111-11--01----0x110x-0----") // ASIMD //INST(asimd_VNEG, "VNEG", "111100111-11--01----0x111x-0----") // ASIMD -//INST(asimd_VSWP, "VSWP", "111100111-11--10----00000x-0----") // ASIMD +INST(asimd_VSWP, "VSWP", "111100111D110010dddd00000QM0mmmm") // ASIMD //INST(asimd_VTRN, "VTRN", "111100111-11--10----00001x-0----") // ASIMD //INST(asimd_VUZP, "VUZP", "111100111-11--10----00010x-0----") // ASIMD //INST(asimd_VZIP, "VZIP", "111100111-11--10----00011x-0----") // ASIMD diff --git a/src/frontend/A32/translate/impl/asimd_two_regs_misc.cpp b/src/frontend/A32/translate/impl/asimd_two_regs_misc.cpp new file mode 100644 index 00000000..f473b9b6 --- /dev/null +++ b/src/frontend/A32/translate/impl/asimd_two_regs_misc.cpp @@ -0,0 +1,43 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2020 MerryMage + * SPDX-License-Identifier: 0BSD + */ + +#include "common/bit_util.h" + +#include "frontend/A32/translate/impl/translate_arm.h" + +namespace Dynarmic::A32 { +namespace { +ExtReg ToExtRegD(size_t base, bool bit) { + return ExtReg::D0 + (base + (bit ? 16 : 0)); +} +} // Anonymous namespace + +bool ArmTranslatorVisitor::asimd_VSWP(bool D, size_t Vd, bool Q, bool M, size_t Vm) { + if (Q && (Common::Bit<0>(Vd) || Common::Bit<0>(Vm))) { + return UndefinedInstruction(); + } + + // Swapping the same register results in the same contents. + const auto d = ToExtRegD(Vd, D); + const auto m = ToExtRegD(Vm, M); + if (d == m) { + return true; + } + + const size_t regs = Q ? 2 : 1; + for (size_t i = 0; i < regs; i++) { + const auto d_index = d + i; + const auto m_index = m + i; + + const auto reg_d = ir.GetExtendedRegister(d_index); + const auto reg_m = ir.GetExtendedRegister(m_index); + + ir.SetExtendedRegister(m_index, reg_d); + ir.SetExtendedRegister(d_index, reg_m); + } + + return true; +} +} // namespace Dynarmic::A32 diff --git a/src/frontend/A32/translate/impl/translate_arm.h b/src/frontend/A32/translate/impl/translate_arm.h index 64d053b9..5aad7137 100644 --- a/src/frontend/A32/translate/impl/translate_arm.h +++ b/src/frontend/A32/translate/impl/translate_arm.h @@ -439,6 +439,9 @@ struct ArmTranslatorVisitor final { bool asimd_VBIT(bool D, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm); bool asimd_VBIF(bool D, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm); + // Advanced SIMD two register, miscellaneous + bool asimd_VSWP(bool D, size_t Vd, bool Q, bool M, size_t Vm); + // Advanced SIMD load/store structures bool v8_VST_multiple(bool D, Reg n, size_t Vd, Imm<4> type, size_t sz, size_t align, Reg m); bool v8_VLD_multiple(bool D, Reg n, size_t Vd, Imm<4> type, size_t sz, size_t align, Reg m);