VFPv5: Implement VRINT{A,N,P,M}
This commit is contained in:
parent
3e252cdbfc
commit
6a965b80d6
4 changed files with 72 additions and 43 deletions
|
@ -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_u32, "VCVT (to u32)", "cccc11101D111100dddd101zr1M0mmmm") // VFPv2
|
||||||
INST(vfp_VCVT_to_s32, "VCVT (to s32)", "cccc11101D111101dddd101zr1M0mmmm") // VFPv2
|
INST(vfp_VCVT_to_s32, "VCVT (to s32)", "cccc11101D111101dddd101zr1M0mmmm") // VFPv2
|
||||||
//INST(vfp_VCVT_to_fixed, "VCVT (to fixed)", "cccc11101D11111Udddd101zx1i0vvvv") // VFPv3
|
//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
|
//INST(vfp_VCVT_rm, "VCVT{A,N,P,M}", "111111101D1111mmdddd101zU1M0mmmm") // VFPv5
|
||||||
|
|
||||||
// Floating-point move instructions
|
// Floating-point move instructions
|
||||||
|
|
|
@ -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));
|
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) {
|
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));
|
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));
|
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) {
|
std::string vfp_VRINT_rm(bool D, size_t rm, size_t Vd, bool sz, bool M, size_t Vm) {
|
||||||
return fmt::format("vcmp{}{}.{} {}, {}", E ? "e" : "", CondToString(cond), sz ? "f64" : "f32", FPRegStr(sz, Vd, D), FPRegStr(sz, Vm, M));
|
return fmt::format("vrint{}.{} {}, {}", "anpm"[rm], 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_VMSR(Cond cond, Reg t) {
|
std::string vfp_VMSR(Cond cond, Reg t) {
|
||||||
return fmt::format("vmsr{} fpscr, {}", CondToString(cond), t);
|
return fmt::format("vmsr{} fpscr, {}", CondToString(cond), t);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string vfp_VMRS(Cond cond, Reg t) {
|
std::string vfp_VMRS(Cond cond, Reg t) {
|
||||||
if (t == Reg::R15) {
|
if (t == Reg::R15) {
|
||||||
return fmt::format("vmrs{} apsr_nzcv, fpscr", CondToString(cond));
|
return fmt::format("vmrs{} apsr_nzcv, fpscr", CondToString(cond));
|
||||||
|
|
|
@ -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_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_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_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_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_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_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_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_VRINT_rm(bool D, size_t rm, size_t Vd, bool sz, bool M, size_t Vm);
|
||||||
bool vfp_VCMP_zero(Cond cond, bool D, size_t Vd, bool sz, bool E);
|
|
||||||
|
|
||||||
// Floating-point system register access
|
// Floating-point system register access
|
||||||
bool vfp_VMSR(Cond cond, Reg t);
|
bool vfp_VMSR(Cond cond, Reg t);
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
#include "frontend/A32/translate/impl/translate_arm.h"
|
#include "frontend/A32/translate/impl/translate_arm.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
namespace Dynarmic::A32 {
|
namespace Dynarmic::A32 {
|
||||||
|
|
||||||
template <typename FnT>
|
template <typename FnT>
|
||||||
|
@ -681,6 +683,46 @@ bool ArmTranslatorVisitor::vfp_VCVTT(Cond cond, bool D, bool op, size_t Vd, bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VCMP{E}.F32 <Sd>, <Sm>
|
||||||
|
// VCMP{E}.F64 <Dd>, <Dm>
|
||||||
|
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 <Sd>, #0.0
|
||||||
|
// VCMP{E}.F64 <Dd>, #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<c>.F64.F32 <Dd>, <Sm>
|
// VCVT<c>.F64.F32 <Dd>, <Sm>
|
||||||
// VCVT<c>.F32.F64 <Sd>, <Dm>
|
// VCVT<c>.F32.F64 <Sd>, <Dm>
|
||||||
bool ArmTranslatorVisitor::vfp_VCVT_f_to_f(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// VCMP{E}.F32 <Sd>, <Sm>
|
// VRINT{A,N,P,M}.F32 <Sd>, <Sm>
|
||||||
// VCMP{E}.F64 <Dd>, <Dm>
|
// VRINT{A,N,P,M}.F64 <Dd>, <Dm>
|
||||||
bool ArmTranslatorVisitor::vfp_VCMP(Cond cond, bool D, size_t Vd, bool sz, bool E, bool M, size_t Vm) {
|
bool ArmTranslatorVisitor::vfp_VRINT_rm(bool D, size_t rm, size_t Vd, bool sz, bool M, size_t Vm) {
|
||||||
if (!ConditionPassed(cond)) {
|
const std::array rm_lookup{
|
||||||
return true;
|
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 d = ToExtReg(sz, Vd, D);
|
||||||
const auto m = ToExtReg(sz, Vm, M);
|
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 EmitVfpVectorOperation(sz, d, m, [this, rounding_mode](ExtReg d, ExtReg m) {
|
||||||
return true;
|
const auto reg_m = ir.GetExtendedRegister(m);
|
||||||
}
|
const auto result = ir.FPRoundInt(reg_m, rounding_mode, false);
|
||||||
|
ir.SetExtendedRegister(d, result);
|
||||||
// VCMP{E}.F32 <Sd>, #0.0
|
});
|
||||||
// VCMP{E}.F64 <Dd>, #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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// VMSR FPSCR, <Rt>
|
// VMSR FPSCR, <Rt>
|
||||||
|
|
Loading…
Reference in a new issue