diff --git a/src/frontend/A32/decoder/asimd.inc b/src/frontend/A32/decoder/asimd.inc index bf71fe8e..119ad330 100644 --- a/src/frontend/A32/decoder/asimd.inc +++ b/src/frontend/A32/decoder/asimd.inc @@ -126,7 +126,7 @@ INST(arm_UDF, "UNALLOCATED (VRINTA)", "111100111-11--10----010 INST(arm_UDF, "UNALLOCATED (VRINTZ)", "111100111-11--10----01011--0----") INST(arm_UDF, "UNALLOCATED (VRINTM)", "111100111-11--10----01101--0----") INST(arm_UDF, "UNALLOCATED (VRINTP)", "111100111-11--10----01111--0----") -INST(arm_UDF, "UNALLOCATED (VCVT half)", "111100111-11--10----011-00-0----") // ASIMD +INST(asimd_VCVT_half, "VCVT (half-precision)", "111100111D11zz10dddd011o00M0mmmm") // ASIMD INST(arm_UDF, "UNALLOCATED", "111100111-11--10----011-01-0----") // ASIMD INST(arm_UDF, "UNALLOCATED (VCVTA)", "111100111-11--11----0000---0----") INST(arm_UDF, "UNALLOCATED (VCVTN)", "111100111-11--11----0001---0----") 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 97122618..d4c3153f 100644 --- a/src/frontend/A32/translate/impl/asimd_two_regs_misc.cpp +++ b/src/frontend/A32/translate/impl/asimd_two_regs_misc.cpp @@ -611,6 +611,40 @@ bool TranslatorVisitor::asimd_VSHLL_max(bool D, size_t sz, size_t Vd, bool M, si return true; } +bool TranslatorVisitor::asimd_VCVT_half(bool D, size_t sz, size_t Vd, bool half_to_single, bool M, size_t Vm) { + if (sz != 0b01) { + return UndefinedInstruction(); + } + if (half_to_single && Common::Bit<0>(Vd)) { + return UndefinedInstruction(); + } + if (!half_to_single && Common::Bit<0>(Vm)) { + return UndefinedInstruction(); + } + + const size_t esize = 8U << sz; + const size_t num_elements = 4; + const auto rounding_mode = FP::RoundingMode::ToNearest_TieEven; // StandardFPSCRValue().RMode + const auto d = ToVector(half_to_single, Vd, D); + const auto m = ToVector(!half_to_single, Vm, M); + + const auto operand = ir.GetVector(m); + IR::U128 result = ir.ZeroVector(); + for (size_t i = 0; i < num_elements; i++) { + if (half_to_single) { + const IR::U16 old_element = ir.VectorGetElement(esize, operand, i); + const IR::U32 new_element = ir.FPHalfToSingle(old_element, rounding_mode); + result = ir.VectorSetElement(esize * 2, result, i, new_element); + } else { + const IR::U32 old_element = ir.VectorGetElement(esize * 2, operand, i); + const IR::U16 new_element = ir.FPSingleToHalf(old_element, rounding_mode); + result = ir.VectorSetElement(esize, result, i, new_element); + } + } + ir.SetVector(d, result); + return true; +} + bool TranslatorVisitor::asimd_VRECPE(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm) { if (Q && (Common::Bit<0>(Vd) || Common::Bit<0>(Vm))) { return UndefinedInstruction(); diff --git a/src/frontend/A32/translate/impl/translate.h b/src/frontend/A32/translate/impl/translate.h index 2f67ad4b..3d298310 100644 --- a/src/frontend/A32/translate/impl/translate.h +++ b/src/frontend/A32/translate/impl/translate.h @@ -940,6 +940,7 @@ struct TranslatorVisitor final { bool asimd_VQMOVUN(bool D, size_t sz, size_t Vd, bool M, size_t Vm); bool asimd_VQMOVN(bool D, size_t sz, size_t Vd, bool op, bool M, size_t Vm); bool asimd_VSHLL_max(bool D, size_t sz, size_t Vd, bool M, size_t Vm); + bool asimd_VCVT_half(bool D, size_t sz, size_t Vd, bool op, bool M, size_t Vm); bool asimd_VRECPE(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm); bool asimd_VRSQRTE(bool D, size_t sz, size_t Vd, bool F, bool Q, bool M, size_t Vm); bool asimd_VCVT_integer(bool D, size_t sz, size_t Vd, bool op, bool U, bool Q, bool M, size_t Vm);