/* This file is part of the dynarmic project. * Copyright (c) 2020 MerryMage * SPDX-License-Identifier: 0BSD */ #include "frontend/A32/translate/impl/translate.h" #include "common/assert.h" #include "common/bit_util.h" namespace Dynarmic::A32 { static bool TableLookup(TranslatorVisitor& v, bool is_vtbl, bool D, size_t Vn, size_t Vd, size_t len, bool N, bool M, size_t Vm) { const size_t length = len + 1; const auto d = ToVector(false, Vd, D); const auto m = ToVector(false, Vm, M); const auto n = ToVector(false, Vn, N); if (RegNumber(n) + length > 32) { return v.UnpredictableInstruction(); } const IR::Table table = v.ir.VectorTable([&]{ std::vector result; for (size_t i = 0; i < length; ++i) { result.emplace_back(v.ir.GetExtendedRegister(n + i)); } return result; }()); const IR::U64 indicies = v.ir.GetExtendedRegister(m); const IR::U64 defaults = is_vtbl ? v.ir.Imm64(0) : IR::U64{v.ir.GetExtendedRegister(d)}; const IR::U64 result = v.ir.VectorTableLookup(defaults, table, indicies); v.ir.SetExtendedRegister(d, result); return true; } bool TranslatorVisitor::asimd_VEXT(bool D, size_t Vn, size_t Vd, Imm<4> imm4, bool N, bool Q, bool M, size_t Vm) { if (Q && (Common::Bit<0>(Vd) || Common::Bit<0>(Vn) || Common::Bit<0>(Vm))) { return UndefinedInstruction(); } if (!Q && imm4.Bit<3>()) { return UndefinedInstruction(); } const u8 position = 8 * imm4.ZeroExtend(); const auto d = ToVector(Q, Vd, D); const auto m = ToVector(Q, Vm, M); const auto n = ToVector(Q, Vn, N); const auto reg_n = ir.GetVector(n); const auto reg_m = ir.GetVector(m); const auto result = Q ? ir.VectorExtract(reg_n, reg_m, position) : ir.VectorExtractLower(reg_n, reg_m, position); ir.SetVector(d, result); return true; } bool TranslatorVisitor::asimd_VTBL(bool D, size_t Vn, size_t Vd, size_t len, bool N, bool M, size_t Vm) { return TableLookup(*this, true, D, Vn, Vd, len, N, M, Vm); } bool TranslatorVisitor::asimd_VTBX(bool D, size_t Vn, size_t Vd, size_t len, bool N, bool M, size_t Vm) { return TableLookup(*this, false, D, Vn, Vd, len, N, M, Vm); } bool TranslatorVisitor::asimd_VDUP_scalar(bool D, Imm<4> imm4, size_t Vd, bool Q, bool M, size_t Vm) { if (Q && Common::Bit<0>(Vd)) { return UndefinedInstruction(); } if (imm4.Bits<0, 2>() == 0b000) { return UndefinedInstruction(); } const size_t imm4_lsb = Common::LowestSetBit(imm4.ZeroExtend()); const size_t esize = 8u << imm4_lsb; const size_t index = imm4.ZeroExtend() >> (imm4_lsb + 1); const auto d = ToVector(Q, Vd, D); const auto m = ToVector(false, Vm, M); const auto reg_m = ir.GetVector(m); const auto scalar = ir.VectorGetElement(esize, reg_m, index); const auto result = ir.VectorBroadcast(esize, scalar); ir.SetVector(d, result); return true; } } // namespace Dynarmic::A32