diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 49837ea9..a96500ea 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -127,6 +127,7 @@ if ("A32" IN_LIST DYNARMIC_FRONTENDS) frontend/A32/translate/impl/asimd_one_reg_modified_immediate.cpp frontend/A32/translate/impl/asimd_three_same.cpp frontend/A32/translate/impl/asimd_two_regs_misc.cpp + frontend/A32/translate/impl/asimd_two_regs_shift.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 e03a58e6..faa483a0 100644 --- a/src/frontend/A32/decoder/asimd.inc +++ b/src/frontend/A32/decoder/asimd.inc @@ -58,7 +58,7 @@ INST(asimd_VQSUB, "VQSUB", "1111001U0Dzznnnndddd001 //INST(asimd_VQRDMULH, "VQRDMULH", "1111001U1-BB--------1101-1-0----") // ASIMD // Two registers and a shift amount -//INST(asimd_SHR, "SHR", "1111001U1-vvv-------0000LB-1----") // ASIMD +INST(asimd_SHR, "SHR", "1111001U1Diiiiiidddd0000LQM1mmmm") // ASIMD //INST(asimd_SRA, "SRA", "1111001U1-vvv-------0001LB-1----") // ASIMD //INST(asimd_VRSHR, "VRSHR", "1111001U1-vvv-------0010LB-1----") // ASIMD //INST(asimd_VRSRA, "VRSRA", "1111001U1-vvv-------0011LB-1----") // ASIMD diff --git a/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp b/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp new file mode 100644 index 00000000..bac8ceee --- /dev/null +++ b/src/frontend/A32/translate/impl/asimd_two_regs_shift.cpp @@ -0,0 +1,52 @@ +/* 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 { +std::pair ElementSizeAndShiftAmount(bool L, size_t imm6) { + if (L) { + return {64, 64U - imm6}; + } + + const int highest = Common::HighestSetBit(imm6 >> 3); + if (highest == 0) { + return {8, 16 - imm6}; + } + + if (highest == 1) { + return {16, 32U - imm6}; + } + + return {32, 64U - imm6}; +} +} // Anonymous namespace + +bool ArmTranslatorVisitor::asimd_SHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm) { + if (Q && (Common::Bit<0>(Vd) || Common::Bit<0>(Vm))) { + return UndefinedInstruction(); + } + + // Technically just a related encoding (One register and modified immediate instructions) + if (!L && Common::Bits<3, 5>(imm6) == 0) { + return UndefinedInstruction(); + } + + const auto [esize, shift_amount] = ElementSizeAndShiftAmount(L, imm6); + const auto d = ToVector(Q, Vd, D); + const auto m = ToVector(Q, Vm, M); + + const auto reg_m = ir.GetVector(m); + const auto result = U ? ir.VectorLogicalShiftRight(esize, reg_m, static_cast(shift_amount)) + : ir.VectorArithmeticShiftRight(esize, reg_m, static_cast(shift_amount)); + + ir.SetVector(d, result); + 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 369b90c7..b0527ffe 100644 --- a/src/frontend/A32/translate/impl/translate_arm.h +++ b/src/frontend/A32/translate/impl/translate_arm.h @@ -451,6 +451,9 @@ struct ArmTranslatorVisitor final { bool asimd_VHSUB(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm); bool asimd_VQSUB(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool Q, bool M, size_t Vm); + // Two registers and a shift amount + bool asimd_SHR(bool U, bool D, size_t imm6, size_t Vd, bool L, bool Q, bool M, size_t Vm); + // Advanced SIMD two register, miscellaneous bool asimd_VREV(bool D, size_t sz, size_t Vd, size_t op, bool Q, bool M, size_t Vm); bool asimd_VCLS(bool D, size_t sz, size_t Vd, bool Q, bool M, size_t Vm);