diff --git a/src/frontend/A32/decoder/vfp.inc b/src/frontend/A32/decoder/vfp.inc index 36871c76..aca0c62e 100644 --- a/src/frontend/A32/decoder/vfp.inc +++ b/src/frontend/A32/decoder/vfp.inc @@ -19,8 +19,8 @@ INST(vfp_VMOV_reg, "VMOV (reg)", "cccc11101D110000dddd101z0 INST(vfp_VABS, "VABS", "cccc11101D110000dddd101z11M0mmmm") // VFPv2 INST(vfp_VNEG, "VNEG", "cccc11101D110001dddd101z01M0mmmm") // VFPv2 INST(vfp_VSQRT, "VSQRT", "cccc11101D110001dddd101z11M0mmmm") // VFPv2 -//INST(vfp_VCVTB, "VCVTB", "cccc11101D11001odddd1010T1M0mmmm") // VFPv3HP -//INST(vfp_VCVTT, "VCVTT", "cccc11101D11001odddd1010T1M0mmmm") // VFPv3HP +INST(vfp_VCVTB, "VCVTB", "cccc11101D11001odddd101z01M0mmmm") // VFPv3HP +INST(vfp_VCVTT, "VCVTT", "cccc11101D11001odddd101z11M0mmmm") // VFPv3HP INST(vfp_VCMP, "VCMP", "cccc11101D110100dddd101zE1M0mmmm") // VFPv2 INST(vfp_VCMP_zero, "VCMP (with zero)", "cccc11101D110101dddd101zE1000000") // VFPv2 INST(vfp_VCVT_f_to_f, "VCVT (f32<->f64)", "cccc11101D110111dddd101z11M0mmmm") // VFPv2 diff --git a/src/frontend/A32/disassembler/disassembler_arm.cpp b/src/frontend/A32/disassembler/disassembler_arm.cpp index 5fc0b0df..196bf3e4 100644 --- a/src/frontend/A32/disassembler/disassembler_arm.cpp +++ b/src/frontend/A32/disassembler/disassembler_arm.cpp @@ -1280,6 +1280,20 @@ public: return fmt::format("vsqrt{}.{} {}, {}", CondToString(cond), sz ? "f64" : "f32", FPRegStr(sz, Vd, D), FPRegStr(sz, Vm, M)); } + std::string vfp_VCVTB(Cond cond, bool D, bool op, size_t Vd, bool sz, bool M, size_t Vm) { + const bool convert_from_half = !op; + const char* const to = convert_from_half ? (sz ? "f64" : "f32") : "f16"; + const char* const from = convert_from_half ? "f16" : (sz ? "f64" : "f32"); + return fmt::format("vcvtb{}.{}.{} {}, {}", CondToString(cond), to, from, FPRegStr(convert_from_half ? sz : false, Vd, D), FPRegStr(convert_from_half ? false : sz, Vm, M)); + } + + std::string vfp_VCVTT(Cond cond, bool D, bool op, size_t Vd, bool sz, bool M, size_t Vm) { + const bool convert_from_half = !op; + const char* const to = convert_from_half ? (sz ? "f64" : "f32") : "f16"; + const char* const from = convert_from_half ? "f16" : (sz ? "f64" : "f32"); + return fmt::format("vcvtt{}.{}.{} {}, {}", CondToString(cond), to, from, FPRegStr(convert_from_half ? sz : false, Vd, D), FPRegStr(convert_from_half ? false : sz, Vm, M)); + } + std::string vfp_VCVT_f_to_f(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm) { return fmt::format("vcvt{}.{}.{} {}, {}", CondToString(cond), !sz ? "f64" : "f32", sz ? "f64" : "f32", FPRegStr(!sz, Vd, D), FPRegStr(sz, Vm, M)); } diff --git a/src/frontend/A32/translate/impl/translate_arm.h b/src/frontend/A32/translate/impl/translate_arm.h index a002e7f7..95a1d27b 100644 --- a/src/frontend/A32/translate/impl/translate_arm.h +++ b/src/frontend/A32/translate/impl/translate_arm.h @@ -391,6 +391,8 @@ struct ArmTranslatorVisitor final { bool vfp_VABS(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm); bool vfp_VNEG(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm); bool vfp_VSQRT(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm); + bool vfp_VCVTB(Cond cond, bool D, bool op, size_t Vd, bool sz, bool M, size_t Vm); + bool vfp_VCVTT(Cond cond, bool D, bool op, size_t Vd, bool sz, bool M, size_t Vm); bool vfp_VCVT_f_to_f(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm); bool vfp_VCVT_from_int(Cond cond, bool D, size_t Vd, bool sz, bool is_signed, bool M, size_t Vm); bool vfp_VCVT_to_u32(Cond cond, bool D, size_t Vd, bool sz, bool round_towards_zero, bool M, size_t Vm); diff --git a/src/frontend/A32/translate/impl/vfp.cpp b/src/frontend/A32/translate/impl/vfp.cpp index e2e41140..7f6830c1 100644 --- a/src/frontend/A32/translate/impl/vfp.cpp +++ b/src/frontend/A32/translate/impl/vfp.cpp @@ -548,6 +548,70 @@ bool ArmTranslatorVisitor::vfp_VSQRT(Cond cond, bool D, size_t Vd, bool sz, bool }); } +// VCVTB.f32.f16
, +// VCVTB.f64.f16
, +// VCVTB.f16.f32
, +// VCVTB.f16.f64
, +bool ArmTranslatorVisitor::vfp_VCVTB(Cond cond, bool D, bool op, size_t Vd, bool sz, bool M, size_t Vm) { + if (!ConditionPassed(cond)) { + return true; + } + + const bool convert_from_half = !op; + const auto rounding_mode = ir.current_location.FPSCR().RMode(); + if (convert_from_half) { + const auto d = ToExtReg(sz, Vd, D); + const auto m = ToExtReg(false, Vm, M); + + return EmitVfpVectorOperation(sz, d, m, [this, sz, rounding_mode](ExtReg d, ExtReg m) { + const auto reg_m = ir.LeastSignificantHalf(ir.GetExtendedRegister(m)); + const auto result = sz ? IR::U32U64{ir.FPHalfToDouble(reg_m, rounding_mode)} : IR::U32U64{ir.FPHalfToSingle(reg_m, rounding_mode)}; + ir.SetExtendedRegister(d, result); + }); + } else { + const auto d = ToExtReg(false, Vd, D); + const auto m = ToExtReg(sz, Vm, M); + + return EmitVfpVectorOperation(sz, d, m, [this, sz, rounding_mode](ExtReg d, ExtReg m) { + const auto reg_m = ir.GetExtendedRegister(m); + const auto result = sz ? ir.FPDoubleToHalf(reg_m, rounding_mode) : ir.FPSingleToHalf(reg_m, rounding_mode); + ir.SetExtendedRegister(d, ir.Or(ir.And(ir.GetExtendedRegister(d), ir.Imm32(0xFFFF0000)), ir.ZeroExtendToWord(result))); + }); + } +} + +// VCVTT.f32.f16
, +// VCVTT.f64.f16
, +// VCVTT.f16.f32
, +// VCVTT.f16.f64
, +bool ArmTranslatorVisitor::vfp_VCVTT(Cond cond, bool D, bool op, size_t Vd, bool sz, bool M, size_t Vm) { + if (!ConditionPassed(cond)) { + return true; + } + + const bool convert_from_half = !op; + const auto rounding_mode = ir.current_location.FPSCR().RMode(); + if (convert_from_half) { + const auto d = ToExtReg(sz, Vd, D); + const auto m = ToExtReg(false, Vm, M); + + return EmitVfpVectorOperation(sz, d, m, [this, sz, rounding_mode](ExtReg d, ExtReg m) { + const auto reg_m = ir.LeastSignificantHalf(ir.LogicalShiftRight(ir.GetExtendedRegister(m), ir.Imm8(16))); + const auto result = sz ? IR::U32U64{ir.FPHalfToDouble(reg_m, rounding_mode)} : IR::U32U64{ir.FPHalfToSingle(reg_m, rounding_mode)}; + ir.SetExtendedRegister(d, result); + }); + } else { + const auto d = ToExtReg(false, Vd, D); + const auto m = ToExtReg(sz, Vm, M); + + return EmitVfpVectorOperation(sz, d, m, [this, sz, rounding_mode](ExtReg d, ExtReg m) { + const auto reg_m = ir.GetExtendedRegister(m); + const auto result = sz ? ir.FPDoubleToHalf(reg_m, rounding_mode) : ir.FPSingleToHalf(reg_m, rounding_mode); + ir.SetExtendedRegister(d, ir.Or(ir.And(ir.GetExtendedRegister(d), ir.Imm32(0x0000FFFF)), ir.LogicalShiftLeft(ir.ZeroExtendToWord(result), ir.Imm8(16)))); + }); + } +} + // VCVT.F64.F32
, // VCVT.F32.F64 , bool ArmTranslatorVisitor::vfp_VCVT_f_to_f(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm) {