diff --git a/src/frontend/A32/decoder/vfp.inc b/src/frontend/A32/decoder/vfp.inc index 9b5cfa11..b58a6ccb 100644 --- a/src/frontend/A32/decoder/vfp.inc +++ b/src/frontend/A32/decoder/vfp.inc @@ -44,6 +44,9 @@ INST(vfp_VMOV_2u32_2f32, "VMOV (2xcore to 2xf32)", "cccc11000100uuuutttt10100 INST(vfp_VMOV_2f32_2u32, "VMOV (2xf32 to 2xcore)", "cccc11000101uuuutttt101000M1mmmm") // VFPv2 INST(vfp_VMOV_2u32_f64, "VMOV (2xcore to f64)", "cccc11000100uuuutttt101100M1mmmm") // VFPv2 INST(vfp_VMOV_f64_2u32, "VMOV (f64 to 2xcore)", "cccc11000101uuuutttt101100M1mmmm") // VFPv2 +INST(vfp_VMOV_from_i32, "VMOV (core to i32)" , "cccc111000i0nnnntttt1011N0010000") // VFPv4 +INST(vfp_VMOV_from_i16, "VMOV (core to i16)" , "cccc111000i0nnnntttt1011Ni110000") // ASIMD +INST(vfp_VMOV_from_i8, "VMOV (core to i8)", "cccc111001i0nnnntttt1011Nii10000") // ASIMD INST(vfp_VMOV_to_i32, "VMOV (i32 to core)" , "cccc111000i1nnnntttt1011N0010000") // VFPv4 INST(vfp_VMOV_to_i16, "VMOV (i16 to core)" , "cccc1110U0i1nnnntttt1011Ni110000") // ASIMD INST(vfp_VMOV_to_i8, "VMOV (i8 to core)", "cccc1110U1i1nnnntttt1011Nii10000") // ASIMD diff --git a/src/frontend/A32/disassembler/disassembler_arm.cpp b/src/frontend/A32/disassembler/disassembler_arm.cpp index a076606f..b3e25e56 100644 --- a/src/frontend/A32/disassembler/disassembler_arm.cpp +++ b/src/frontend/A32/disassembler/disassembler_arm.cpp @@ -1347,6 +1347,21 @@ public: return fmt::format("vmov{} {}, {}, {}", CondToString(cond), t, t2, FPRegStr(true, Vm, M)); } + std::string vfp_VMOV_from_i32(Cond cond, Imm<1> i, size_t Vd, Reg t, bool D) { + const size_t index = i.ZeroExtend(); + return fmt::format("vmov{}.32 {}[{}], {}", CondToString(cond), FPRegStr(true, Vd, D), index, t); + } + + std::string vfp_VMOV_from_i16(Cond cond, Imm<1> i1, size_t Vd, Reg t, bool D, Imm<1> i2) { + const size_t index = concatenate(i1, i2).ZeroExtend(); + return fmt::format("vmov{}.{}16 {}[{}], {}", CondToString(cond), FPRegStr(true, Vd, D), index, t); + } + + std::string vfp_VMOV_from_i8(Cond cond, Imm<1> i1, size_t Vd, Reg t, bool D, Imm<2> i2) { + const size_t index = concatenate(i1, i2).ZeroExtend(); + return fmt::format("vmov{}.{}8 {}[{}], {}", CondToString(cond), FPRegStr(true, Vd, D), index, t); + } + std::string vfp_VMOV_to_i32(Cond cond, Imm<1> i, size_t Vn, Reg t, bool N) { const size_t index = i.ZeroExtend(); return fmt::format("vmov{}.32 {}, {}[{}]", CondToString(cond), t, FPRegStr(true, Vn, N), index); diff --git a/src/frontend/A32/translate/impl/translate_arm.h b/src/frontend/A32/translate/impl/translate_arm.h index 6b1f0aed..92c9f583 100644 --- a/src/frontend/A32/translate/impl/translate_arm.h +++ b/src/frontend/A32/translate/impl/translate_arm.h @@ -405,6 +405,9 @@ struct ArmTranslatorVisitor final { bool vfp_VMOV_2f32_2u32(Cond cond, Reg t2, Reg t, bool M, size_t Vm); bool vfp_VMOV_2u32_f64(Cond cond, Reg t2, Reg t, bool M, size_t Vm); bool vfp_VMOV_f64_2u32(Cond cond, Reg t2, Reg t, bool M, size_t Vm); + bool vfp_VMOV_from_i32(Cond cond, Imm<1> i, size_t Vd, Reg t, bool D); + bool vfp_VMOV_from_i16(Cond cond, Imm<1> i1, size_t Vd, Reg t, bool D, Imm<1> i2); + bool vfp_VMOV_from_i8(Cond cond, Imm<1> i1, size_t Vd, Reg t, bool D, Imm<2> i2); bool vfp_VMOV_to_i32(Cond cond, Imm<1> i, size_t Vn, Reg t, bool N); bool vfp_VMOV_to_i16(Cond cond, bool U, Imm<1> i1, size_t Vn, Reg t, bool N, Imm<1> i2); bool vfp_VMOV_to_i8(Cond cond, bool U, Imm<1> i1, size_t Vn, Reg t, bool N, Imm<2> i2); diff --git a/src/frontend/A32/translate/impl/vfp.cpp b/src/frontend/A32/translate/impl/vfp.cpp index f329d9a3..7d76f9c9 100644 --- a/src/frontend/A32/translate/impl/vfp.cpp +++ b/src/frontend/A32/translate/impl/vfp.cpp @@ -523,7 +523,73 @@ bool ArmTranslatorVisitor::vfp_VMOV_f64_2u32(Cond cond, Reg t2, Reg t, bool M, s return true; } -// VMOV.{U16,S16} , +// VMOV.32 , +bool ArmTranslatorVisitor::vfp_VMOV_from_i32(Cond cond, Imm<1> i, size_t Vd, Reg t, bool D) { + if (!ConditionPassed(cond)) { + return true; + } + + if (t == Reg::R15) { + // TODO: v8 removes UPREDICTABLE for R13 + return UnpredictableInstruction(); + } + + const size_t index = i.ZeroExtend(); + const auto d = ToVector(false, Vd, D); + + const auto reg_d = ir.GetVector(d); + const auto scalar = ir.GetRegister(t); + const auto result = ir.VectorSetElement(32, reg_d, index, scalar); + + ir.SetVector(d, result); + return true; +} + +// VMOV.16 , +bool ArmTranslatorVisitor::vfp_VMOV_from_i16(Cond cond, Imm<1> i1, size_t Vd, Reg t, bool D, Imm<1> i2) { + if (!ConditionPassed(cond)) { + return true; + } + + if (t == Reg::R15) { + // TODO: v8 removes UPREDICTABLE for R13 + return UnpredictableInstruction(); + } + + const size_t index = concatenate(i1, i2).ZeroExtend(); + const auto d = ToVector(false, Vd, D); + + const auto reg_d = ir.GetVector(d); + const auto scalar = ir.LeastSignificantHalf(ir.GetRegister(t)); + const auto result = ir.VectorSetElement(16, reg_d, index, scalar); + + ir.SetVector(d, result); + return true; +} + +// VMOV.8 , +bool ArmTranslatorVisitor::vfp_VMOV_from_i8(Cond cond, Imm<1> i1, size_t Vd, Reg t, bool D, Imm<2> i2) { + if (!ConditionPassed(cond)) { + return true; + } + + if (t == Reg::R15) { + // TODO: v8 removes UPREDICTABLE for R13 + return UnpredictableInstruction(); + } + + const size_t index = concatenate(i1, i2).ZeroExtend(); + const auto d = ToVector(false, Vd, D); + + const auto reg_d = ir.GetVector(d); + const auto scalar = ir.LeastSignificantByte(ir.GetRegister(t)); + const auto result = ir.VectorSetElement(8, reg_d, index, scalar); + + ir.SetVector(d, result); + return true; +} + +// VMOV.32 , bool ArmTranslatorVisitor::vfp_VMOV_to_i32(Cond cond, Imm<1> i, size_t Vn, Reg t, bool N) { if (!ConditionPassed(cond)) { return true;