diff --git a/src/frontend/decoder/vfp2.h b/src/frontend/decoder/vfp2.h index be67f81a..ec2e8e80 100644 --- a/src/frontend/decoder/vfp2.h +++ b/src/frontend/decoder/vfp2.h @@ -64,10 +64,10 @@ boost::optional&> DecodeVFP2(u32 instruction) { // cccc1110________----101-__-0---- // Floating-point three-register data processing instructions - // VMLA - // VMLS - // VNMLA - // VNMLS + INST(&V::vfp2_VMLA, "VMLA", "cccc11100D00nnnndddd101zN0M0mmmm"), + INST(&V::vfp2_VMLS, "VMLS", "cccc11100D00nnnndddd101zN1M0mmmm"), + INST(&V::vfp2_VNMLS, "VNMLS", "cccc11100D01nnnndddd101zN0M0mmmm"), + INST(&V::vfp2_VNMLA, "VNMLA", "cccc11100D01nnnndddd101zN1M0mmmm"), INST(&V::vfp2_VMUL, "VMUL", "cccc11100D10nnnndddd101zN0M0mmmm"), INST(&V::vfp2_VNMUL, "VNMUL", "cccc11100D10nnnndddd101zN1M0mmmm"), INST(&V::vfp2_VADD, "VADD", "cccc11100D11nnnndddd101zN0M0mmmm"), @@ -99,6 +99,9 @@ boost::optional&> DecodeVFP2(u32 instruction) { }; + if ((instruction & 0xF0000000) == 0xF0000000) + return boost::none; // Don't try matching any unconditional instructions. + const auto matches_instruction = [instruction](const auto& matcher){ return matcher.Matches(instruction); }; auto iter = std::find_if(table.begin(), table.end(), matches_instruction); diff --git a/src/frontend/disassembler/disassembler_arm.cpp b/src/frontend/disassembler/disassembler_arm.cpp index 0be58d6f..a09ecc83 100644 --- a/src/frontend/disassembler/disassembler_arm.cpp +++ b/src/frontend/disassembler/disassembler_arm.cpp @@ -560,10 +560,6 @@ public: std::string arm_SRS() { return "ice"; } // Floating point arithmetic instructions - std::string vfp2_VMUL(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) { - return Common::StringFromFormat("vmul%s.%s %s, %s, %s", CondToString(cond), sz ? "f64" : "f32", FPRegStr(sz, Vd, D).c_str(), FPRegStr(sz, Vn, N).c_str(), FPRegStr(sz, Vm, M).c_str()); - } - std::string vfp2_VADD(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) { return Common::StringFromFormat("vadd%s.%s %s, %s, %s", CondToString(cond), sz ? "f64" : "f32", FPRegStr(sz, Vd, D).c_str(), FPRegStr(sz, Vn, N).c_str(), FPRegStr(sz, Vm, M).c_str()); } @@ -572,10 +568,30 @@ public: return Common::StringFromFormat("vsub%s.%s %s, %s, %s", CondToString(cond), sz ? "f64" : "f32", FPRegStr(sz, Vd, D).c_str(), FPRegStr(sz, Vn, N).c_str(), FPRegStr(sz, Vm, M).c_str()); } + std::string vfp2_VMUL(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) { + return Common::StringFromFormat("vmul%s.%s %s, %s, %s", CondToString(cond), sz ? "f64" : "f32", FPRegStr(sz, Vd, D).c_str(), FPRegStr(sz, Vn, N).c_str(), FPRegStr(sz, Vm, M).c_str()); + } + + std::string vfp2_VMLA(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) { + return Common::StringFromFormat("vmla%s.%s %s, %s, %s", CondToString(cond), sz ? "f64" : "f32", FPRegStr(sz, Vd, D).c_str(), FPRegStr(sz, Vn, N).c_str(), FPRegStr(sz, Vm, M).c_str()); + } + + std::string vfp2_VMLS(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) { + return Common::StringFromFormat("vmls%s.%s %s, %s, %s", CondToString(cond), sz ? "f64" : "f32", FPRegStr(sz, Vd, D).c_str(), FPRegStr(sz, Vn, N).c_str(), FPRegStr(sz, Vm, M).c_str()); + } + std::string vfp2_VNMUL(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) { return Common::StringFromFormat("vnmul%s.%s %s, %s, %s", CondToString(cond), sz ? "f64" : "f32", FPRegStr(sz, Vd, D).c_str(), FPRegStr(sz, Vn, N).c_str(), FPRegStr(sz, Vm, M).c_str()); } + std::string vfp2_VNMLA(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) { + return Common::StringFromFormat("vnmla%s.%s %s, %s, %s", CondToString(cond), sz ? "f64" : "f32", FPRegStr(sz, Vd, D).c_str(), FPRegStr(sz, Vn, N).c_str(), FPRegStr(sz, Vm, M).c_str()); + } + + std::string vfp2_VNMLS(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) { + return Common::StringFromFormat("vnmls%s.%s %s, %s, %s", CondToString(cond), sz ? "f64" : "f32", FPRegStr(sz, Vd, D).c_str(), FPRegStr(sz, Vn, N).c_str(), FPRegStr(sz, Vm, M).c_str()); + } + std::string vfp2_VDIV(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) { return Common::StringFromFormat("vdiv%s.%s %s, %s, %s", CondToString(cond), sz ? "f64" : "f32", FPRegStr(sz, Vd, D).c_str(), FPRegStr(sz, Vn, N).c_str(), FPRegStr(sz, Vm, M).c_str()); } diff --git a/src/frontend/translate/translate_arm/translate_arm.h b/src/frontend/translate/translate_arm/translate_arm.h index 5107b96c..9cf68973 100644 --- a/src/frontend/translate/translate_arm/translate_arm.h +++ b/src/frontend/translate/translate_arm/translate_arm.h @@ -321,8 +321,12 @@ struct ArmTranslatorVisitor final { // Floating-point three-register data processing instructions bool vfp2_VADD(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm); bool vfp2_VSUB(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm); - bool vfp2_VNMUL(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm); bool vfp2_VMUL(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm); + bool vfp2_VMLA(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm); + bool vfp2_VMLS(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm); + bool vfp2_VNMUL(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm); + bool vfp2_VNMLA(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm); + bool vfp2_VNMLS(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm); bool vfp2_VDIV(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm); // Floating-point misc instructions diff --git a/src/frontend/translate/translate_arm/vfp2.cpp b/src/frontend/translate/translate_arm/vfp2.cpp index cad47750..d9a1c0e6 100644 --- a/src/frontend/translate/translate_arm/vfp2.cpp +++ b/src/frontend/translate/translate_arm/vfp2.cpp @@ -74,6 +74,46 @@ bool ArmTranslatorVisitor::vfp2_VMUL(Cond cond, bool D, size_t Vn, size_t Vd, bo return true; } +bool ArmTranslatorVisitor::vfp2_VMLA(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) { + if (ir.current_location.FPSCR_Len() != 1 || ir.current_location.FPSCR_Stride() != 1) + return InterpretThisInstruction(); // TODO: Vectorised floating point instructions + + ExtReg d = ToExtReg(sz, Vd, D); + ExtReg n = ToExtReg(sz, Vn, N); + ExtReg m = ToExtReg(sz, Vm, M); + // VMLA.{F32,F64} <{S,D}d>, <{S,D}n>, <{S,D}m> + if (ConditionPassed(cond)) { + auto a = ir.GetExtendedRegister(n); + auto b = ir.GetExtendedRegister(m); + auto c = ir.GetExtendedRegister(d); + auto result = sz + ? ir.FPAdd64(c, ir.FPMul64(a, b, true), true) + : ir.FPAdd32(c, ir.FPMul32(a, b, true), true); + ir.SetExtendedRegister(d, result); + } + return true; +} + +bool ArmTranslatorVisitor::vfp2_VMLS(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) { + if (ir.current_location.FPSCR_Len() != 1 || ir.current_location.FPSCR_Stride() != 1) + return InterpretThisInstruction(); // TODO: Vectorised floating point instructions + + ExtReg d = ToExtReg(sz, Vd, D); + ExtReg n = ToExtReg(sz, Vn, N); + ExtReg m = ToExtReg(sz, Vm, M); + // VMLS.{F32,F64} <{S,D}d>, <{S,D}n>, <{S,D}m> + if (ConditionPassed(cond)) { + auto a = ir.GetExtendedRegister(n); + auto b = ir.GetExtendedRegister(m); + auto c = ir.GetExtendedRegister(d); + auto result = sz + ? ir.FPAdd64(c, ir.FPNeg64(ir.FPMul64(a, b, true)), true) + : ir.FPAdd32(c, ir.FPNeg32(ir.FPMul32(a, b, true)), true); + ir.SetExtendedRegister(d, result); + } + return true; +} + bool ArmTranslatorVisitor::vfp2_VNMUL(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) { if (ir.current_location.FPSCR_Len() != 1 || ir.current_location.FPSCR_Stride() != 1) return InterpretThisInstruction(); // TODO: Vectorised floating point instructions @@ -93,6 +133,46 @@ bool ArmTranslatorVisitor::vfp2_VNMUL(Cond cond, bool D, size_t Vn, size_t Vd, b return true; } +bool ArmTranslatorVisitor::vfp2_VNMLA(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) { + if (ir.current_location.FPSCR_Len() != 1 || ir.current_location.FPSCR_Stride() != 1) + return InterpretThisInstruction(); // TODO: Vectorised floating point instructions + + ExtReg d = ToExtReg(sz, Vd, D); + ExtReg n = ToExtReg(sz, Vn, N); + ExtReg m = ToExtReg(sz, Vm, M); + // VNMLA.{F32,F64} <{S,D}d>, <{S,D}n>, <{S,D}m> + if (ConditionPassed(cond)) { + auto a = ir.GetExtendedRegister(n); + auto b = ir.GetExtendedRegister(m); + auto c = ir.GetExtendedRegister(d); + auto result = sz + ? ir.FPAdd64(ir.FPNeg64(c), ir.FPNeg64(ir.FPMul64(a, b, true)), true) + : ir.FPAdd32(ir.FPNeg32(c), ir.FPNeg32(ir.FPMul32(a, b, true)), true); + ir.SetExtendedRegister(d, result); + } + return true; +} + +bool ArmTranslatorVisitor::vfp2_VNMLS(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) { + if (ir.current_location.FPSCR_Len() != 1 || ir.current_location.FPSCR_Stride() != 1) + return InterpretThisInstruction(); // TODO: Vectorised floating point instructions + + ExtReg d = ToExtReg(sz, Vd, D); + ExtReg n = ToExtReg(sz, Vn, N); + ExtReg m = ToExtReg(sz, Vm, M); + // VNMLS.{F32,F64} <{S,D}d>, <{S,D}n>, <{S,D}m> + if (ConditionPassed(cond)) { + auto a = ir.GetExtendedRegister(n); + auto b = ir.GetExtendedRegister(m); + auto c = ir.GetExtendedRegister(d); + auto result = sz + ? ir.FPAdd64(ir.FPNeg64(c), ir.FPMul64(a, b, true), true) + : ir.FPAdd32(ir.FPNeg32(c), ir.FPMul32(a, b, true), true); + ir.SetExtendedRegister(d, result); + } + return true; +} + bool ArmTranslatorVisitor::vfp2_VDIV(Cond cond, bool D, size_t Vn, size_t Vd, bool sz, bool N, bool M, size_t Vm) { if (ir.current_location.FPSCR_Len() != 1 || ir.current_location.FPSCR_Stride() != 1) return InterpretThisInstruction(); // TODO: Vectorised floating point instructions