diff --git a/src/frontend/A32/decoder/asimd.inc b/src/frontend/A32/decoder/asimd.inc index a8aed69d..307cb0a4 100644 --- a/src/frontend/A32/decoder/asimd.inc +++ b/src/frontend/A32/decoder/asimd.inc @@ -76,9 +76,7 @@ INST(asimd_VQSUB, "VQSUB", "1111001U0Dzznnnndddd001 //INST(asimd_VCVT_fixed, "VCVT (fixed-point)", "1111001U1-vvv-------111x0B-1----") // ASIMD // Two registers, miscellaneous -//INST(asimd_VREV64, "VREV64", "111100111-11--00----00000x-0----") // ASIMD -//INST(asimd_VREV32, "VREV32", "111100111-11--00----00001x-0----") // ASIMD -//INST(asimd_VREV16, "VREV16", "111100111-11--00----00010x-0----") // ASIMD +INST(asimd_VREV, "VREV{16,32,64}", "111100111D11zz00dddd000ooQM0mmmm") // ASIMD //INST(asimd_VPADDL, "VPADDL", "111100111-11--00----0010xx-0----") // ASIMD INST(asimd_VCLS, "VCLS", "111100111D11zz00dddd01000QM0mmmm") // ASIMD INST(asimd_VCLZ, "VCLZ", "111100111D11zz00dddd01001QM0mmmm") // 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 index a4d804a1..e1bad909 100644 --- a/src/frontend/A32/translate/impl/asimd_two_regs_misc.cpp +++ b/src/frontend/A32/translate/impl/asimd_two_regs_misc.cpp @@ -9,6 +9,66 @@ namespace Dynarmic::A32 { +bool ArmTranslatorVisitor::asimd_VREV(bool D, size_t sz, size_t Vd, size_t op, bool Q, bool M, size_t Vm) { + if (op + sz >= 3) { + return UndefinedInstruction(); + } + + if (Q && (Common::Bit<0>(Vd) || Common::Bit<0>(Vm))) { + return UndefinedInstruction(); + } + + const auto d = ToVector(Q, Vd, D); + const auto m = ToVector(Q, Vm, M); + const auto result = [this, m, op, sz] { + const auto reg_m = ir.GetVector(m); + const size_t esize = 16U << sz; + const auto shift = static_cast(8U << sz); + + // 64-bit regions + if (op == 0b00) { + IR::U128 result = ir.VectorOr(ir.VectorLogicalShiftRight(esize, reg_m, shift), + ir.VectorLogicalShiftLeft(esize, reg_m, shift)); + + switch (sz) { + case 0: // 8-bit elements + result = ir.VectorShuffleLowHalfwords(result, 0b00011011); + result = ir.VectorShuffleHighHalfwords(result, 0b00011011); + break; + case 1: // 16-bit elements + result = ir.VectorShuffleLowHalfwords(result, 0b01001110); + result = ir.VectorShuffleHighHalfwords(result, 0b01001110); + break; + } + + return result; + } + + // 32-bit regions + if (op == 0b01) { + IR::U128 result = ir.VectorOr(ir.VectorLogicalShiftRight(esize, reg_m, shift), + ir.VectorLogicalShiftLeft(esize, reg_m, shift)); + + // If dealing with 8-bit elements we'll need to shuffle the bytes in each halfword + // e.g. Assume the following numbers point out bytes in a 32-bit word, we're essentially + // changing [3, 2, 1, 0] to [2, 3, 0, 1] + if (sz == 0) { + result = ir.VectorShuffleLowHalfwords(result, 0b10110001); + result = ir.VectorShuffleHighHalfwords(result, 0b10110001); + } + + return result; + } + + // 16-bit regions + return ir.VectorOr(ir.VectorLogicalShiftRight(esize, reg_m, 8), + ir.VectorLogicalShiftLeft(esize, reg_m, 8)); + }(); + + ir.SetVector(d, result); + return true; +} + bool ArmTranslatorVisitor::asimd_VCLS(bool D, size_t sz, size_t Vd, bool Q, bool M, size_t Vm) { if (sz == 0b11) { return UndefinedInstruction(); diff --git a/src/frontend/A32/translate/impl/translate_arm.h b/src/frontend/A32/translate/impl/translate_arm.h index 7e964ffd..094cda31 100644 --- a/src/frontend/A32/translate/impl/translate_arm.h +++ b/src/frontend/A32/translate/impl/translate_arm.h @@ -452,6 +452,7 @@ struct ArmTranslatorVisitor final { 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); // 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); bool asimd_VCLZ(bool D, size_t sz, size_t Vd, bool Q, bool M, size_t Vm); bool asimd_VCNT(bool D, size_t sz, size_t Vd, bool Q, bool M, size_t Vm);