From 6a965b80d6d44a9326695216107662ba2e668e35 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Fri, 19 Jun 2020 20:21:21 +0100 Subject: [PATCH] VFPv5: Implement VRINT{A,N,P,M} --- src/frontend/A32/decoder/vfp.inc | 2 +- .../A32/disassembler/disassembler_arm.cpp | 17 ++-- .../A32/translate/impl/translate_arm.h | 5 +- src/frontend/A32/translate/impl/vfp.cpp | 91 ++++++++++++------- 4 files changed, 72 insertions(+), 43 deletions(-) diff --git a/src/frontend/A32/decoder/vfp.inc b/src/frontend/A32/decoder/vfp.inc index a043cb0f..07ce7895 100644 --- a/src/frontend/A32/decoder/vfp.inc +++ b/src/frontend/A32/decoder/vfp.inc @@ -32,7 +32,7 @@ INST(vfp_VCVT_from_int, "VCVT (from int)", "cccc11101D111000dddd101zs INST(vfp_VCVT_to_u32, "VCVT (to u32)", "cccc11101D111100dddd101zr1M0mmmm") // VFPv2 INST(vfp_VCVT_to_s32, "VCVT (to s32)", "cccc11101D111101dddd101zr1M0mmmm") // VFPv2 //INST(vfp_VCVT_to_fixed, "VCVT (to fixed)", "cccc11101D11111Udddd101zx1i0vvvv") // VFPv3 -//INST(vfp_VRINT_rm, "VRINT{A,N,P,M}", "111111101D1110mmdddd101z01M0mmmm") // VFPv5 +INST(vfp_VRINT_rm, "VRINT{A,N,P,M}", "111111101D1110mmdddd101z01M0mmmm") // VFPv5 //INST(vfp_VCVT_rm, "VCVT{A,N,P,M}", "111111101D1111mmdddd101zU1M0mmmm") // VFPv5 // Floating-point move instructions diff --git a/src/frontend/A32/disassembler/disassembler_arm.cpp b/src/frontend/A32/disassembler/disassembler_arm.cpp index 606c3145..5b43ab17 100644 --- a/src/frontend/A32/disassembler/disassembler_arm.cpp +++ b/src/frontend/A32/disassembler/disassembler_arm.cpp @@ -1367,6 +1367,14 @@ public: 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_VCMP(Cond cond, bool D, size_t Vd, bool sz, bool E, bool M, size_t Vm) { + return fmt::format("vcmp{}{}.{} {}, {}", E ? "e" : "", CondToString(cond), sz ? "f64" : "f32", FPRegStr(sz, Vd, D), FPRegStr(sz, Vm, M)); + } + + std::string vfp_VCMP_zero(Cond cond, bool D, size_t Vd, bool sz, bool E) { + return fmt::format("vcmp{}{}.{} {}, #0.0", E ? "e" : "", CondToString(cond), sz ? "f64" : "f32", FPRegStr(sz, Vd, D)); + } + 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)); } @@ -1383,17 +1391,14 @@ public: return fmt::format("vcvt{}{}.s32.{} {}, {}", round_towards_zero ? "" : "r", CondToString(cond), sz ? "f64" : "f32", FPRegStr(false, Vd, D), FPRegStr(sz, Vm, M)); } - std::string vfp_VCMP(Cond cond, bool D, size_t Vd, bool sz, bool E, bool M, size_t Vm) { - return fmt::format("vcmp{}{}.{} {}, {}", E ? "e" : "", CondToString(cond), sz ? "f64" : "f32", FPRegStr(sz, Vd, D), FPRegStr(sz, Vm, M)); - } - - std::string vfp_VCMP_zero(Cond cond, bool D, size_t Vd, bool sz, bool E) { - return fmt::format("vcmp{}{}.{} {}, #0.0", E ? "e" : "", CondToString(cond), sz ? "f64" : "f32", FPRegStr(sz, Vd, D)); + std::string vfp_VRINT_rm(bool D, size_t rm, size_t Vd, bool sz, bool M, size_t Vm) { + return fmt::format("vrint{}.{} {}, {}", "anpm"[rm], sz ? "f64" : "f32", FPRegStr(sz, Vd, D), FPRegStr(sz, Vm, M)); } std::string vfp_VMSR(Cond cond, Reg t) { return fmt::format("vmsr{} fpscr, {}", CondToString(cond), t); } + std::string vfp_VMRS(Cond cond, Reg t) { if (t == Reg::R15) { return fmt::format("vmrs{} apsr_nzcv, fpscr", CondToString(cond)); diff --git a/src/frontend/A32/translate/impl/translate_arm.h b/src/frontend/A32/translate/impl/translate_arm.h index 9fd6642d..d1b093bd 100644 --- a/src/frontend/A32/translate/impl/translate_arm.h +++ b/src/frontend/A32/translate/impl/translate_arm.h @@ -414,12 +414,13 @@ struct ArmTranslatorVisitor final { 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_VCMP(Cond cond, bool D, size_t Vd, bool sz, bool E, bool M, size_t Vm); + bool vfp_VCMP_zero(Cond cond, bool D, size_t Vd, bool sz, bool E); 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); bool vfp_VCVT_to_s32(Cond cond, bool D, size_t Vd, bool sz, bool round_towards_zero, bool M, size_t Vm); - bool vfp_VCMP(Cond cond, bool D, size_t Vd, bool sz, bool E, bool M, size_t Vm); - bool vfp_VCMP_zero(Cond cond, bool D, size_t Vd, bool sz, bool E); + bool vfp_VRINT_rm(bool D, size_t rm, size_t Vd, bool sz, bool M, size_t Vm); // Floating-point system register access bool vfp_VMSR(Cond cond, Reg t); diff --git a/src/frontend/A32/translate/impl/vfp.cpp b/src/frontend/A32/translate/impl/vfp.cpp index 6558656e..340f3c1b 100644 --- a/src/frontend/A32/translate/impl/vfp.cpp +++ b/src/frontend/A32/translate/impl/vfp.cpp @@ -5,6 +5,8 @@ #include "frontend/A32/translate/impl/translate_arm.h" +#include + namespace Dynarmic::A32 { template @@ -681,6 +683,46 @@ bool ArmTranslatorVisitor::vfp_VCVTT(Cond cond, bool D, bool op, size_t Vd, bool } } +// VCMP{E}.F32 , +// VCMP{E}.F64
, +bool ArmTranslatorVisitor::vfp_VCMP(Cond cond, bool D, size_t Vd, bool sz, bool E, bool M, size_t Vm) { + if (!ConditionPassed(cond)) { + return true; + } + + const auto d = ToExtReg(sz, Vd, D); + const auto m = ToExtReg(sz, Vm, M); + const auto exc_on_qnan = E; + const auto reg_d = ir.GetExtendedRegister(d); + const auto reg_m = ir.GetExtendedRegister(m); + const auto nzcv = ir.FPCompare(reg_d, reg_m, exc_on_qnan, true); + + ir.SetFpscrNZCV(nzcv); + return true; +} + +// VCMP{E}.F32 , #0.0 +// VCMP{E}.F64
, #0.0 +bool ArmTranslatorVisitor::vfp_VCMP_zero(Cond cond, bool D, size_t Vd, bool sz, bool E) { + if (!ConditionPassed(cond)) { + return true; + } + + const auto d = ToExtReg(sz, Vd, D); + const auto exc_on_qnan = E; + const auto reg_d = ir.GetExtendedRegister(d); + + if (sz) { + const auto nzcv = ir.FPCompare(reg_d, ir.Imm64(0), exc_on_qnan, true); + ir.SetFpscrNZCV(nzcv); + } else { + const auto nzcv = ir.FPCompare(reg_d, ir.Imm32(0), exc_on_qnan, true); + ir.SetFpscrNZCV(nzcv); + } + + return true; +} + // 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) { @@ -763,44 +805,25 @@ bool ArmTranslatorVisitor::vfp_VCVT_to_s32(Cond cond, bool D, size_t Vd, bool sz return true; } -// VCMP{E}.F32 , -// VCMP{E}.F64
, -bool ArmTranslatorVisitor::vfp_VCMP(Cond cond, bool D, size_t Vd, bool sz, bool E, bool M, size_t Vm) { - if (!ConditionPassed(cond)) { - return true; - } +// VRINT{A,N,P,M}.F32 , +// VRINT{A,N,P,M}.F64
, +bool ArmTranslatorVisitor::vfp_VRINT_rm(bool D, size_t rm, size_t Vd, bool sz, bool M, size_t Vm) { + const std::array rm_lookup{ + FP::RoundingMode::ToNearest_TieAwayFromZero, + FP::RoundingMode::ToNearest_TieEven, + FP::RoundingMode::TowardsPlusInfinity, + FP::RoundingMode::TowardsMinusInfinity, + }; + const FP::RoundingMode rounding_mode = rm_lookup[rm]; const auto d = ToExtReg(sz, Vd, D); const auto m = ToExtReg(sz, Vm, M); - const auto exc_on_qnan = E; - const auto reg_d = ir.GetExtendedRegister(d); - const auto reg_m = ir.GetExtendedRegister(m); - const auto nzcv = ir.FPCompare(reg_d, reg_m, exc_on_qnan, true); - ir.SetFpscrNZCV(nzcv); - return true; -} - -// VCMP{E}.F32 , #0.0 -// VCMP{E}.F64
, #0.0 -bool ArmTranslatorVisitor::vfp_VCMP_zero(Cond cond, bool D, size_t Vd, bool sz, bool E) { - if (!ConditionPassed(cond)) { - return true; - } - - const auto d = ToExtReg(sz, Vd, D); - const auto exc_on_qnan = E; - const auto reg_d = ir.GetExtendedRegister(d); - - if (sz) { - const auto nzcv = ir.FPCompare(reg_d, ir.Imm64(0), exc_on_qnan, true); - ir.SetFpscrNZCV(nzcv); - } else { - const auto nzcv = ir.FPCompare(reg_d, ir.Imm32(0), exc_on_qnan, true); - ir.SetFpscrNZCV(nzcv); - } - - return true; + return EmitVfpVectorOperation(sz, d, m, [this, rounding_mode](ExtReg d, ExtReg m) { + const auto reg_m = ir.GetExtendedRegister(m); + const auto result = ir.FPRoundInt(reg_m, rounding_mode, false); + ir.SetExtendedRegister(d, result); + }); } // VMSR FPSCR,