diff --git a/src/frontend/A32/decoder/vfp.inc b/src/frontend/A32/decoder/vfp.inc index fcf95eb1..123b4da1 100644 --- a/src/frontend/A32/decoder/vfp.inc +++ b/src/frontend/A32/decoder/vfp.inc @@ -44,6 +44,7 @@ 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_VDUP, "VDUP (from core)", "cccc11101BQ0ddddtttt1011D0E10000") // ASIMD // Floating-point system register access INST(vfp_VMSR, "VMSR", "cccc111011100001tttt101000010000") // VFPv2 diff --git a/src/frontend/A32/disassembler/disassembler_arm.cpp b/src/frontend/A32/disassembler/disassembler_arm.cpp index 00ef587e..0b5e5600 100644 --- a/src/frontend/A32/disassembler/disassembler_arm.cpp +++ b/src/frontend/A32/disassembler/disassembler_arm.cpp @@ -119,6 +119,16 @@ public: return fmt::format("{}{}", dp_operation ? 'd' : 's', reg_num + 1); } + static std::string VectorStr(bool Q, size_t base, bool bit) { + size_t reg_num; + if (Q) { + reg_num = (base >> 1) + (bit ? 8 : 0); + } else { + reg_num = base + (bit ? 16 : 0); + } + return fmt::format("{}{}", Q ? 'q' : 'd', reg_num); + } + static std::string CondOrTwo(Cond cond) { return cond == Cond::NV ? "2" : CondToString(cond); } @@ -1337,6 +1347,11 @@ public: return fmt::format("vmov{} {}, {}, {}", CondToString(cond), t, t2, FPRegStr(true, Vm, M)); } + std::string vfp_VDUP(Cond cond, Imm<1> B, bool Q, size_t Vd, Reg t, bool D, Imm<1> E) { + const size_t esize = 32u >> concatenate(B, E).ZeroExtend(); + return fmt::format("vdup{}.{} {}, {}", CondToString(cond), esize, VectorStr(Q, Vd, D), t); + } + std::string vfp_VMOV_reg(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm){ return fmt::format("vmov{}.{} {}, {}", CondToString(cond), 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 aef984a6..3b4e977c 100644 --- a/src/frontend/A32/translate/impl/translate_arm.h +++ b/src/frontend/A32/translate/impl/translate_arm.h @@ -407,6 +407,7 @@ struct ArmTranslatorVisitor final { 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_reg(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm); + bool vfp_VDUP(Cond cond, Imm<1> B, bool Q, size_t Vd, Reg t, bool D, Imm<1> E); // Floating-point misc instructions bool vfp_VABS(Cond cond, bool D, size_t Vd, bool sz, bool M, size_t Vm); diff --git a/src/frontend/A32/translate/impl/vfp.cpp b/src/frontend/A32/translate/impl/vfp.cpp index 33f8578a..f33baf3c 100644 --- a/src/frontend/A32/translate/impl/vfp.cpp +++ b/src/frontend/A32/translate/impl/vfp.cpp @@ -523,6 +523,34 @@ bool ArmTranslatorVisitor::vfp_VMOV_f64_2u32(Cond cond, Reg t2, Reg t, bool M, s return true; } +// VDUP.{8,16,32} , +// VDUP.{8,16,32}
, +bool ArmTranslatorVisitor::vfp_VDUP(Cond cond, Imm<1> B, bool Q, size_t Vd, Reg t, bool D, Imm<1> E) { + if (!ConditionPassed(cond)) { + return true; + } + + if (Q && Common::Bit<0>(Vd)) { + return UndefinedInstruction(); + } + if (t == Reg::R15) { + return UnpredictableInstruction(); + } + + const auto d = ToVector(Q, Vd, D); + const size_t BE = concatenate(B, E).ZeroExtend(); + const size_t esize = 32u >> BE; + + if (BE == 0b11) { + return UndefinedInstruction(); + } + + const auto scalar = ir.LeastSignificant(esize, ir.GetRegister(t)); + const auto result = ir.VectorBroadcast(esize, scalar); + ir.SetVector(d, result); + return true; +} + // VMOV.F64
, # // VMOV.F32 , # bool ArmTranslatorVisitor::vfp_VMOV_imm(Cond cond, bool D, Imm<4> imm4H, size_t Vd, bool sz, Imm<4> imm4L) {