Merge pull request #570 from lioncash/parallel
thumb32: Implement parallel add/sub instructions
This commit is contained in:
commit
644350c7e6
5 changed files with 682 additions and 66 deletions
|
@ -152,6 +152,7 @@ if ("A32" IN_LIST DYNARMIC_FRONTENDS)
|
|||
frontend/A32/translate/impl/thumb16.cpp
|
||||
frontend/A32/translate/impl/thumb32.cpp
|
||||
frontend/A32/translate/impl/thumb32_misc.cpp
|
||||
frontend/A32/translate/impl/thumb32_parallel.cpp
|
||||
frontend/A32/translate/impl/translate_arm.h
|
||||
frontend/A32/translate/impl/translate_thumb.h
|
||||
frontend/A32/translate/impl/vfp.cpp
|
||||
|
|
|
@ -235,44 +235,44 @@ std::optional<std::reference_wrapper<const Thumb32Matcher<V>>> DecodeThumb32(u32
|
|||
//INST(&V::thumb32_UXTAB, "UXTAB", "111110100101----1111----1-------"),
|
||||
|
||||
// Parallel Addition and Subtraction (signed)
|
||||
//INST(&V::thumb32_SADD16, "SADD16", "111110101001----1111----0000----"),
|
||||
//INST(&V::thumb32_SASX, "SASX", "111110101010----1111----0000----"),
|
||||
//INST(&V::thumb32_SSAX, "SSAX", "111110101110----1111----0000----"),
|
||||
//INST(&V::thumb32_SSUB16, "SSUB16", "111110101101----1111----0000----"),
|
||||
//INST(&V::thumb32_SADD8, "SADD8", "111110101000----1111----0000----"),
|
||||
//INST(&V::thumb32_SSUB8, "SSUB8", "111110101100----1111----0000----"),
|
||||
//INST(&V::thumb32_QADD16, "QADD16", "111110101001----1111----0001----"),
|
||||
//INST(&V::thumb32_QASX, "QASX", "111110101010----1111----0001----"),
|
||||
//INST(&V::thumb32_QSAX, "QSAX", "111110101110----1111----0001----"),
|
||||
//INST(&V::thumb32_QSUB16, "QSUB16", "111110101101----1111----0001----"),
|
||||
//INST(&V::thumb32_QADD8, "QADD8", "111110101000----1111----0001----"),
|
||||
//INST(&V::thumb32_QSUB8, "QSUB8", "111110101100----1111----0001----"),
|
||||
//INST(&V::thumb32_SHADD16, "SHADD16", "111110101001----1111----0010----"),
|
||||
//INST(&V::thumb32_SHASX, "SHASX", "111110101010----1111----0010----"),
|
||||
//INST(&V::thumb32_SHSAX, "SHSAX", "111110101110----1111----0010----"),
|
||||
//INST(&V::thumb32_SHSUB16, "SHSUB16", "111110101101----1111----0010----"),
|
||||
//INST(&V::thumb32_SHADD8, "SHADD8", "111110101000----1111----0010----"),
|
||||
//INST(&V::thumb32_SHSUB8, "SHSUB8", "111110101100----1111----0010----"),
|
||||
INST(&V::thumb32_SADD16, "SADD16", "111110101001nnnn1111dddd0000mmmm"),
|
||||
INST(&V::thumb32_SASX, "SASX", "111110101010nnnn1111dddd0000mmmm"),
|
||||
INST(&V::thumb32_SSAX, "SSAX", "111110101110nnnn1111dddd0000mmmm"),
|
||||
INST(&V::thumb32_SSUB16, "SSUB16", "111110101101nnnn1111dddd0000mmmm"),
|
||||
INST(&V::thumb32_SADD8, "SADD8", "111110101000nnnn1111dddd0000mmmm"),
|
||||
INST(&V::thumb32_SSUB8, "SSUB8", "111110101100nnnn1111dddd0000mmmm"),
|
||||
INST(&V::thumb32_QADD16, "QADD16", "111110101001nnnn1111dddd0001mmmm"),
|
||||
INST(&V::thumb32_QASX, "QASX", "111110101010nnnn1111dddd0001mmmm"),
|
||||
INST(&V::thumb32_QSAX, "QSAX", "111110101110nnnn1111dddd0001mmmm"),
|
||||
INST(&V::thumb32_QSUB16, "QSUB16", "111110101101nnnn1111dddd0001mmmm"),
|
||||
INST(&V::thumb32_QADD8, "QADD8", "111110101000nnnn1111dddd0001mmmm"),
|
||||
INST(&V::thumb32_QSUB8, "QSUB8", "111110101100nnnn1111dddd0001mmmm"),
|
||||
INST(&V::thumb32_SHADD16, "SHADD16", "111110101001nnnn1111dddd0010mmmm"),
|
||||
INST(&V::thumb32_SHASX, "SHASX", "111110101010nnnn1111dddd0010mmmm"),
|
||||
INST(&V::thumb32_SHSAX, "SHSAX", "111110101110nnnn1111dddd0010mmmm"),
|
||||
INST(&V::thumb32_SHSUB16, "SHSUB16", "111110101101nnnn1111dddd0010mmmm"),
|
||||
INST(&V::thumb32_SHADD8, "SHADD8", "111110101000nnnn1111dddd0010mmmm"),
|
||||
INST(&V::thumb32_SHSUB8, "SHSUB8", "111110101100nnnn1111dddd0010mmmm"),
|
||||
|
||||
// Parallel Addition and Subtraction (unsigned)
|
||||
//INST(&V::thumb32_UADD16, "UADD16", "111110101001----1111----0100----"),
|
||||
//INST(&V::thumb32_UASX, "UASX", "111110101010----1111----0100----"),
|
||||
//INST(&V::thumb32_USAX, "USAX", "111110101110----1111----0100----"),
|
||||
//INST(&V::thumb32_USUB16, "USUB16", "111110101101----1111----0100----"),
|
||||
//INST(&V::thumb32_UADD8, "UADD8", "111110101000----1111----0100----"),
|
||||
//INST(&V::thumb32_USUB8, "USUB8", "111110101100----1111----0100----"),
|
||||
//INST(&V::thumb32_UQADD16, "UQADD16", "111110101001----1111----0101----"),
|
||||
//INST(&V::thumb32_UQASX, "UQASX", "111110101010----1111----0101----"),
|
||||
//INST(&V::thumb32_UQSAX, "UQSAX", "111110101110----1111----0101----"),
|
||||
//INST(&V::thumb32_UQSUB16, "UQSUB16", "111110101101----1111----0101----"),
|
||||
//INST(&V::thumb32_UQADD8, "UQADD8", "111110101000----1111----0101----"),
|
||||
//INST(&V::thumb32_UQSUB8, "UQSUB8", "111110101100----1111----0101----"),
|
||||
//INST(&V::thumb32_UHADD16, "UHADD16", "111110101001----1111----0110----"),
|
||||
//INST(&V::thumb32_UHASX, "UHASX", "111110101010----1111----0110----"),
|
||||
//INST(&V::thumb32_UHSAX, "UHSAX", "111110101110----1111----0110----"),
|
||||
//INST(&V::thumb32_UHSUB16, "UHSUB16", "111110101101----1111----0110----"),
|
||||
//INST(&V::thumb32_UHADD8, "UHADD8", "111110101000----1111----0110----"),
|
||||
//INST(&V::thumb32_UHSUB8, "UHSUB8", "111110101100----1111----0110----"),
|
||||
INST(&V::thumb32_UADD16, "UADD16", "111110101001nnnn1111dddd0100mmmm"),
|
||||
INST(&V::thumb32_UASX, "UASX", "111110101010nnnn1111dddd0100mmmm"),
|
||||
INST(&V::thumb32_USAX, "USAX", "111110101110nnnn1111dddd0100mmmm"),
|
||||
INST(&V::thumb32_USUB16, "USUB16", "111110101101nnnn1111dddd0100mmmm"),
|
||||
INST(&V::thumb32_UADD8, "UADD8", "111110101000nnnn1111dddd0100mmmm"),
|
||||
INST(&V::thumb32_USUB8, "USUB8", "111110101100nnnn1111dddd0100mmmm"),
|
||||
INST(&V::thumb32_UQADD16, "UQADD16", "111110101001nnnn1111dddd0101mmmm"),
|
||||
INST(&V::thumb32_UQASX, "UQASX", "111110101010nnnn1111dddd0101mmmm"),
|
||||
INST(&V::thumb32_UQSAX, "UQSAX", "111110101110nnnn1111dddd0101mmmm"),
|
||||
INST(&V::thumb32_UQSUB16, "UQSUB16", "111110101101nnnn1111dddd0101mmmm"),
|
||||
INST(&V::thumb32_UQADD8, "UQADD8", "111110101000nnnn1111dddd0101mmmm"),
|
||||
INST(&V::thumb32_UQSUB8, "UQSUB8", "111110101100nnnn1111dddd0101mmmm"),
|
||||
INST(&V::thumb32_UHADD16, "UHADD16", "111110101001nnnn1111dddd0110mmmm"),
|
||||
INST(&V::thumb32_UHASX, "UHASX", "111110101010nnnn1111dddd0110mmmm"),
|
||||
INST(&V::thumb32_UHSAX, "UHSAX", "111110101110nnnn1111dddd0110mmmm"),
|
||||
INST(&V::thumb32_UHSUB16, "UHSUB16", "111110101101nnnn1111dddd0110mmmm"),
|
||||
INST(&V::thumb32_UHADD8, "UHADD8", "111110101000nnnn1111dddd0110mmmm"),
|
||||
INST(&V::thumb32_UHSUB8, "UHSUB8", "111110101100nnnn1111dddd0110mmmm"),
|
||||
|
||||
// Miscellaneous Operations
|
||||
INST(&V::thumb32_QADD, "QADD", "111110101000nnnn1111dddd1000mmmm"),
|
||||
|
|
521
src/frontend/A32/translate/impl/thumb32_parallel.cpp
Normal file
521
src/frontend/A32/translate/impl/thumb32_parallel.cpp
Normal file
|
@ -0,0 +1,521 @@
|
|||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2016 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
*/
|
||||
|
||||
#include "frontend/A32/translate/impl/translate_thumb.h"
|
||||
|
||||
namespace Dynarmic::A32 {
|
||||
static IR::U32 Pack2x16To1x32(A32::IREmitter& ir, IR::U32 lo, IR::U32 hi) {
|
||||
return ir.Or(ir.And(lo, ir.Imm32(0xFFFF)), ir.LogicalShiftLeft(hi, ir.Imm8(16), ir.Imm1(0)).result);
|
||||
}
|
||||
|
||||
static IR::U16 MostSignificantHalf(A32::IREmitter& ir, IR::U32 value) {
|
||||
return ir.LeastSignificantHalf(ir.LogicalShiftRight(value, ir.Imm8(16), ir.Imm1(0)).result);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_SADD8(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedAddS8(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_SADD16(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedAddS16(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_SASX(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedAddSubS16(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_SSAX(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedSubAddS16(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_SSUB8(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedSubS8(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_SSUB16(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedSubS16(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_UADD8(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedAddU8(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_UADD16(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedAddU16(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_UASX(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedAddSubU16(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_USAX(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedSubAddU16(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_USUB8(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedSubU8(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_USUB16(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedSubU16(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_QADD8(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedSaturatedAddS8(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_QADD16(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedSaturatedAddS16(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_QASX(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto Rn = ir.GetRegister(n);
|
||||
const auto Rm = ir.GetRegister(m);
|
||||
const auto Rn_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(Rn));
|
||||
const auto Rn_hi = ir.SignExtendHalfToWord(MostSignificantHalf(ir, Rn));
|
||||
const auto Rm_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(Rm));
|
||||
const auto Rm_hi = ir.SignExtendHalfToWord(MostSignificantHalf(ir, Rm));
|
||||
const auto diff = ir.SignedSaturation(ir.Sub(Rn_lo, Rm_hi), 16).result;
|
||||
const auto sum = ir.SignedSaturation(ir.Add(Rn_hi, Rm_lo), 16).result;
|
||||
const auto result = Pack2x16To1x32(ir, diff, sum);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_QSAX(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto Rn = ir.GetRegister(n);
|
||||
const auto Rm = ir.GetRegister(m);
|
||||
const auto Rn_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(Rn));
|
||||
const auto Rn_hi = ir.SignExtendHalfToWord(MostSignificantHalf(ir, Rn));
|
||||
const auto Rm_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(Rm));
|
||||
const auto Rm_hi = ir.SignExtendHalfToWord(MostSignificantHalf(ir, Rm));
|
||||
const auto sum = ir.SignedSaturation(ir.Add(Rn_lo, Rm_hi), 16).result;
|
||||
const auto diff = ir.SignedSaturation(ir.Sub(Rn_hi, Rm_lo), 16).result;
|
||||
const auto result = Pack2x16To1x32(ir, sum, diff);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_QSUB8(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedSaturatedSubS8(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_QSUB16(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedSaturatedSubS16(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_UQADD8(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedSaturatedAddU8(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_UQADD16(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedSaturatedAddU16(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_UQASX(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto Rn = ir.GetRegister(n);
|
||||
const auto Rm = ir.GetRegister(m);
|
||||
const auto Rn_lo = ir.ZeroExtendHalfToWord(ir.LeastSignificantHalf(Rn));
|
||||
const auto Rn_hi = ir.ZeroExtendHalfToWord(MostSignificantHalf(ir, Rn));
|
||||
const auto Rm_lo = ir.ZeroExtendHalfToWord(ir.LeastSignificantHalf(Rm));
|
||||
const auto Rm_hi = ir.ZeroExtendHalfToWord(MostSignificantHalf(ir, Rm));
|
||||
const auto diff = ir.UnsignedSaturation(ir.Sub(Rn_lo, Rm_hi), 16).result;
|
||||
const auto sum = ir.UnsignedSaturation(ir.Add(Rn_hi, Rm_lo), 16).result;
|
||||
const auto result = Pack2x16To1x32(ir, diff, sum);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_UQSAX(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto Rn = ir.GetRegister(n);
|
||||
const auto Rm = ir.GetRegister(m);
|
||||
const auto Rn_lo = ir.ZeroExtendHalfToWord(ir.LeastSignificantHalf(Rn));
|
||||
const auto Rn_hi = ir.ZeroExtendHalfToWord(MostSignificantHalf(ir, Rn));
|
||||
const auto Rm_lo = ir.ZeroExtendHalfToWord(ir.LeastSignificantHalf(Rm));
|
||||
const auto Rm_hi = ir.ZeroExtendHalfToWord(MostSignificantHalf(ir, Rm));
|
||||
const auto sum = ir.UnsignedSaturation(ir.Add(Rn_lo, Rm_hi), 16).result;
|
||||
const auto diff = ir.UnsignedSaturation(ir.Sub(Rn_hi, Rm_lo), 16).result;
|
||||
const auto result = Pack2x16To1x32(ir, sum, diff);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_UQSUB8(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedSaturatedSubU8(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_UQSUB16(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedSaturatedSubU16(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_SHADD8(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedHalvingAddS8(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_SHADD16(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedHalvingAddS16(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_SHASX(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedHalvingAddSubS16(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_SHSAX(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedHalvingSubAddS16(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_SHSUB8(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedHalvingSubS8(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_SHSUB16(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedHalvingSubS16(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_UHADD8(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedHalvingAddU8(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_UHADD16(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedHalvingAddU16(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_UHASX(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedHalvingAddSubU16(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_UHSAX(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedHalvingSubAddU16(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_UHSUB8(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedHalvingSubU8(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_UHSUB16(Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.PackedHalvingSubU16(reg_n, reg_m);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::A32
|
|
@ -127,6 +127,46 @@ struct ThumbTranslatorVisitor final {
|
|||
bool thumb32_REV16(Reg n, Reg d, Reg m);
|
||||
bool thumb32_REVSH(Reg n, Reg d, Reg m);
|
||||
bool thumb32_SEL(Reg n, Reg d, Reg m);
|
||||
|
||||
// thumb32 parallel add/sub instructions
|
||||
bool thumb32_SADD8(Reg n, Reg d, Reg m);
|
||||
bool thumb32_SADD16(Reg n, Reg d, Reg m);
|
||||
bool thumb32_SASX(Reg n, Reg d, Reg m);
|
||||
bool thumb32_SSAX(Reg n, Reg d, Reg m);
|
||||
bool thumb32_SSUB8(Reg n, Reg d, Reg m);
|
||||
bool thumb32_SSUB16(Reg n, Reg d, Reg m);
|
||||
bool thumb32_UADD8(Reg n, Reg d, Reg m);
|
||||
bool thumb32_UADD16(Reg n, Reg d, Reg m);
|
||||
bool thumb32_UASX(Reg n, Reg d, Reg m);
|
||||
bool thumb32_USAX(Reg n, Reg d, Reg m);
|
||||
bool thumb32_USUB8(Reg n, Reg d, Reg m);
|
||||
bool thumb32_USUB16(Reg n, Reg d, Reg m);
|
||||
|
||||
bool thumb32_QADD8(Reg n, Reg d, Reg m);
|
||||
bool thumb32_QADD16(Reg n, Reg d, Reg m);
|
||||
bool thumb32_QASX(Reg n, Reg d, Reg m);
|
||||
bool thumb32_QSAX(Reg n, Reg d, Reg m);
|
||||
bool thumb32_QSUB8(Reg n, Reg d, Reg m);
|
||||
bool thumb32_QSUB16(Reg n, Reg d, Reg m);
|
||||
bool thumb32_UQADD8(Reg n, Reg d, Reg m);
|
||||
bool thumb32_UQADD16(Reg n, Reg d, Reg m);
|
||||
bool thumb32_UQASX(Reg n, Reg d, Reg m);
|
||||
bool thumb32_UQSAX(Reg n, Reg d, Reg m);
|
||||
bool thumb32_UQSUB8(Reg n, Reg d, Reg m);
|
||||
bool thumb32_UQSUB16(Reg n, Reg d, Reg m);
|
||||
|
||||
bool thumb32_SHADD8(Reg n, Reg d, Reg m);
|
||||
bool thumb32_SHADD16(Reg n, Reg d, Reg m);
|
||||
bool thumb32_SHASX(Reg n, Reg d, Reg m);
|
||||
bool thumb32_SHSAX(Reg n, Reg d, Reg m);
|
||||
bool thumb32_SHSUB8(Reg n, Reg d, Reg m);
|
||||
bool thumb32_SHSUB16(Reg n, Reg d, Reg m);
|
||||
bool thumb32_UHADD8(Reg n, Reg d, Reg m);
|
||||
bool thumb32_UHADD16(Reg n, Reg d, Reg m);
|
||||
bool thumb32_UHASX(Reg n, Reg d, Reg m);
|
||||
bool thumb32_UHSAX(Reg n, Reg d, Reg m);
|
||||
bool thumb32_UHSUB8(Reg n, Reg d, Reg m);
|
||||
bool thumb32_UHSUB16(Reg n, Reg d, Reg m);
|
||||
};
|
||||
|
||||
} // namespace Dynarmic::A32
|
||||
|
|
|
@ -361,6 +361,13 @@ TEST_CASE("Fuzz Thumb instructions set 2 (affects PC)", "[JitX64][Thumb][Thumb16
|
|||
}
|
||||
|
||||
TEST_CASE("Fuzz Thumb32 instructions set", "[JitX64][Thumb][Thumb32]") {
|
||||
const auto three_reg_not_r15 = [](u32 inst) {
|
||||
const auto d = Common::Bits<8, 11>(inst);
|
||||
const auto m = Common::Bits<0, 3>(inst);
|
||||
const auto n = Common::Bits<16, 19>(inst);
|
||||
return d != 15 && m != 15 && n != 15;
|
||||
};
|
||||
|
||||
const std::array instructions = {
|
||||
ThumbInstGen("111110101011nnnn1111dddd1000mmmm", // CLZ
|
||||
[](u32 inst) {
|
||||
|
@ -370,33 +377,25 @@ TEST_CASE("Fuzz Thumb32 instructions set", "[JitX64][Thumb][Thumb32]") {
|
|||
return m == n && d != 15 && m != 15;
|
||||
}),
|
||||
ThumbInstGen("111110101000nnnn1111dddd1000mmmm", // QADD
|
||||
[](u32 inst) {
|
||||
const auto d = Common::Bits<8, 11>(inst);
|
||||
const auto m = Common::Bits<0, 3>(inst);
|
||||
const auto n = Common::Bits<16, 19>(inst);
|
||||
return d != 15 && m != 15 && n != 15;
|
||||
}),
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101000nnnn1111dddd0001mmmm", // QADD8
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101001nnnn1111dddd0001mmmm", // QADD16
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101010nnnn1111dddd0001mmmm", // QASX
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101000nnnn1111dddd1001mmmm", // QDADD
|
||||
[](u32 inst) {
|
||||
const auto d = Common::Bits<8, 11>(inst);
|
||||
const auto m = Common::Bits<0, 3>(inst);
|
||||
const auto n = Common::Bits<16, 19>(inst);
|
||||
return d != 15 && m != 15 && n != 15;
|
||||
}),
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101000nnnn1111dddd1011mmmm", // QDSUB
|
||||
[](u32 inst) {
|
||||
const auto d = Common::Bits<8, 11>(inst);
|
||||
const auto m = Common::Bits<0, 3>(inst);
|
||||
const auto n = Common::Bits<16, 19>(inst);
|
||||
return d != 15 && m != 15 && n != 15;
|
||||
}),
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101110nnnn1111dddd0001mmmm", // QSAX
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101000nnnn1111dddd1010mmmm", // QSUB
|
||||
[](u32 inst) {
|
||||
const auto d = Common::Bits<8, 11>(inst);
|
||||
const auto m = Common::Bits<0, 3>(inst);
|
||||
const auto n = Common::Bits<16, 19>(inst);
|
||||
return d != 15 && m != 15 && n != 15;
|
||||
}),
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101100nnnn1111dddd0001mmmm", // QSUB8
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101101nnnn1111dddd0001mmmm", // QSUB16
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101001nnnn1111dddd1010mmmm", // RBIT
|
||||
[](u32 inst) {
|
||||
const auto d = Common::Bits<8, 11>(inst);
|
||||
|
@ -425,13 +424,68 @@ TEST_CASE("Fuzz Thumb32 instructions set", "[JitX64][Thumb][Thumb32]") {
|
|||
const auto n = Common::Bits<16, 19>(inst);
|
||||
return m == n && d != 15 && m != 15;
|
||||
}),
|
||||
ThumbInstGen("111110101000nnnn1111dddd0000mmmm", // SADD8
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101001nnnn1111dddd0000mmmm", // SADD16
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101010nnnn1111dddd0000mmmm", // SASX
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101010nnnn1111dddd1000mmmm", // SEL
|
||||
[](u32 inst) {
|
||||
const auto d = Common::Bits<8, 11>(inst);
|
||||
const auto m = Common::Bits<0, 3>(inst);
|
||||
const auto n = Common::Bits<16, 19>(inst);
|
||||
return d != 15 && m != 15 && n != 15;
|
||||
}),
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101000nnnn1111dddd0010mmmm", // SHADD8
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101001nnnn1111dddd0010mmmm", // SHADD16
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101010nnnn1111dddd0010mmmm", // SHASX
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101110nnnn1111dddd0010mmmm", // SHSAX
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101100nnnn1111dddd0010mmmm", // SHSUB8
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101101nnnn1111dddd0010mmmm", // SHSUB16
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101110nnnn1111dddd0000mmmm", // SSAX
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101100nnnn1111dddd0000mmmm", // SSUB8
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101101nnnn1111dddd0000mmmm", // SSUB16
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101000nnnn1111dddd0100mmmm", // UADD8
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101001nnnn1111dddd0100mmmm", // UADD16
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101010nnnn1111dddd0100mmmm", // UASX
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101000nnnn1111dddd0110mmmm", // UHADD8
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101001nnnn1111dddd0110mmmm", // UHADD16
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101010nnnn1111dddd0110mmmm", // UHASX
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101110nnnn1111dddd0110mmmm", // UHSAX
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101100nnnn1111dddd0110mmmm", // UHSUB8
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101101nnnn1111dddd0110mmmm", // UHSUB16
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101000nnnn1111dddd0101mmmm", // UQADD8
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101001nnnn1111dddd0101mmmm", // UQADD16
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101010nnnn1111dddd0101mmmm", // UQASX
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101110nnnn1111dddd0101mmmm", // UQSAX
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101100nnnn1111dddd0101mmmm", // UQSUB8
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101101nnnn1111dddd0101mmmm", // UQSUB16
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101110nnnn1111dddd0100mmmm", // USAX
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101100nnnn1111dddd0100mmmm", // USUB8
|
||||
three_reg_not_r15),
|
||||
ThumbInstGen("111110101101nnnn1111dddd0100mmmm", // USUB16
|
||||
three_reg_not_r15),
|
||||
};
|
||||
|
||||
const auto instruction_select = [&]() -> u32 {
|
||||
|
|
Loading…
Reference in a new issue