diff --git a/src/backend/x64/emit_x64_vector_floating_point.cpp b/src/backend/x64/emit_x64_vector_floating_point.cpp index 7cf3392c..a715c99e 100644 --- a/src/backend/x64/emit_x64_vector_floating_point.cpp +++ b/src/backend/x64/emit_x64_vector_floating_point.cpp @@ -1241,7 +1241,7 @@ void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { const size_t fbits = inst->GetArg(1).GetU8(); const auto rounding = static_cast(inst->GetArg(2).GetU8()); - using fbits_list = mp::vllift>; + using fbits_list = mp::vllift>; using rounding_list = mp::list< std::integral_constant, std::integral_constant, diff --git a/src/frontend/A64/decoder/a64.inc b/src/frontend/A64/decoder/a64.inc index 090ea301..6f6e1e07 100644 --- a/src/frontend/A64/decoder/a64.inc +++ b/src/frontend/A64/decoder/a64.inc @@ -801,8 +801,8 @@ INST(RSHRN, "RSHRN, RSHRN2", "0Q001 INST(SQSHRN_2, "SQSHRN, SQSHRN2", "0Q0011110IIIIiii100101nnnnnddddd") INST(SQRSHRN_2, "SQRSHRN, SQRSHRN2", "0Q0011110IIIIiii100111nnnnnddddd") INST(SSHLL, "SSHLL, SSHLL2", "0Q0011110IIIIiii101001nnnnnddddd") -//INST(SCVTF_fix_2, "SCVTF (vector, fixed-point)", "0Q0011110IIIIiii111001nnnnnddddd") -//INST(FCVTZS_fix_2, "FCVTZS (vector, fixed-point)", "0Q0011110IIIIiii111111nnnnnddddd") +INST(SCVTF_fix_2, "SCVTF (vector, fixed-point)", "0Q0011110IIIIiii111001nnnnnddddd") +INST(FCVTZS_fix_2, "FCVTZS (vector, fixed-point)", "0Q0011110IIIIiii111111nnnnnddddd") INST(USHR_2, "USHR", "0Q1011110IIIIiii000001nnnnnddddd") INST(USRA_2, "USRA", "0Q1011110IIIIiii000101nnnnnddddd") INST(URSHR_2, "URSHR", "0Q1011110IIIIiii001001nnnnnddddd") @@ -816,8 +816,8 @@ INST(SQRSHRUN_2, "SQRSHRUN, SQRSHRUN2", "0Q101 INST(UQSHRN_2, "UQSHRN, UQSHRN2", "0Q1011110IIIIiii100101nnnnnddddd") INST(UQRSHRN_2, "UQRSHRN, UQRSHRN2", "0Q1011110IIIIiii100111nnnnnddddd") INST(USHLL, "USHLL, USHLL2", "0Q1011110IIIIiii101001nnnnnddddd") -//INST(UCVTF_fix_2, "UCVTF (vector, fixed-point)", "0Q1011110IIIIiii111001nnnnnddddd") -//INST(FCVTZU_fix_2, "FCVTZU (vector, fixed-point)", "0Q1011110IIIIiii111111nnnnnddddd") +INST(UCVTF_fix_2, "UCVTF (vector, fixed-point)", "0Q1011110IIIIiii111001nnnnnddddd") +INST(FCVTZU_fix_2, "FCVTZU (vector, fixed-point)", "0Q1011110IIIIiii111111nnnnnddddd") // Data Processing - FP and SIMD - SIMD vector x indexed element INST(SMLAL_elt, "SMLAL, SMLAL2 (by element)", "0Q001111zzLMmmmm0010H0nnnnnddddd") diff --git a/src/frontend/A64/translate/impl/simd_shift_by_immediate.cpp b/src/frontend/A64/translate/impl/simd_shift_by_immediate.cpp index ca5dc019..197740b0 100644 --- a/src/frontend/A64/translate/impl/simd_shift_by_immediate.cpp +++ b/src/frontend/A64/translate/impl/simd_shift_by_immediate.cpp @@ -5,6 +5,7 @@ */ #include "common/bit_util.h" +#include "common/fp/rounding_mode.h" #include "frontend/A64/translate/impl/impl.h" namespace Dynarmic::A64 { @@ -30,6 +31,11 @@ enum class Narrowing { SaturateToSigned, }; +enum class FloatConversionDirection { + FixedToFloat, + FloatToFixed, +}; + IR::U128 PerformRoundingCorrection(TranslatorVisitor& v, size_t esize, u64 round_value, IR::U128 original, IR::U128 shifted) { const IR::U128 round_const = v.ir.VectorBroadcast(esize, v.I(esize, round_value)); const IR::U128 round_correction = v.ir.VectorEqual(esize, v.ir.VectorAnd(original, round_const), round_const); @@ -176,6 +182,45 @@ bool SaturatingShiftLeft(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, v.V(datasize, Vd, result); return true; } + +bool ConvertFloat(TranslatorVisitor& v, bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd, Signedness signedness, FloatConversionDirection direction, FP::RoundingMode rounding_mode) { + if (immh == 0b0000) { + return v.DecodeError(); + } + + if (immh == 0b0001 || immh == 0b0010 || immh == 0b0011) { + return v.ReservedValue(); + } + + if (immh.Bit<3>() && !Q) { + return v.ReservedValue(); + } + + const size_t esize = 8 << Common::HighestSetBit(immh.ZeroExtend()); + const size_t datasize = Q ? 128 : 64; + + const u8 fbits = static_cast(esize * 2) - concatenate(immh, immb).ZeroExtend(); + + const IR::U128 operand = v.V(datasize, Vn); + const IR::U128 result = [&] { + switch (direction) { + case FloatConversionDirection::FixedToFloat: + return signedness == Signedness::Signed + ? v.ir.FPVectorFromSignedFixed(esize, operand, fbits, rounding_mode) + : v.ir.FPVectorFromUnsignedFixed(esize, operand, fbits, rounding_mode); + case FloatConversionDirection::FloatToFixed: + return signedness == Signedness::Signed + ? v.ir.FPVectorToSignedFixed(esize, operand, fbits, rounding_mode) + : v.ir.FPVectorToUnsignedFixed(esize, operand, fbits, rounding_mode); + } + UNREACHABLE(); + return IR::U128{}; + }(); + + v.V(datasize, Vd, result); + return true; +} + } // Anonymous namespace bool TranslatorVisitor::SSHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { @@ -329,4 +374,20 @@ bool TranslatorVisitor::SLI_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) return true; } +bool TranslatorVisitor::SCVTF_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return ConvertFloat(*this, Q, immh, immb, Vn, Vd, Signedness::Signed, FloatConversionDirection::FixedToFloat, ir.current_location->FPCR().RMode()); +} + +bool TranslatorVisitor::UCVTF_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return ConvertFloat(*this, Q, immh, immb, Vn, Vd, Signedness::Unsigned, FloatConversionDirection::FixedToFloat, ir.current_location->FPCR().RMode()); +} + +bool TranslatorVisitor::FCVTZS_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return ConvertFloat(*this, Q, immh, immb, Vn, Vd, Signedness::Signed, FloatConversionDirection::FloatToFixed, FP::RoundingMode::TowardsZero); +} + +bool TranslatorVisitor::FCVTZU_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return ConvertFloat(*this, Q, immh, immb, Vn, Vd, Signedness::Unsigned, FloatConversionDirection::FloatToFixed, FP::RoundingMode::TowardsZero); +} + } // namespace Dynarmic::A64