Merge pull request #434 from lioncash/format
A32/translate_arm: Formatting/tidying up
This commit is contained in:
commit
dbf47db713
16 changed files with 3718 additions and 2470 deletions
|
@ -10,65 +10,75 @@
|
|||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
bool ArmTranslatorVisitor::arm_B(Cond cond, Imm24 imm24) {
|
||||
u32 imm32 = Common::SignExtend<26, u32>(imm24 << 2) + 8;
|
||||
// B <label>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto new_location = ir.current_location.AdvancePC(imm32);
|
||||
ir.SetTerm(IR::Term::LinkBlock{ new_location });
|
||||
return false;
|
||||
}
|
||||
bool ArmTranslatorVisitor::arm_B(Cond cond, Imm24 imm24) {
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_BL(Cond cond, Imm24 imm24) {
|
||||
u32 imm32 = Common::SignExtend<26, u32>(imm24 << 2) + 8;
|
||||
const u32 imm32 = Common::SignExtend<26, u32>(imm24 << 2) + 8;
|
||||
const auto new_location = ir.current_location.AdvancePC(imm32);
|
||||
ir.SetTerm(IR::Term::LinkBlock{new_location});
|
||||
return false;
|
||||
}
|
||||
|
||||
// BL <label>
|
||||
if (ConditionPassed(cond)) {
|
||||
ir.PushRSB(ir.current_location.AdvancePC(4));
|
||||
ir.SetRegister(Reg::LR, ir.Imm32(ir.current_location.PC() + 4));
|
||||
auto new_location = ir.current_location.AdvancePC(imm32);
|
||||
ir.SetTerm(IR::Term::LinkBlock{ new_location });
|
||||
return false;
|
||||
}
|
||||
bool ArmTranslatorVisitor::arm_BL(Cond cond, Imm24 imm24) {
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_BLX_imm(bool H, Imm24 imm24) {
|
||||
u32 imm32 = Common::SignExtend<26, u32>((imm24 << 2)) + (H ? 2 : 0) + 8;
|
||||
ir.PushRSB(ir.current_location.AdvancePC(4));
|
||||
ir.SetRegister(Reg::LR, ir.Imm32(ir.current_location.PC() + 4));
|
||||
|
||||
const u32 imm32 = Common::SignExtend<26, u32>(imm24 << 2) + 8;
|
||||
const auto new_location = ir.current_location.AdvancePC(imm32);
|
||||
ir.SetTerm(IR::Term::LinkBlock{new_location});
|
||||
return false;
|
||||
}
|
||||
|
||||
// BLX <label>
|
||||
bool ArmTranslatorVisitor::arm_BLX_imm(bool H, Imm24 imm24) {
|
||||
ir.PushRSB(ir.current_location.AdvancePC(4));
|
||||
ir.SetRegister(Reg::LR, ir.Imm32(ir.current_location.PC() + 4));
|
||||
auto new_location = ir.current_location.AdvancePC(imm32).SetTFlag(true);
|
||||
|
||||
const u32 imm32 = Common::SignExtend<26, u32>((imm24 << 2)) + (H ? 2 : 0) + 8;
|
||||
const auto new_location = ir.current_location.AdvancePC(imm32).SetTFlag(true);
|
||||
ir.SetTerm(IR::Term::LinkBlock{new_location});
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_BLX_reg(Cond cond, Reg m) {
|
||||
if (m == Reg::PC)
|
||||
return UnpredictableInstruction();
|
||||
// BLX <Rm>
|
||||
if (ConditionPassed(cond)) {
|
||||
bool ArmTranslatorVisitor::arm_BLX_reg(Cond cond, Reg m) {
|
||||
if (m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ir.PushRSB(ir.current_location.AdvancePC(4));
|
||||
ir.BXWritePC(ir.GetRegister(m));
|
||||
ir.SetRegister(Reg::LR, ir.Imm32(ir.current_location.PC() + 4));
|
||||
ir.SetTerm(IR::Term::FastDispatchHint{});
|
||||
return false;
|
||||
}
|
||||
|
||||
// BX <Rm>
|
||||
bool ArmTranslatorVisitor::arm_BX(Cond cond, Reg m) {
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_BX(Cond cond, Reg m) {
|
||||
// BX <Rm>
|
||||
if (ConditionPassed(cond)) {
|
||||
ir.BXWritePC(ir.GetRegister(m));
|
||||
if (m == Reg::R14)
|
||||
if (m == Reg::R14) {
|
||||
ir.SetTerm(IR::Term::PopRSBHint{});
|
||||
else
|
||||
} else {
|
||||
ir.SetTerm(IR::Term::FastDispatchHint{});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_BXJ(Cond cond, Reg m) {
|
||||
|
|
|
@ -8,36 +8,40 @@
|
|||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
// CDP{2} <coproc_no>, #<opc1>, <CRd>, <CRn>, <CRm>, #<opc2>
|
||||
bool ArmTranslatorVisitor::arm_CDP(Cond cond, size_t opc1, CoprocReg CRn, CoprocReg CRd, size_t coproc_no, size_t opc2, CoprocReg CRm) {
|
||||
if ((coproc_no & 0b1110) == 0b1010)
|
||||
if ((coproc_no & 0b1110) == 0b1010) {
|
||||
return arm_UDF();
|
||||
}
|
||||
|
||||
const bool two = cond == Cond::NV;
|
||||
|
||||
// CDP{2} <coproc_no>, #<opc1>, <CRd>, <CRn>, <CRm>, #<opc2>
|
||||
if (two || ConditionPassed(cond)) {
|
||||
ir.CoprocInternalOperation(coproc_no, two, opc1, CRd, CRn, CRm, opc2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// LDC{2}{L}<c> <coproc_no>, <CRd>, [<Rn>, #+/-<imm32>]{!}
|
||||
// LDC{2}{L}<c> <coproc_no>, <CRd>, [<Rn>], #+/-<imm32>
|
||||
// LDC{2}{L}<c> <coproc_no>, <CRd>, [<Rn>], <imm8>
|
||||
bool ArmTranslatorVisitor::arm_LDC(Cond cond, bool p, bool u, bool d, bool w, Reg n, CoprocReg CRd, size_t coproc_no, Imm8 imm8) {
|
||||
if (!p && !u && !d && !w)
|
||||
if (!p && !u && !d && !w) {
|
||||
return arm_UDF();
|
||||
if ((coproc_no & 0b1110) == 0b1010)
|
||||
}
|
||||
|
||||
if ((coproc_no & 0b1110) == 0b1010) {
|
||||
return arm_UDF();
|
||||
}
|
||||
|
||||
const bool two = cond == Cond::NV;
|
||||
|
||||
if (two || ConditionPassed(cond)) {
|
||||
const u32 imm32 = static_cast<u8>(imm8) << 2;
|
||||
const bool index = p;
|
||||
const bool add = u;
|
||||
const bool wback = w;
|
||||
const bool has_option = !p && !w && u;
|
||||
|
||||
// LDC{2}{L} <coproc_no>, <CRd>, [<Rn>, #+/-<imm32>]{!}
|
||||
// LDC{2}{L} <coproc_no>, <CRd>, [<Rn>], #+/-<imm32>
|
||||
// LDC{2}{L} <coproc_no>, <CRd>, [<Rn>], <imm8>
|
||||
if (two || ConditionPassed(cond)) {
|
||||
const IR::U32 reg_n = ir.GetRegister(n);
|
||||
const IR::U32 offset_address = add ? ir.Add(reg_n, ir.Imm32(imm32)) : ir.Sub(reg_n, ir.Imm32(imm32));
|
||||
const IR::U32 address = index ? offset_address : reg_n;
|
||||
|
@ -49,91 +53,106 @@ bool ArmTranslatorVisitor::arm_LDC(Cond cond, bool p, bool u, bool d, bool w, Re
|
|||
return true;
|
||||
}
|
||||
|
||||
// MCR{2}<c> <coproc_no>, #<opc1>, <Rt>, <CRn>, <CRm>, #<opc2>
|
||||
bool ArmTranslatorVisitor::arm_MCR(Cond cond, size_t opc1, CoprocReg CRn, Reg t, size_t coproc_no, size_t opc2, CoprocReg CRm) {
|
||||
if ((coproc_no & 0b1110) == 0b1010)
|
||||
if ((coproc_no & 0b1110) == 0b1010) {
|
||||
return arm_UDF();
|
||||
if (t == Reg::PC)
|
||||
}
|
||||
|
||||
if (t == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const bool two = cond == Cond::NV;
|
||||
|
||||
// MCR{2} <coproc_no>, #<opc1>, <Rt>, <CRn>, <CRm>, #<opc2>
|
||||
if (two || ConditionPassed(cond)) {
|
||||
ir.CoprocSendOneWord(coproc_no, two, opc1, CRn, CRm, opc2, ir.GetRegister(t));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// MCRR{2}<c> <coproc_no>, #<opc>, <Rt>, <Rt2>, <CRm>
|
||||
bool ArmTranslatorVisitor::arm_MCRR(Cond cond, Reg t2, Reg t, size_t coproc_no, size_t opc, CoprocReg CRm) {
|
||||
if ((coproc_no & 0b1110) == 0b1010)
|
||||
if ((coproc_no & 0b1110) == 0b1010) {
|
||||
return arm_UDF();
|
||||
if (t == Reg::PC || t2 == Reg::PC)
|
||||
}
|
||||
|
||||
if (t == Reg::PC || t2 == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const bool two = cond == Cond::NV;
|
||||
|
||||
// MCRR{2} <coproc_no>, #<opc>, <Rt>, <Rt2>, <CRm>
|
||||
if (two || ConditionPassed(cond)) {
|
||||
ir.CoprocSendTwoWords(coproc_no, two, opc, CRm, ir.GetRegister(t), ir.GetRegister(t2));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// MRC{2}<c> <coproc_no>, #<opc1>, <Rt>, <CRn>, <CRm>, #<opc2>
|
||||
bool ArmTranslatorVisitor::arm_MRC(Cond cond, size_t opc1, CoprocReg CRn, Reg t, size_t coproc_no, size_t opc2, CoprocReg CRm) {
|
||||
if ((coproc_no & 0b1110) == 0b1010)
|
||||
if ((coproc_no & 0b1110) == 0b1010) {
|
||||
return arm_UDF();
|
||||
}
|
||||
|
||||
const bool two = cond == Cond::NV;
|
||||
|
||||
// MRC{2} <coproc_no>, #<opc1>, <Rt>, <CRn>, <CRm>, #<opc2>
|
||||
if (two || ConditionPassed(cond)) {
|
||||
auto word = ir.CoprocGetOneWord(coproc_no, two, opc1, CRn, CRm, opc2);
|
||||
const auto word = ir.CoprocGetOneWord(coproc_no, two, opc1, CRn, CRm, opc2);
|
||||
if (t != Reg::PC) {
|
||||
ir.SetRegister(t, word);
|
||||
} else {
|
||||
auto new_cpsr_nzcv = ir.And(word, ir.Imm32(0xF0000000));
|
||||
const auto new_cpsr_nzcv = ir.And(word, ir.Imm32(0xF0000000));
|
||||
ir.SetCpsrNZCV(new_cpsr_nzcv);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// MRRC{2}<c> <coproc_no>, #<opc>, <Rt>, <Rt2>, <CRm>
|
||||
bool ArmTranslatorVisitor::arm_MRRC(Cond cond, Reg t2, Reg t, size_t coproc_no, size_t opc, CoprocReg CRm) {
|
||||
if ((coproc_no & 0b1110) == 0b1010)
|
||||
if ((coproc_no & 0b1110) == 0b1010) {
|
||||
return arm_UDF();
|
||||
if (t == Reg::PC || t2 == Reg::PC || t == t2)
|
||||
}
|
||||
|
||||
if (t == Reg::PC || t2 == Reg::PC || t == t2) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const bool two = cond == Cond::NV;
|
||||
|
||||
// MRRC{2} <coproc_no>, #<opc>, <Rt>, <Rt2>, <CRm>
|
||||
if (two || ConditionPassed(cond)) {
|
||||
auto two_words = ir.CoprocGetTwoWords(coproc_no, two, opc, CRm);
|
||||
const auto two_words = ir.CoprocGetTwoWords(coproc_no, two, opc, CRm);
|
||||
ir.SetRegister(t, ir.LeastSignificantWord(two_words));
|
||||
ir.SetRegister(t2, ir.MostSignificantWord(two_words).result);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// STC{2}{L}<c> <coproc>, <CRd>, [<Rn>, #+/-<imm32>]{!}
|
||||
// STC{2}{L}<c> <coproc>, <CRd>, [<Rn>], #+/-<imm32>
|
||||
// STC{2}{L}<c> <coproc>, <CRd>, [<Rn>], <imm8>
|
||||
bool ArmTranslatorVisitor::arm_STC(Cond cond, bool p, bool u, bool d, bool w, Reg n, CoprocReg CRd, size_t coproc_no, Imm8 imm8) {
|
||||
if ((coproc_no & 0b1110) == 0b1010)
|
||||
if ((coproc_no & 0b1110) == 0b1010) {
|
||||
return arm_UDF();
|
||||
if (!p && !u && !d && !w)
|
||||
}
|
||||
|
||||
if (!p && !u && !d && !w) {
|
||||
return arm_UDF();
|
||||
if (n == Reg::PC && w)
|
||||
}
|
||||
|
||||
if (n == Reg::PC && w) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const bool two = cond == Cond::NV;
|
||||
|
||||
if (two || ConditionPassed(cond)) {
|
||||
const u32 imm32 = static_cast<u8>(imm8) << 2;
|
||||
const bool index = p;
|
||||
const bool add = u;
|
||||
const bool wback = w;
|
||||
const bool has_option = !p && !w && u;
|
||||
|
||||
// STC{2}{L} <coproc>, <CRd>, [<Rn>, #+/-<imm32>]{!}
|
||||
// STC{2}{L} <coproc>, <CRd>, [<Rn>], #+/-<imm32>
|
||||
// STC{2}{L} <coproc>, <CRd>, [<Rn>], <imm8>
|
||||
if (two || ConditionPassed(cond)) {
|
||||
const IR::U32 reg_n = ir.GetRegister(n);
|
||||
const IR::U32 offset_address = add ? ir.Add(reg_n, ir.Imm32(imm32)) : ir.Sub(reg_n, ir.Imm32(imm32));
|
||||
const IR::U32 address = index ? offset_address : reg_n;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -10,33 +10,37 @@
|
|||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
// BKPT #<imm16>
|
||||
bool ArmTranslatorVisitor::arm_BKPT(Cond cond, Imm12 /*imm12*/, Imm4 /*imm4*/) {
|
||||
if (cond != Cond::AL && !options.define_unpredictable_behaviour) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
// UNPREDICTABLE: The instruction executes conditionally.
|
||||
|
||||
if (ConditionPassed(cond)) {
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ir.ExceptionRaised(Exception::Breakpoint);
|
||||
ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
|
||||
return false;
|
||||
}
|
||||
|
||||
// SVC<c> #<imm24>
|
||||
bool ArmTranslatorVisitor::arm_SVC(Cond cond, Imm24 imm24) {
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_SVC(Cond cond, Imm24 imm24) {
|
||||
u32 imm32 = imm24;
|
||||
// SVC<c> #<imm24>
|
||||
if (ConditionPassed(cond)) {
|
||||
const u32 imm32 = imm24;
|
||||
ir.PushRSB(ir.current_location.AdvancePC(4));
|
||||
ir.BranchWritePC(ir.Imm32(ir.current_location.PC() + 4));
|
||||
ir.CallSupervisor(ir.Imm32(imm32));
|
||||
ir.SetTerm(IR::Term::CheckHalt{IR::Term::PopRSBHint{}});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// UDF<c> #<imm16>
|
||||
bool ArmTranslatorVisitor::arm_UDF() {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
|
|
|
@ -13,170 +13,217 @@ static IR::U32 Rotate(A32::IREmitter& ir, Reg m, SignExtendRotation rotate) {
|
|||
return ir.RotateRight(ir.GetRegister(m), ir.Imm8(rotate_by), ir.Imm1(0)).result;
|
||||
}
|
||||
|
||||
// SXTAB<c> <Rd>, <Rn>, <Rm>{, <rotation>}
|
||||
bool ArmTranslatorVisitor::arm_SXTAB(Cond cond, Reg n, Reg d, SignExtendRotation rotate, Reg m) {
|
||||
if (d == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
|
||||
// SXTAB <Rd>, <Rn>, <Rm>, <rotate>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto rotated = Rotate(ir, m, rotate);
|
||||
auto reg_n = ir.GetRegister(n);
|
||||
auto result = ir.Add(reg_n, ir.SignExtendByteToWord(ir.LeastSignificantByte(rotated)));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto rotated = Rotate(ir, m, rotate);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.Add(reg_n, ir.SignExtendByteToWord(ir.LeastSignificantByte(rotated)));
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// SXTAB16<c> <Rd>, <Rn>, <Rm>{, <rotation>}
|
||||
bool ArmTranslatorVisitor::arm_SXTAB16(Cond cond, Reg n, Reg d, SignExtendRotation rotate, Reg m) {
|
||||
if (d == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
|
||||
// SXTAB16 <Rd>, <Rn>, <Rm>, <rotate>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto rotated = Rotate(ir, m, rotate);
|
||||
auto low_byte = ir.And(rotated, ir.Imm32(0x00FF00FF));
|
||||
auto sign_bit = ir.And(rotated, ir.Imm32(0x00800080));
|
||||
auto addend = ir.Or(low_byte, ir.Mul(sign_bit, ir.Imm32(0x1FE)));
|
||||
auto result = ir.PackedAddU16(addend, ir.GetRegister(n)).result;
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto rotated = Rotate(ir, m, rotate);
|
||||
const auto low_byte = ir.And(rotated, ir.Imm32(0x00FF00FF));
|
||||
const auto sign_bit = ir.And(rotated, ir.Imm32(0x00800080));
|
||||
const auto addend = ir.Or(low_byte, ir.Mul(sign_bit, ir.Imm32(0x1FE)));
|
||||
const auto result = ir.PackedAddU16(addend, ir.GetRegister(n)).result;
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// SXTAH<c> <Rd>, <Rn>, <Rm>{, <rotation>}
|
||||
bool ArmTranslatorVisitor::arm_SXTAH(Cond cond, Reg n, Reg d, SignExtendRotation rotate, Reg m) {
|
||||
if (d == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
|
||||
// SXTAH <Rd>, <Rn>, <Rm>, <rotate>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto rotated = Rotate(ir, m, rotate);
|
||||
auto reg_n = ir.GetRegister(n);
|
||||
auto result = ir.Add(reg_n, ir.SignExtendHalfToWord(ir.LeastSignificantHalf(rotated)));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto rotated = Rotate(ir, m, rotate);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.Add(reg_n, ir.SignExtendHalfToWord(ir.LeastSignificantHalf(rotated)));
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// SXTB<c> <Rd>, <Rm>{, <rotation>}
|
||||
bool ArmTranslatorVisitor::arm_SXTB(Cond cond, Reg d, SignExtendRotation rotate, Reg m) {
|
||||
if (d == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
|
||||
// SXTB <Rd>, <Rm>, <rotate>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto rotated = Rotate(ir, m, rotate);
|
||||
auto result = ir.SignExtendByteToWord(ir.LeastSignificantByte(rotated));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto rotated = Rotate(ir, m, rotate);
|
||||
const auto result = ir.SignExtendByteToWord(ir.LeastSignificantByte(rotated));
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// SXTB16<c> <Rd>, <Rm>{, <rotation>}
|
||||
bool ArmTranslatorVisitor::arm_SXTB16(Cond cond, Reg d, SignExtendRotation rotate, Reg m) {
|
||||
if (d == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
|
||||
// SXTB16 <Rd>, <Rm>, <rotate>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto rotated = Rotate(ir, m, rotate);
|
||||
auto low_byte = ir.And(rotated, ir.Imm32(0x00FF00FF));
|
||||
auto sign_bit = ir.And(rotated, ir.Imm32(0x00800080));
|
||||
auto result = ir.Or(low_byte, ir.Mul(sign_bit, ir.Imm32(0x1FE)));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto rotated = Rotate(ir, m, rotate);
|
||||
const auto low_byte = ir.And(rotated, ir.Imm32(0x00FF00FF));
|
||||
const auto sign_bit = ir.And(rotated, ir.Imm32(0x00800080));
|
||||
const auto result = ir.Or(low_byte, ir.Mul(sign_bit, ir.Imm32(0x1FE)));
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// SXTH<c> <Rd>, <Rm>{, <rotation>}
|
||||
bool ArmTranslatorVisitor::arm_SXTH(Cond cond, Reg d, SignExtendRotation rotate, Reg m) {
|
||||
if (d == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
|
||||
// SXTH <Rd>, <Rm>, <rotate>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto rotated = Rotate(ir, m, rotate);
|
||||
auto result = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(rotated));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto rotated = Rotate(ir, m, rotate);
|
||||
const auto result = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(rotated));
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// UXTAB<c> <Rd>, <Rn>, <Rm>{, <rotation>}
|
||||
bool ArmTranslatorVisitor::arm_UXTAB(Cond cond, Reg n, Reg d, SignExtendRotation rotate, Reg m) {
|
||||
if (d == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
|
||||
// UXTAB <Rd>, <Rn>, <Rm>, <rotate>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto rotated = Rotate(ir, m, rotate);
|
||||
auto reg_n = ir.GetRegister(n);
|
||||
auto result = ir.Add(reg_n, ir.ZeroExtendByteToWord(ir.LeastSignificantByte(rotated)));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto rotated = Rotate(ir, m, rotate);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.Add(reg_n, ir.ZeroExtendByteToWord(ir.LeastSignificantByte(rotated)));
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// UXTAB16<c> <Rd>, <Rn>, <Rm>{, <rotation>}
|
||||
bool ArmTranslatorVisitor::arm_UXTAB16(Cond cond, Reg n, Reg d, SignExtendRotation rotate, Reg m) {
|
||||
if (d == Reg::PC || m == Reg::PC || n == Reg::PC)
|
||||
if (d == Reg::PC || m == Reg::PC || n == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
// UXTAB16 <Rd>, <Rn>, <Rm>, <rotate>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto rotated = Rotate(ir, m, rotate);
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto rotated = Rotate(ir, m, rotate);
|
||||
auto result = ir.And(rotated, ir.Imm32(0x00FF00FF));
|
||||
auto reg_n = ir.GetRegister(n);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
result = ir.PackedAddU16(reg_n, result).result;
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// UXTAH<c> <Rd>, <Rn>, <Rm>{, <rotation>}
|
||||
bool ArmTranslatorVisitor::arm_UXTAH(Cond cond, Reg n, Reg d, SignExtendRotation rotate, Reg m) {
|
||||
if (d == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
|
||||
// UXTAH <Rd>, <Rn>, <Rm>, <rotate>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto rotated = Rotate(ir, m, rotate);
|
||||
auto reg_n = ir.GetRegister(n);
|
||||
auto result = ir.Add(reg_n, ir.ZeroExtendHalfToWord(ir.LeastSignificantHalf(rotated)));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto rotated = Rotate(ir, m, rotate);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto result = ir.Add(reg_n, ir.ZeroExtendHalfToWord(ir.LeastSignificantHalf(rotated)));
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// UXTB<c> <Rd>, <Rm>{, <rotation>}
|
||||
bool ArmTranslatorVisitor::arm_UXTB(Cond cond, Reg d, SignExtendRotation rotate, Reg m) {
|
||||
if (d == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
|
||||
// UXTB <Rd>, <Rm>, <rotate>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto rotated = Rotate(ir, m, rotate);
|
||||
auto result = ir.ZeroExtendByteToWord(ir.LeastSignificantByte(rotated));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto rotated = Rotate(ir, m, rotate);
|
||||
const auto result = ir.ZeroExtendByteToWord(ir.LeastSignificantByte(rotated));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// UXTB16<c> <Rd>, <Rm>{, <rotation>}
|
||||
bool ArmTranslatorVisitor::arm_UXTB16(Cond cond, Reg d, SignExtendRotation rotate, Reg m) {
|
||||
if (d == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
|
||||
// UXTB16 <Rd>, <Rm>, <rotate>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto rotated = Rotate(ir, m, rotate);
|
||||
auto result = ir.And(rotated, ir.Imm32(0x00FF00FF));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_UXTH(Cond cond, Reg d, SignExtendRotation rotate, Reg m) {
|
||||
if (d == Reg::PC || m == Reg::PC)
|
||||
return UnpredictableInstruction();
|
||||
const auto rotated = Rotate(ir, m, rotate);
|
||||
const auto result = ir.And(rotated, ir.Imm32(0x00FF00FF));
|
||||
|
||||
// UXTH <Rd>, <Rm>, <rotate>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto rotated = Rotate(ir, m, rotate);
|
||||
auto result = ir.ZeroExtendHalfToWord(ir.LeastSignificantHalf(rotated));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// UXTH<c> <Rd>, <Rm>{, <rotation>}
|
||||
bool ArmTranslatorVisitor::arm_UXTH(Cond cond, Reg d, SignExtendRotation rotate, Reg m) {
|
||||
if (d == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto rotated = Rotate(ir, m, rotate);
|
||||
const auto result = ir.ZeroExtendHalfToWord(ir.LeastSignificantHalf(rotated));
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -8,26 +8,35 @@
|
|||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
// CLZ<c> <Rd>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_CLZ(Cond cond, Reg d, Reg m) {
|
||||
if (d == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
ir.SetRegister(d, ir.CountLeadingZeros(ir.GetRegister(m)));
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_SEL(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (n == Reg::PC || d == Reg::PC || m == Reg::PC)
|
||||
return UnpredictableInstruction();
|
||||
|
||||
if (ConditionPassed(cond)) {
|
||||
auto to = ir.GetRegister(m);
|
||||
auto from = ir.GetRegister(n);
|
||||
auto result = ir.PackedSelect(ir.GetGEFlags(), to, from);
|
||||
ir.SetRegister(d, result);
|
||||
ir.SetRegister(d, ir.CountLeadingZeros(ir.GetRegister(m)));
|
||||
return true;
|
||||
}
|
||||
|
||||
// SEL<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_SEL(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (n == Reg::PC || d == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto to = ir.GetRegister(m);
|
||||
const auto from = ir.GetRegister(n);
|
||||
const auto result = ir.PackedSelect(ir.GetGEFlags(), to, from);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,149 +8,209 @@
|
|||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
// Multiply (Normal) instructions
|
||||
// MLA{S}<c> <Rd>, <Rn>, <Rm>, <Ra>
|
||||
bool ArmTranslatorVisitor::arm_MLA(Cond cond, bool S, Reg d, Reg a, Reg m, Reg n) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.Add(ir.Mul(ir.GetRegister(n), ir.GetRegister(m)), ir.GetRegister(a));
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.Add(ir.Mul(ir.GetRegister(n), ir.GetRegister(m)), ir.GetRegister(a));
|
||||
ir.SetRegister(d, result);
|
||||
if (S) {
|
||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
||||
ir.SetZFlag(ir.IsZero(result));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// MUL{S}<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_MUL(Cond cond, bool S, Reg d, Reg m, Reg n) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.Mul(ir.GetRegister(n), ir.GetRegister(m));
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.Mul(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
if (S) {
|
||||
ir.SetNFlag(ir.MostSignificantBit(result));
|
||||
ir.SetZFlag(ir.IsZero(result));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Multiply (Long) instructions
|
||||
// SMLAL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_SMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
|
||||
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (dLo == dHi)
|
||||
}
|
||||
|
||||
if (dLo == dHi) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
|
||||
auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
|
||||
auto product = ir.Mul(n64, m64);
|
||||
auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
|
||||
auto result = ir.Add(product, addend);
|
||||
auto lo = ir.LeastSignificantWord(result);
|
||||
auto hi = ir.MostSignificantWord(result).result;
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
|
||||
const auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
|
||||
const auto product = ir.Mul(n64, m64);
|
||||
const auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
|
||||
const auto result = ir.Add(product, addend);
|
||||
const auto lo = ir.LeastSignificantWord(result);
|
||||
const auto hi = ir.MostSignificantWord(result).result;
|
||||
|
||||
ir.SetRegister(dLo, lo);
|
||||
ir.SetRegister(dHi, hi);
|
||||
if (S) {
|
||||
ir.SetNFlag(ir.MostSignificantBit(hi));
|
||||
ir.SetZFlag(ir.IsZero(result));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// SMULL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_SMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
|
||||
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (dLo == dHi)
|
||||
}
|
||||
|
||||
if (dLo == dHi) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
|
||||
auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
|
||||
auto result = ir.Mul(n64, m64);
|
||||
auto lo = ir.LeastSignificantWord(result);
|
||||
auto hi = ir.MostSignificantWord(result).result;
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
|
||||
const auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
|
||||
const auto result = ir.Mul(n64, m64);
|
||||
const auto lo = ir.LeastSignificantWord(result);
|
||||
const auto hi = ir.MostSignificantWord(result).result;
|
||||
|
||||
ir.SetRegister(dLo, lo);
|
||||
ir.SetRegister(dHi, hi);
|
||||
if (S) {
|
||||
ir.SetNFlag(ir.MostSignificantBit(hi));
|
||||
ir.SetZFlag(ir.IsZero(result));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// UMAAL<c> <RdLo>, <RdHi>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_UMAAL(Cond cond, Reg dHi, Reg dLo, Reg m, Reg n) {
|
||||
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (dLo == dHi)
|
||||
}
|
||||
|
||||
if (dLo == dHi) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto lo64 = ir.ZeroExtendWordToLong(ir.GetRegister(dLo));
|
||||
auto hi64 = ir.ZeroExtendWordToLong(ir.GetRegister(dHi));
|
||||
auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n));
|
||||
auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m));
|
||||
auto result = ir.Add(ir.Add(ir.Mul(n64, m64), hi64), lo64);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto lo64 = ir.ZeroExtendWordToLong(ir.GetRegister(dLo));
|
||||
const auto hi64 = ir.ZeroExtendWordToLong(ir.GetRegister(dHi));
|
||||
const auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n));
|
||||
const auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m));
|
||||
const auto result = ir.Add(ir.Add(ir.Mul(n64, m64), hi64), lo64);
|
||||
|
||||
ir.SetRegister(dLo, ir.LeastSignificantWord(result));
|
||||
ir.SetRegister(dHi, ir.MostSignificantWord(result).result);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// UMLAL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_UMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
|
||||
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (dLo == dHi)
|
||||
}
|
||||
|
||||
if (dLo == dHi) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
|
||||
auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n));
|
||||
auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m));
|
||||
auto result = ir.Add(ir.Mul(n64, m64), addend);
|
||||
auto lo = ir.LeastSignificantWord(result);
|
||||
auto hi = ir.MostSignificantWord(result).result;
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
|
||||
const auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n));
|
||||
const auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m));
|
||||
const auto result = ir.Add(ir.Mul(n64, m64), addend);
|
||||
const auto lo = ir.LeastSignificantWord(result);
|
||||
const auto hi = ir.MostSignificantWord(result).result;
|
||||
|
||||
ir.SetRegister(dLo, lo);
|
||||
ir.SetRegister(dHi, hi);
|
||||
if (S) {
|
||||
ir.SetNFlag(ir.MostSignificantBit(hi));
|
||||
ir.SetZFlag(ir.IsZero(result));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// UMULL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_UMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
|
||||
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (dLo == dHi)
|
||||
}
|
||||
|
||||
if (dLo == dHi) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n));
|
||||
auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m));
|
||||
auto result = ir.Mul(n64, m64);
|
||||
auto lo = ir.LeastSignificantWord(result);
|
||||
auto hi = ir.MostSignificantWord(result).result;
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n));
|
||||
const auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m));
|
||||
const auto result = ir.Mul(n64, m64);
|
||||
const auto lo = ir.LeastSignificantWord(result);
|
||||
const auto hi = ir.MostSignificantWord(result).result;
|
||||
|
||||
ir.SetRegister(dLo, lo);
|
||||
ir.SetRegister(dHi, hi);
|
||||
if (S) {
|
||||
ir.SetNFlag(ir.MostSignificantBit(hi));
|
||||
ir.SetZFlag(ir.IsZero(result));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Multiply (Halfword) instructions
|
||||
// SMLAL<x><y><c> <RdLo>, <RdHi>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_SMLALxy(Cond cond, Reg dHi, Reg dLo, Reg m, bool M, bool N, Reg n) {
|
||||
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (dLo == dHi)
|
||||
}
|
||||
|
||||
if (dLo == dHi) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const IR::U32 n32 = ir.GetRegister(n);
|
||||
const IR::U32 m32 = ir.GetRegister(m);
|
||||
const IR::U32 n16 = N ? ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result
|
||||
|
@ -158,18 +218,24 @@ bool ArmTranslatorVisitor::arm_SMLALxy(Cond cond, Reg dHi, Reg dLo, Reg m, bool
|
|||
const IR::U32 m16 = M ? ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result
|
||||
: ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
|
||||
const IR::U64 product = ir.SignExtendWordToLong(ir.Mul(n16, m16));
|
||||
auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
|
||||
auto result = ir.Add(product, addend);
|
||||
const auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
|
||||
const auto result = ir.Add(product, addend);
|
||||
|
||||
ir.SetRegister(dLo, ir.LeastSignificantWord(result));
|
||||
ir.SetRegister(dHi, ir.MostSignificantWord(result).result);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// SMLA<x><y><c> <Rd>, <Rn>, <Rm>, <Ra>
|
||||
bool ArmTranslatorVisitor::arm_SMLAxy(Cond cond, Reg d, Reg a, Reg m, bool M, bool N, Reg n) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const IR::U32 n32 = ir.GetRegister(n);
|
||||
const IR::U32 m32 = ir.GetRegister(m);
|
||||
const IR::U32 n16 = N ? ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result
|
||||
|
@ -177,17 +243,23 @@ bool ArmTranslatorVisitor::arm_SMLAxy(Cond cond, Reg d, Reg a, Reg m, bool M, bo
|
|||
const IR::U32 m16 = M ? ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result
|
||||
: ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
|
||||
const IR::U32 product = ir.Mul(n16, m16);
|
||||
auto result_overflow = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0));
|
||||
const auto result_overflow = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0));
|
||||
|
||||
ir.SetRegister(d, result_overflow.result);
|
||||
ir.OrQFlag(result_overflow.overflow);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// SMUL<x><y><c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_SMULxy(Cond cond, Reg d, Reg m, bool M, bool N, Reg n) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const IR::U32 n32 = ir.GetRegister(n);
|
||||
const IR::U32 m32 = ir.GetRegister(m);
|
||||
const IR::U32 n16 = N ? ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result
|
||||
|
@ -195,236 +267,326 @@ bool ArmTranslatorVisitor::arm_SMULxy(Cond cond, Reg d, Reg m, bool M, bool N, R
|
|||
const IR::U32 m16 = M ? ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result
|
||||
: ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
|
||||
const IR::U32 result = ir.Mul(n16, m16);
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Multiply (word by halfword) instructions
|
||||
// SMLAW<y><c> <Rd>, <Rn>, <Rm>, <Ra>
|
||||
bool ArmTranslatorVisitor::arm_SMLAWy(Cond cond, Reg d, Reg a, Reg m, bool M, Reg n) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const IR::U64 n32 = ir.SignExtendWordToLong(ir.GetRegister(n));
|
||||
IR::U32 m32 = ir.GetRegister(m);
|
||||
if (M)
|
||||
if (M) {
|
||||
m32 = ir.LogicalShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
|
||||
}
|
||||
const IR::U64 m16 = ir.SignExtendWordToLong(ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32)));
|
||||
auto product = ir.LeastSignificantWord(ir.LogicalShiftRight(ir.Mul(n32, m16), ir.Imm8(16)));
|
||||
auto result_overflow = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0));
|
||||
const auto product = ir.LeastSignificantWord(ir.LogicalShiftRight(ir.Mul(n32, m16), ir.Imm8(16)));
|
||||
const auto result_overflow = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0));
|
||||
|
||||
ir.SetRegister(d, result_overflow.result);
|
||||
ir.OrQFlag(result_overflow.overflow);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// SMULW<y><c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_SMULWy(Cond cond, Reg d, Reg m, bool M, Reg n) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const IR::U64 n32 = ir.SignExtendWordToLong(ir.GetRegister(n));
|
||||
IR::U32 m32 = ir.GetRegister(m);
|
||||
if (M)
|
||||
if (M) {
|
||||
m32 = ir.LogicalShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
|
||||
}
|
||||
const IR::U64 m16 = ir.SignExtendWordToLong(ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32)));
|
||||
auto result = ir.LogicalShiftRight(ir.Mul(n32, m16), ir.Imm8(16));
|
||||
const auto result = ir.LogicalShiftRight(ir.Mul(n32, m16), ir.Imm8(16));
|
||||
|
||||
ir.SetRegister(d, ir.LeastSignificantWord(result));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Multiply (Most significant word) instructions
|
||||
// SMMLA{R}<c> <Rd>, <Rn>, <Rm>, <Ra>
|
||||
bool ArmTranslatorVisitor::arm_SMMLA(Cond cond, Reg d, Reg a, Reg m, bool R, Reg n) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC /* no check for a */)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC /* no check for a */) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
|
||||
auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
|
||||
auto a64 = ir.Pack2x32To1x64(ir.Imm32(0), ir.GetRegister(a));
|
||||
auto temp = ir.Add(a64, ir.Mul(n64, m64));
|
||||
auto result_carry = ir.MostSignificantWord(temp);
|
||||
auto result = result_carry.result;
|
||||
if (R)
|
||||
result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
|
||||
const auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
|
||||
const auto a64 = ir.Pack2x32To1x64(ir.Imm32(0), ir.GetRegister(a));
|
||||
const auto temp = ir.Add(a64, ir.Mul(n64, m64));
|
||||
const auto result_carry = ir.MostSignificantWord(temp);
|
||||
auto result = result_carry.result;
|
||||
if (R) {
|
||||
result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
|
||||
}
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// SMMLS{R}<c> <Rd>, <Rn>, <Rm>, <Ra>
|
||||
bool ArmTranslatorVisitor::arm_SMMLS(Cond cond, Reg d, Reg a, Reg m, bool R, Reg n) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
|
||||
auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
|
||||
auto a64 = ir.Pack2x32To1x64(ir.Imm32(0), ir.GetRegister(a));
|
||||
auto temp = ir.Sub(a64, ir.Mul(n64, m64));
|
||||
auto result_carry = ir.MostSignificantWord(temp);
|
||||
auto result = result_carry.result;
|
||||
if (R)
|
||||
result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
|
||||
const auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
|
||||
const auto a64 = ir.Pack2x32To1x64(ir.Imm32(0), ir.GetRegister(a));
|
||||
const auto temp = ir.Sub(a64, ir.Mul(n64, m64));
|
||||
const auto result_carry = ir.MostSignificantWord(temp);
|
||||
auto result = result_carry.result;
|
||||
if (R) {
|
||||
result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
|
||||
}
|
||||
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// SMMUL{R}<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_SMMUL(Cond cond, Reg d, Reg m, bool R, Reg n) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
|
||||
auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
|
||||
auto product = ir.Mul(n64, m64);
|
||||
auto result_carry = ir.MostSignificantWord(product);
|
||||
auto result = result_carry.result;
|
||||
if (R)
|
||||
result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
|
||||
const auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
|
||||
const auto product = ir.Mul(n64, m64);
|
||||
const auto result_carry = ir.MostSignificantWord(product);
|
||||
auto result = result_carry.result;
|
||||
if (R) {
|
||||
result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
|
||||
}
|
||||
|
||||
// Multiply (Dual) instructions
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// SMLAD{X}<c> <Rd>, <Rn>, <Rm>, <Ra>
|
||||
bool ArmTranslatorVisitor::arm_SMLAD(Cond cond, Reg d, Reg a, Reg m, bool M, Reg n) {
|
||||
if (a == Reg::PC)
|
||||
if (a == Reg::PC) {
|
||||
return arm_SMUAD(cond, d, m, M, n);
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
}
|
||||
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const IR::U32 n32 = ir.GetRegister(n);
|
||||
const IR::U32 m32 = ir.GetRegister(m);
|
||||
const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
|
||||
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
|
||||
const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
|
||||
|
||||
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
|
||||
IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
|
||||
if (M)
|
||||
if (M) {
|
||||
std::swap(m_lo, m_hi);
|
||||
}
|
||||
|
||||
const IR::U32 product_lo = ir.Mul(n_lo, m_lo);
|
||||
const IR::U32 product_hi = ir.Mul(n_hi, m_hi);
|
||||
const IR::U32 addend = ir.GetRegister(a);
|
||||
|
||||
auto result_overflow = ir.AddWithCarry(product_lo, product_hi, ir.Imm1(0));
|
||||
ir.OrQFlag(result_overflow.overflow);
|
||||
result_overflow = ir.AddWithCarry(result_overflow.result, addend, ir.Imm1(0));
|
||||
ir.SetRegister(d, result_overflow.result);
|
||||
ir.OrQFlag(result_overflow.overflow);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// SMLALD{X}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_SMLALD(Cond cond, Reg dHi, Reg dLo, Reg m, bool M, Reg n) {
|
||||
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (dLo == dHi)
|
||||
}
|
||||
|
||||
if (dLo == dHi) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const IR::U32 n32 = ir.GetRegister(n);
|
||||
const IR::U32 m32 = ir.GetRegister(m);
|
||||
const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
|
||||
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
|
||||
const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
|
||||
|
||||
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
|
||||
IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
|
||||
if (M)
|
||||
if (M) {
|
||||
std::swap(m_lo, m_hi);
|
||||
}
|
||||
|
||||
const IR::U64 product_lo = ir.SignExtendWordToLong(ir.Mul(n_lo, m_lo));
|
||||
const IR::U64 product_hi = ir.SignExtendWordToLong(ir.Mul(n_hi, m_hi));
|
||||
auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
|
||||
auto result = ir.Add(ir.Add(product_lo, product_hi), addend);
|
||||
const auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
|
||||
const auto result = ir.Add(ir.Add(product_lo, product_hi), addend);
|
||||
|
||||
ir.SetRegister(dLo, ir.LeastSignificantWord(result));
|
||||
ir.SetRegister(dHi, ir.MostSignificantWord(result).result);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// SMLSD{X}<c> <Rd>, <Rn>, <Rm>, <Ra>
|
||||
bool ArmTranslatorVisitor::arm_SMLSD(Cond cond, Reg d, Reg a, Reg m, bool M, Reg n) {
|
||||
if (a == Reg::PC)
|
||||
if (a == Reg::PC) {
|
||||
return arm_SMUSD(cond, d, m, M, n);
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
}
|
||||
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const IR::U32 n32 = ir.GetRegister(n);
|
||||
const IR::U32 m32 = ir.GetRegister(m);
|
||||
const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
|
||||
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
|
||||
const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
|
||||
|
||||
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
|
||||
IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
|
||||
if (M)
|
||||
if (M) {
|
||||
std::swap(m_lo, m_hi);
|
||||
}
|
||||
|
||||
const IR::U32 product_lo = ir.Mul(n_lo, m_lo);
|
||||
const IR::U32 product_hi = ir.Mul(n_hi, m_hi);
|
||||
const IR::U32 addend = ir.GetRegister(a);
|
||||
const IR::U32 product = ir.Sub(product_lo, product_hi);
|
||||
auto result_overflow = ir.AddWithCarry(product, addend, ir.Imm1(0));
|
||||
|
||||
ir.SetRegister(d, result_overflow.result);
|
||||
ir.OrQFlag(result_overflow.overflow);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// SMLSLD{X}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_SMLSLD(Cond cond, Reg dHi, Reg dLo, Reg m, bool M, Reg n) {
|
||||
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (dLo == dHi)
|
||||
}
|
||||
|
||||
if (dLo == dHi) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const IR::U32 n32 = ir.GetRegister(n);
|
||||
const IR::U32 m32 = ir.GetRegister(m);
|
||||
const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
|
||||
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
|
||||
const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
|
||||
|
||||
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
|
||||
IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
|
||||
if (M)
|
||||
if (M) {
|
||||
std::swap(m_lo, m_hi);
|
||||
}
|
||||
|
||||
const IR::U64 product_lo = ir.SignExtendWordToLong(ir.Mul(n_lo, m_lo));
|
||||
const IR::U64 product_hi = ir.SignExtendWordToLong(ir.Mul(n_hi, m_hi));
|
||||
auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
|
||||
auto result = ir.Add(ir.Sub(product_lo, product_hi), addend);
|
||||
const auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
|
||||
const auto result = ir.Add(ir.Sub(product_lo, product_hi), addend);
|
||||
|
||||
ir.SetRegister(dLo, ir.LeastSignificantWord(result));
|
||||
ir.SetRegister(dHi, ir.MostSignificantWord(result).result);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// SMUAD{X}<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_SMUAD(Cond cond, Reg d, Reg m, bool M, Reg n) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const IR::U32 n32 = ir.GetRegister(n);
|
||||
const IR::U32 m32 = ir.GetRegister(m);
|
||||
const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
|
||||
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
|
||||
const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
|
||||
|
||||
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
|
||||
IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
|
||||
if (M)
|
||||
if (M) {
|
||||
std::swap(m_lo, m_hi);
|
||||
}
|
||||
|
||||
const IR::U32 product_lo = ir.Mul(n_lo, m_lo);
|
||||
const IR::U32 product_hi = ir.Mul(n_hi, m_hi);
|
||||
auto result_overflow = ir.AddWithCarry(product_lo, product_hi, ir.Imm1(0));
|
||||
const auto result_overflow = ir.AddWithCarry(product_lo, product_hi, ir.Imm1(0));
|
||||
|
||||
ir.SetRegister(d, result_overflow.result);
|
||||
ir.OrQFlag(result_overflow.overflow);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// SMUSD{X}<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_SMUSD(Cond cond, Reg d, Reg m, bool M, Reg n) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const IR::U32 n32 = ir.GetRegister(n);
|
||||
const IR::U32 m32 = ir.GetRegister(m);
|
||||
const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
|
||||
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
|
||||
const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
|
||||
|
||||
IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
|
||||
IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
|
||||
if (M)
|
||||
if (M) {
|
||||
std::swap(m_lo, m_hi);
|
||||
}
|
||||
|
||||
const IR::U32 product_lo = ir.Mul(n_lo, m_lo);
|
||||
const IR::U32 product_hi = ir.Mul(n_hi, m_hi);
|
||||
auto result = ir.Sub(product_lo, product_hi);
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,31 +8,39 @@
|
|||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
// PKHBT<c> <Rd>, <Rn>, <Rm>{, LSL #<imm>}
|
||||
bool ArmTranslatorVisitor::arm_PKHBT(Cond cond, Reg n, Reg d, Imm5 imm5, Reg m) {
|
||||
if (n == Reg::PC || d == Reg::PC || m == Reg::PC)
|
||||
if (n == Reg::PC || d == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
|
||||
if (ConditionPassed(cond)) {
|
||||
auto shifted = EmitImmShift(ir.GetRegister(m), ShiftType::LSL, imm5, ir.Imm1(false)).result;
|
||||
auto lower_half = ir.And(ir.GetRegister(n), ir.Imm32(0x0000FFFF));
|
||||
auto upper_half = ir.And(shifted, ir.Imm32(0xFFFF0000));
|
||||
ir.SetRegister(d, ir.Or(lower_half, upper_half));
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_PKHTB(Cond cond, Reg n, Reg d, Imm5 imm5, Reg m) {
|
||||
if (n == Reg::PC || d == Reg::PC || m == Reg::PC)
|
||||
return UnpredictableInstruction();
|
||||
const auto shifted = EmitImmShift(ir.GetRegister(m), ShiftType::LSL, imm5, ir.Imm1(false)).result;
|
||||
const auto lower_half = ir.And(ir.GetRegister(n), ir.Imm32(0x0000FFFF));
|
||||
const auto upper_half = ir.And(shifted, ir.Imm32(0xFFFF0000));
|
||||
|
||||
if (ConditionPassed(cond)) {
|
||||
auto shifted = EmitImmShift(ir.GetRegister(m), ShiftType::ASR, imm5, ir.Imm1(false)).result;
|
||||
auto lower_half = ir.And(shifted, ir.Imm32(0x0000FFFF));
|
||||
auto upper_half = ir.And(ir.GetRegister(n), ir.Imm32(0xFFFF0000));
|
||||
ir.SetRegister(d, ir.Or(lower_half, upper_half));
|
||||
return true;
|
||||
}
|
||||
|
||||
// PKHTB<c> <Rd>, <Rn>, <Rm>{, ASR #<imm>}
|
||||
bool ArmTranslatorVisitor::arm_PKHTB(Cond cond, Reg n, Reg d, Imm5 imm5, Reg m) {
|
||||
if (n == Reg::PC || d == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto shifted = EmitImmShift(ir.GetRegister(m), ShiftType::ASR, imm5, ir.Imm1(false)).result;
|
||||
const auto lower_half = ir.And(shifted, ir.Imm32(0x0000FFFF));
|
||||
const auto upper_half = ir.And(ir.GetRegister(n), ir.Imm32(0xFFFF0000));
|
||||
|
||||
ir.SetRegister(d, ir.Or(lower_half, upper_half));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,359 +8,530 @@
|
|||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
// Parallel Add/Subtract (Modulo arithmetic) instructions
|
||||
// SADD8<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_SADD8(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedAddS8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedAddS8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
// SADD16<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_SADD16(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedAddS16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedAddS16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
// SASX<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_SASX(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedAddSubS16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedAddSubS16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
// SSAX<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_SSAX(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedSubAddS16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedSubAddS16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
// SSUB8<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_SSUB8(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedSubS8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedSubS8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
// SSUB16<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_SSUB16(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedSubS16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedSubS16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
// UADD8<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_UADD8(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedAddU8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedAddU8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
// UADD16<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_UADD16(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedAddU16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedAddU16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
// UASX<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_UASX(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedAddSubU16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedAddSubU16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
// USAX<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_USAX(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedSubAddU16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedSubAddU16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
// USAD8<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_USAD8(Cond cond, Reg d, Reg m, Reg n) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedAbsDiffSumS8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedAbsDiffSumS8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// USADA8<c> <Rd>, <Rn>, <Rm>, <Ra>
|
||||
bool ArmTranslatorVisitor::arm_USADA8(Cond cond, Reg d, Reg a, Reg m, Reg n){
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto tmp = ir.PackedAbsDiffSumS8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
auto result = ir.AddWithCarry(ir.GetRegister(a), tmp, ir.Imm1(0));
|
||||
ir.SetRegister(d, result.result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto tmp = ir.PackedAbsDiffSumS8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
const auto result = ir.AddWithCarry(ir.GetRegister(a), tmp, ir.Imm1(0));
|
||||
ir.SetRegister(d, result.result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// USUB8<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_USUB8(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedSubU8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_USUB16(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedSubU16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
const auto result = ir.PackedSubU8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
// USUB16<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_USUB16(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedSubU16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.SetGEFlags(result.ge);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parallel Add/Subtract (Saturating) instructions
|
||||
|
||||
// QADD8<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_QADD8(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedSaturatedAddS8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedSaturatedAddS8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// QADD16<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_QADD16(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedSaturatedAddS16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedSaturatedAddS16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// QSUB8<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_QSUB8(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedSaturatedSubS8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedSaturatedSubS8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// QSUB16<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_QSUB16(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedSaturatedSubS16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedSaturatedSubS16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// UQADD8<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_UQADD8(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedSaturatedAddU8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedSaturatedAddU8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// UQADD16<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_UQADD16(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedSaturatedAddU16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedSaturatedAddU16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// UQSUB8<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_UQSUB8(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedSaturatedSubU8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_UQSUB16(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedSaturatedSubU16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
const auto result = ir.PackedSaturatedSubU8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// UQSUB16<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_UQSUB16(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedSaturatedSubU16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parallel Add/Subtract (Halving) instructions
|
||||
|
||||
// SHADD8<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_SHADD8(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedHalvingAddS8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedHalvingAddS8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// SHADD16<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_SHADD16(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedHalvingAddS16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedHalvingAddS16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// SHASX<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_SHASX(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedHalvingAddSubS16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedHalvingAddSubS16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// SHSAX<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_SHSAX(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedHalvingSubAddS16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedHalvingSubAddS16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// SHSUB8<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_SHSUB8(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedHalvingSubS8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedHalvingSubS8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// SHSUB16<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_SHSUB16(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedHalvingSubS16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedHalvingSubS16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// UHADD8<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_UHADD8(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedHalvingAddU8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedHalvingAddU8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// UHADD16<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_UHADD16(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedHalvingAddU16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedHalvingAddU16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// UHASX<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_UHASX(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedHalvingAddSubU16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedHalvingAddSubU16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// UHSAX<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_UHSAX(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedHalvingSubAddU16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedHalvingSubAddU16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// UHSUB8<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_UHSUB8(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedHalvingSubU8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_UHSUB16(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
return UnpredictableInstruction();
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.PackedHalvingSubU16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
const auto result = ir.PackedHalvingSubU8(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// UHSUB16<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_UHSUB16(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.PackedHalvingSubU16(ir.GetRegister(n), ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,41 +8,52 @@
|
|||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
bool ArmTranslatorVisitor::arm_REV(Cond cond, Reg d, Reg m) {
|
||||
// REV<c> <Rd>, <Rm>
|
||||
if (d == Reg::PC || m == Reg::PC)
|
||||
bool ArmTranslatorVisitor::arm_REV(Cond cond, Reg d, Reg m) {
|
||||
if (d == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.ByteReverseWord(ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto result = ir.ByteReverseWord(ir.GetRegister(m));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// REV16<c> <Rd>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_REV16(Cond cond, Reg d, Reg m) {
|
||||
if (d == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
|
||||
if (ConditionPassed(cond)) {
|
||||
auto reg_m = ir.GetRegister(m);
|
||||
auto lo = ir.And(ir.LogicalShiftRight(reg_m, ir.Imm8(8), ir.Imm1(0)).result, ir.Imm32(0x00FF00FF));
|
||||
auto hi = ir.And(ir.LogicalShiftLeft(reg_m, ir.Imm8(8), ir.Imm1(0)).result, ir.Imm32(0xFF00FF00));
|
||||
auto result = ir.Or(lo, hi);
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_REVSH(Cond cond, Reg d, Reg m) {
|
||||
// REVSH<c> <Rd>, <Rm>
|
||||
if (d == Reg::PC || m == Reg::PC)
|
||||
return UnpredictableInstruction();
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto lo = ir.And(ir.LogicalShiftRight(reg_m, ir.Imm8(8), ir.Imm1(0)).result, ir.Imm32(0x00FF00FF));
|
||||
const auto hi = ir.And(ir.LogicalShiftLeft(reg_m, ir.Imm8(8), ir.Imm1(0)).result, ir.Imm32(0xFF00FF00));
|
||||
const auto result = ir.Or(lo, hi);
|
||||
|
||||
if (ConditionPassed(cond)) {
|
||||
auto rev_half = ir.ByteReverseHalf(ir.LeastSignificantHalf(ir.GetRegister(m)));
|
||||
ir.SetRegister(d, ir.SignExtendHalfToWord(rev_half));
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// REVSH<c> <Rd>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_REVSH(Cond cond, Reg d, Reg m) {
|
||||
if (d == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto rev_half = ir.ByteReverseHalf(ir.LeastSignificantHalf(ir.GetRegister(m)));
|
||||
ir.SetRegister(d, ir.SignExtendHalfToWord(rev_half));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,224 +18,268 @@ static IR::U16 MostSignificantHalf(A32::IREmitter& ir, IR::U32 value) {
|
|||
|
||||
// Saturation instructions
|
||||
|
||||
// SSAT<c> <Rd>, #<imm>, <Rn>{, <shift>}
|
||||
bool ArmTranslatorVisitor::arm_SSAT(Cond cond, Imm5 sat_imm, Reg d, Imm5 imm5, bool sh, Reg n) {
|
||||
if (d == Reg::PC || n == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
|
||||
size_t saturate_to = static_cast<size_t>(sat_imm) + 1;
|
||||
ShiftType shift = !sh ? ShiftType::LSL : ShiftType::ASR;
|
||||
|
||||
// SSAT <Rd>, #<saturate_to>, <Rn>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto operand = EmitImmShift(ir.GetRegister(n), shift, imm5, ir.GetCFlag());
|
||||
auto result = ir.SignedSaturation(operand.result, saturate_to);
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.OrQFlag(result.overflow);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto saturate_to = static_cast<size_t>(sat_imm) + 1;
|
||||
const auto shift = !sh ? ShiftType::LSL : ShiftType::ASR;
|
||||
const auto operand = EmitImmShift(ir.GetRegister(n), shift, imm5, ir.GetCFlag());
|
||||
const auto result = ir.SignedSaturation(operand.result, saturate_to);
|
||||
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.OrQFlag(result.overflow);
|
||||
return true;
|
||||
}
|
||||
|
||||
// SSAT16<c> <Rd>, #<imm>, <Rn>
|
||||
bool ArmTranslatorVisitor::arm_SSAT16(Cond cond, Imm4 sat_imm, Reg d, Reg n) {
|
||||
if (d == Reg::PC || n == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
|
||||
size_t saturate_to = static_cast<size_t>(sat_imm) + 1;
|
||||
|
||||
// SSAT16 <Rd>, #<saturate_to>, <Rn>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto lo_operand = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(ir.GetRegister(n)));
|
||||
auto hi_operand = ir.SignExtendHalfToWord(MostSignificantHalf(ir, ir.GetRegister(n)));
|
||||
auto lo_result = ir.SignedSaturation(lo_operand, saturate_to);
|
||||
auto hi_result = ir.SignedSaturation(hi_operand, saturate_to);
|
||||
ir.SetRegister(d, Pack2x16To1x32(ir, lo_result.result, hi_result.result));
|
||||
ir.OrQFlag(lo_result.overflow);
|
||||
ir.OrQFlag(hi_result.overflow);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto saturate_to = static_cast<size_t>(sat_imm) + 1;
|
||||
const auto lo_operand = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(ir.GetRegister(n)));
|
||||
const auto hi_operand = ir.SignExtendHalfToWord(MostSignificantHalf(ir, ir.GetRegister(n)));
|
||||
const auto lo_result = ir.SignedSaturation(lo_operand, saturate_to);
|
||||
const auto hi_result = ir.SignedSaturation(hi_operand, saturate_to);
|
||||
|
||||
ir.SetRegister(d, Pack2x16To1x32(ir, lo_result.result, hi_result.result));
|
||||
ir.OrQFlag(lo_result.overflow);
|
||||
ir.OrQFlag(hi_result.overflow);
|
||||
return true;
|
||||
}
|
||||
|
||||
// USAT<c> <Rd>, #<imm5>, <Rn>{, <shift>}
|
||||
bool ArmTranslatorVisitor::arm_USAT(Cond cond, Imm5 sat_imm, Reg d, Imm5 imm5, bool sh, Reg n) {
|
||||
if (d == Reg::PC || n == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
size_t saturate_to = static_cast<size_t>(sat_imm);
|
||||
ShiftType shift = !sh ? ShiftType::LSL : ShiftType::ASR;
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto saturate_to = static_cast<size_t>(sat_imm);
|
||||
const auto shift = !sh ? ShiftType::LSL : ShiftType::ASR;
|
||||
const auto operand = EmitImmShift(ir.GetRegister(n), shift, imm5, ir.GetCFlag());
|
||||
const auto result = ir.UnsignedSaturation(operand.result, saturate_to);
|
||||
|
||||
// USAT <Rd>, #<saturate_to>, <Rn>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto operand = EmitImmShift(ir.GetRegister(n), shift, imm5, ir.GetCFlag());
|
||||
auto result = ir.UnsignedSaturation(operand.result, saturate_to);
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.OrQFlag(result.overflow);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// USAT16<c> <Rd>, #<imm4>, <Rn>
|
||||
bool ArmTranslatorVisitor::arm_USAT16(Cond cond, Imm4 sat_imm, Reg d, Reg n) {
|
||||
if (d == Reg::PC || n == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
size_t saturate_to = static_cast<size_t>(sat_imm);
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// USAT16 <Rd>, #<saturate_to>, <Rn>
|
||||
if (ConditionPassed(cond)) {
|
||||
// UnsignedSaturation takes a *signed* value as input, hence sign extension is required.
|
||||
auto lo_operand = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(ir.GetRegister(n)));
|
||||
auto hi_operand = ir.SignExtendHalfToWord(MostSignificantHalf(ir, ir.GetRegister(n)));
|
||||
auto lo_result = ir.UnsignedSaturation(lo_operand, saturate_to);
|
||||
auto hi_result = ir.UnsignedSaturation(hi_operand, saturate_to);
|
||||
const auto saturate_to = static_cast<size_t>(sat_imm);
|
||||
const auto lo_operand = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(ir.GetRegister(n)));
|
||||
const auto hi_operand = ir.SignExtendHalfToWord(MostSignificantHalf(ir, ir.GetRegister(n)));
|
||||
const auto lo_result = ir.UnsignedSaturation(lo_operand, saturate_to);
|
||||
const auto hi_result = ir.UnsignedSaturation(hi_operand, saturate_to);
|
||||
|
||||
ir.SetRegister(d, Pack2x16To1x32(ir, lo_result.result, hi_result.result));
|
||||
ir.OrQFlag(lo_result.overflow);
|
||||
ir.OrQFlag(hi_result.overflow);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Saturated Add/Subtract instructions
|
||||
|
||||
// QADD<c> <Rd>, <Rm>, <Rn>
|
||||
bool ArmTranslatorVisitor::arm_QADD(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
|
||||
// QADD <Rd>, <Rm>, <Rn>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto a = ir.GetRegister(m);
|
||||
auto b = ir.GetRegister(n);
|
||||
auto result = ir.SignedSaturatedAdd(a, b);
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.OrQFlag(result.overflow);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto a = ir.GetRegister(m);
|
||||
const auto b = ir.GetRegister(n);
|
||||
const auto result = ir.SignedSaturatedAdd(a, b);
|
||||
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.OrQFlag(result.overflow);
|
||||
return true;
|
||||
}
|
||||
|
||||
// QSUB<c> <Rd>, <Rm>, <Rn>
|
||||
bool ArmTranslatorVisitor::arm_QSUB(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
|
||||
// QSUB <Rd>, <Rm>, <Rn>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto a = ir.GetRegister(m);
|
||||
auto b = ir.GetRegister(n);
|
||||
auto result = ir.SignedSaturatedSub(a, b);
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.OrQFlag(result.overflow);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto a = ir.GetRegister(m);
|
||||
const auto b = ir.GetRegister(n);
|
||||
const auto result = ir.SignedSaturatedSub(a, b);
|
||||
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.OrQFlag(result.overflow);
|
||||
return true;
|
||||
}
|
||||
|
||||
// QDADD<c> <Rd>, <Rm>, <Rn>
|
||||
bool ArmTranslatorVisitor::arm_QDADD(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
|
||||
// QDADD <Rd>, <Rm>, <Rn>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto a = ir.GetRegister(m);
|
||||
auto b = ir.GetRegister(n);
|
||||
auto doubled = ir.SignedSaturatedAdd(b, b);
|
||||
ir.OrQFlag(doubled.overflow);
|
||||
auto result = ir.SignedSaturatedAdd(a, doubled.result);
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.OrQFlag(result.overflow);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_QDSUB(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
return UnpredictableInstruction();
|
||||
|
||||
// QDSUB <Rd>, <Rm>, <Rn>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto a = ir.GetRegister(m);
|
||||
auto b = ir.GetRegister(n);
|
||||
auto doubled = ir.SignedSaturatedAdd(b, b);
|
||||
const auto a = ir.GetRegister(m);
|
||||
const auto b = ir.GetRegister(n);
|
||||
const auto doubled = ir.SignedSaturatedAdd(b, b);
|
||||
ir.OrQFlag(doubled.overflow);
|
||||
auto result = ir.SignedSaturatedSub(a, doubled.result);
|
||||
|
||||
const auto result = ir.SignedSaturatedAdd(a, doubled.result);
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.OrQFlag(result.overflow);
|
||||
return true;
|
||||
}
|
||||
|
||||
// QDSUB<c> <Rd>, <Rm>, <Rn>
|
||||
bool ArmTranslatorVisitor::arm_QDSUB(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto a = ir.GetRegister(m);
|
||||
const auto b = ir.GetRegister(n);
|
||||
const auto doubled = ir.SignedSaturatedAdd(b, b);
|
||||
ir.OrQFlag(doubled.overflow);
|
||||
|
||||
const auto result = ir.SignedSaturatedSub(a, doubled.result);
|
||||
ir.SetRegister(d, result.result);
|
||||
ir.OrQFlag(result.overflow);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parallel saturated instructions
|
||||
|
||||
// QASX<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_QASX(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
|
||||
// QASX <Rd>, <Rn>, <Rm>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto Rn = ir.GetRegister(n);
|
||||
auto Rm = ir.GetRegister(m);
|
||||
auto Rn_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(Rn));
|
||||
auto Rn_hi = ir.SignExtendHalfToWord(MostSignificantHalf(ir, Rn));
|
||||
auto Rm_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(Rm));
|
||||
auto Rm_hi = ir.SignExtendHalfToWord(MostSignificantHalf(ir, Rm));
|
||||
auto diff = ir.SignedSaturation(ir.Sub(Rn_lo, Rm_hi), 16).result;
|
||||
auto sum = ir.SignedSaturation(ir.Add(Rn_hi, Rm_lo), 16).result;
|
||||
auto result = Pack2x16To1x32(ir, diff, sum);
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// QSAX<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_QSAX(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
|
||||
// QSAX <Rd>, <Rn>, <Rm>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto Rn = ir.GetRegister(n);
|
||||
auto Rm = ir.GetRegister(m);
|
||||
auto Rn_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(Rn));
|
||||
auto Rn_hi = ir.SignExtendHalfToWord(MostSignificantHalf(ir, Rn));
|
||||
auto Rm_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(Rm));
|
||||
auto Rm_hi = ir.SignExtendHalfToWord(MostSignificantHalf(ir, Rm));
|
||||
auto sum = ir.SignedSaturation(ir.Add(Rn_lo, Rm_hi), 16).result;
|
||||
auto diff = ir.SignedSaturation(ir.Sub(Rn_hi, Rm_lo), 16).result;
|
||||
auto result = Pack2x16To1x32(ir, sum, diff);
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// UQASX<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_UQASX(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC)
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
|
||||
// UQASX <Rd>, <Rn>, <Rm>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto Rn = ir.GetRegister(n);
|
||||
auto Rm = ir.GetRegister(m);
|
||||
auto Rn_lo = ir.ZeroExtendHalfToWord(ir.LeastSignificantHalf(Rn));
|
||||
auto Rn_hi = ir.ZeroExtendHalfToWord(MostSignificantHalf(ir, Rn));
|
||||
auto Rm_lo = ir.ZeroExtendHalfToWord(ir.LeastSignificantHalf(Rm));
|
||||
auto Rm_hi = ir.ZeroExtendHalfToWord(MostSignificantHalf(ir, Rm));
|
||||
auto diff = ir.UnsignedSaturation(ir.Sub(Rn_lo, Rm_hi), 16).result;
|
||||
auto sum = ir.UnsignedSaturation(ir.Add(Rn_hi, Rm_lo), 16).result;
|
||||
auto result = Pack2x16To1x32(ir, diff, sum);
|
||||
ir.SetRegister(d, result);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_UQSAX(Cond cond, 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);
|
||||
|
||||
// UQSAX <Rd>, <Rn>, <Rm>
|
||||
if (ConditionPassed(cond)) {
|
||||
auto Rn = ir.GetRegister(n);
|
||||
auto Rm = ir.GetRegister(m);
|
||||
auto Rn_lo = ir.ZeroExtendHalfToWord(ir.LeastSignificantHalf(Rn));
|
||||
auto Rn_hi = ir.ZeroExtendHalfToWord(MostSignificantHalf(ir, Rn));
|
||||
auto Rm_lo = ir.ZeroExtendHalfToWord(ir.LeastSignificantHalf(Rm));
|
||||
auto Rm_hi = ir.ZeroExtendHalfToWord(MostSignificantHalf(ir, Rm));
|
||||
auto sum = ir.UnsignedSaturation(ir.Add(Rn_lo, Rm_hi), 16).result;
|
||||
auto diff = ir.UnsignedSaturation(ir.Sub(Rn_hi, Rm_lo), 16).result;
|
||||
auto result = Pack2x16To1x32(ir, sum, diff);
|
||||
ir.SetRegister(d, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// UQSAX<c> <Rd>, <Rn>, <Rm>
|
||||
bool ArmTranslatorVisitor::arm_UQSAX(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,34 +10,47 @@
|
|||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
// CPS<effect> <iflags>{, #<mode>}
|
||||
// CPS #<mode>
|
||||
bool ArmTranslatorVisitor::arm_CPS() {
|
||||
return InterpretThisInstruction();
|
||||
}
|
||||
|
||||
// MRS<c> <Rd>, <spec_reg>
|
||||
bool ArmTranslatorVisitor::arm_MRS(Cond cond, Reg d) {
|
||||
if (d == Reg::PC)
|
||||
if (d == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
// MRS <Rd>, APSR
|
||||
if (ConditionPassed(cond)) {
|
||||
ir.SetRegister(d, ir.GetCpsr());
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ir.SetRegister(d, ir.GetCpsr());
|
||||
return true;
|
||||
}
|
||||
|
||||
// MSR<c> <spec_reg>, #<const>
|
||||
bool ArmTranslatorVisitor::arm_MSR_imm(Cond cond, int mask, int rotate, Imm8 imm8) {
|
||||
ASSERT_MSG(mask != 0, "Decode error");
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const bool write_nzcvq = Common::Bit<3>(mask);
|
||||
const bool write_g = Common::Bit<2>(mask);
|
||||
const bool write_e = Common::Bit<1>(mask);
|
||||
const u32 imm32 = ArmExpandImm(rotate, imm8);
|
||||
ASSERT_MSG(mask != 0, "Decode error");
|
||||
// MSR <spec_reg>, #<imm32>
|
||||
if (ConditionPassed(cond)) {
|
||||
|
||||
if (write_nzcvq) {
|
||||
ir.SetCpsrNZCVQ(ir.Imm32(imm32 & 0xF8000000));
|
||||
}
|
||||
|
||||
if (write_g) {
|
||||
ir.SetGEFlagsCompressed(ir.Imm32(imm32 & 0x000F0000));
|
||||
}
|
||||
|
||||
if (write_e) {
|
||||
const bool E = (imm32 & 0x00000200) != 0;
|
||||
if (E != ir.current_location.EFlag()) {
|
||||
|
@ -45,25 +58,34 @@ bool ArmTranslatorVisitor::arm_MSR_imm(Cond cond, int mask, int rotate, Imm8 imm
|
|||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// MSR<c> <spec_reg>, <Rn>
|
||||
bool ArmTranslatorVisitor::arm_MSR_reg(Cond cond, int mask, Reg n) {
|
||||
if (mask == 0) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
if (n == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const bool write_nzcvq = Common::Bit<3>(mask);
|
||||
const bool write_g = Common::Bit<2>(mask);
|
||||
const bool write_e = Common::Bit<1>(mask);
|
||||
if (mask == 0)
|
||||
return UnpredictableInstruction();
|
||||
if (n == Reg::PC)
|
||||
return UnpredictableInstruction();
|
||||
// MSR <spec_reg>, #<imm32>
|
||||
if (ConditionPassed(cond)) {
|
||||
const auto value = ir.GetRegister(n);
|
||||
|
||||
if (!write_e) {
|
||||
if (write_nzcvq) {
|
||||
ir.SetCpsrNZCVQ(ir.And(value, ir.Imm32(0xF8000000)));
|
||||
}
|
||||
|
||||
if (write_g) {
|
||||
ir.SetGEFlagsCompressed(ir.And(value, ir.Imm32(0x000F0000)));
|
||||
}
|
||||
|
@ -77,20 +99,22 @@ bool ArmTranslatorVisitor::arm_MSR_reg(Cond cond, int mask, Reg n) {
|
|||
ir.SetTerm(IR::Term::CheckHalt{IR::Term::PopRSBHint{}});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// RFE{<amode>} <Rn>{!}
|
||||
bool ArmTranslatorVisitor::arm_RFE() {
|
||||
return InterpretThisInstruction();
|
||||
}
|
||||
|
||||
// SETEND <endian_specifier>
|
||||
bool ArmTranslatorVisitor::arm_SETEND(bool E) {
|
||||
// SETEND {BE,LE}
|
||||
ir.SetTerm(IR::Term::LinkBlock{ir.current_location.AdvancePC(4).SetEFlag(E)});
|
||||
return false;
|
||||
}
|
||||
|
||||
// SRS{<amode>} SP{!}, #<mode>
|
||||
bool ArmTranslatorVisitor::arm_SRS() {
|
||||
return InterpretThisInstruction();
|
||||
}
|
||||
|
|
|
@ -8,151 +8,200 @@
|
|||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
bool ArmTranslatorVisitor::arm_CLREX() {
|
||||
// CLREX
|
||||
bool ArmTranslatorVisitor::arm_CLREX() {
|
||||
ir.ClearExclusive();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_LDREX(Cond cond, Reg n, Reg d) {
|
||||
if (d == Reg::PC || n == Reg::PC)
|
||||
// LDREX<c> <Rt>, [<Rn>]
|
||||
bool ArmTranslatorVisitor::arm_LDREX(Cond cond, Reg n, Reg t) {
|
||||
if (t == Reg::PC || n == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
// LDREX <Rd>, [<Rn>]
|
||||
if (ConditionPassed(cond)) {
|
||||
auto address = ir.GetRegister(n);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto address = ir.GetRegister(n);
|
||||
ir.SetExclusive(address, 4);
|
||||
ir.SetRegister(d, ir.ReadMemory32(address));
|
||||
}
|
||||
ir.SetRegister(t, ir.ReadMemory32(address));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_LDREXB(Cond cond, Reg n, Reg d) {
|
||||
if (d == Reg::PC || n == Reg::PC)
|
||||
// LDREXB<c> <Rt>, [<Rn>]
|
||||
bool ArmTranslatorVisitor::arm_LDREXB(Cond cond, Reg n, Reg t) {
|
||||
if (t == Reg::PC || n == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
// LDREXB <Rd>, [<Rn>]
|
||||
if (ConditionPassed(cond)) {
|
||||
auto address = ir.GetRegister(n);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto address = ir.GetRegister(n);
|
||||
ir.SetExclusive(address, 1);
|
||||
ir.SetRegister(d, ir.ZeroExtendByteToWord(ir.ReadMemory8(address)));
|
||||
}
|
||||
ir.SetRegister(t, ir.ZeroExtendByteToWord(ir.ReadMemory8(address)));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_LDREXD(Cond cond, Reg n, Reg d) {
|
||||
if (d == Reg::LR || d == Reg::PC || n == Reg::PC)
|
||||
// LDREXD<c> <Rt>, <Rt2>, [<Rn>]
|
||||
bool ArmTranslatorVisitor::arm_LDREXD(Cond cond, Reg n, Reg t) {
|
||||
if (t == Reg::LR || t == Reg::PC || n == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
// LDREXD <Rd>, <Rd1>, [<Rn>]
|
||||
if (ConditionPassed(cond)) {
|
||||
auto address = ir.GetRegister(n);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto address = ir.GetRegister(n);
|
||||
ir.SetExclusive(address, 8);
|
||||
|
||||
// DO NOT SWAP hi AND lo IN BIG ENDIAN MODE, THIS IS CORRECT BEHAVIOUR
|
||||
auto lo = ir.ReadMemory32(address);
|
||||
ir.SetRegister(d, lo);
|
||||
auto hi = ir.ReadMemory32(ir.Add(address, ir.Imm32(4)));
|
||||
ir.SetRegister(d+1, hi);
|
||||
}
|
||||
const auto lo = ir.ReadMemory32(address);
|
||||
ir.SetRegister(t, lo);
|
||||
const auto hi = ir.ReadMemory32(ir.Add(address, ir.Imm32(4)));
|
||||
ir.SetRegister(t+1, hi);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_LDREXH(Cond cond, Reg n, Reg d) {
|
||||
if (d == Reg::PC || n == Reg::PC)
|
||||
// LDREXH<c> <Rt>, [<Rn>]
|
||||
bool ArmTranslatorVisitor::arm_LDREXH(Cond cond, Reg n, Reg t) {
|
||||
if (t == Reg::PC || n == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
// LDREXH <Rd>, [<Rn>]
|
||||
if (ConditionPassed(cond)) {
|
||||
auto address = ir.GetRegister(n);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto address = ir.GetRegister(n);
|
||||
ir.SetExclusive(address, 2);
|
||||
ir.SetRegister(d, ir.ZeroExtendHalfToWord(ir.ReadMemory16(address)));
|
||||
}
|
||||
ir.SetRegister(t, ir.ZeroExtendHalfToWord(ir.ReadMemory16(address)));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_STREX(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (n == Reg::PC || d == Reg::PC || m == Reg::PC)
|
||||
// STREX<c> <Rd>, <Rt>, [<Rn>]
|
||||
bool ArmTranslatorVisitor::arm_STREX(Cond cond, Reg n, Reg d, Reg t) {
|
||||
if (n == Reg::PC || d == Reg::PC || t == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (d == n || d == m)
|
||||
}
|
||||
|
||||
if (d == n || d == t) {
|
||||
return UnpredictableInstruction();
|
||||
// STREX <Rd>, <Rm>, [<Rn>]
|
||||
if (ConditionPassed(cond)) {
|
||||
auto address = ir.GetRegister(n);
|
||||
auto value = ir.GetRegister(m);
|
||||
auto passed = ir.ExclusiveWriteMemory32(address, value);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto address = ir.GetRegister(n);
|
||||
const auto value = ir.GetRegister(t);
|
||||
const auto passed = ir.ExclusiveWriteMemory32(address, value);
|
||||
ir.SetRegister(d, passed);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_STREXB(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (n == Reg::PC || d == Reg::PC || m == Reg::PC)
|
||||
// STREXB<c> <Rd>, <Rt>, [<Rn>]
|
||||
bool ArmTranslatorVisitor::arm_STREXB(Cond cond, Reg n, Reg d, Reg t) {
|
||||
if (n == Reg::PC || d == Reg::PC || t == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (d == n || d == m)
|
||||
}
|
||||
|
||||
if (d == n || d == t) {
|
||||
return UnpredictableInstruction();
|
||||
// STREXB <Rd>, <Rm>, [<Rn>]
|
||||
if (ConditionPassed(cond)) {
|
||||
auto address = ir.GetRegister(n);
|
||||
auto value = ir.LeastSignificantByte(ir.GetRegister(m));
|
||||
auto passed = ir.ExclusiveWriteMemory8(address, value);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto address = ir.GetRegister(n);
|
||||
const auto value = ir.LeastSignificantByte(ir.GetRegister(t));
|
||||
const auto passed = ir.ExclusiveWriteMemory8(address, value);
|
||||
ir.SetRegister(d, passed);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_STREXD(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (n == Reg::PC || d == Reg::PC || m == Reg::LR || static_cast<size_t>(m) % 2 == 1)
|
||||
// STREXD<c> <Rd>, <Rt>, <Rt2>, [<Rn>]
|
||||
bool ArmTranslatorVisitor::arm_STREXD(Cond cond, Reg n, Reg d, Reg t) {
|
||||
if (n == Reg::PC || d == Reg::PC || t == Reg::LR || static_cast<size_t>(t) % 2 == 1) {
|
||||
return UnpredictableInstruction();
|
||||
if (d == n || d == m || d == m+1)
|
||||
}
|
||||
|
||||
if (d == n || d == t || d == t+1) {
|
||||
return UnpredictableInstruction();
|
||||
Reg m2 = m + 1;
|
||||
// STREXD <Rd>, <Rm>, <Rm2>, [<Rn>]
|
||||
if (ConditionPassed(cond)) {
|
||||
auto address = ir.GetRegister(n);
|
||||
auto value_lo = ir.GetRegister(m);
|
||||
auto value_hi = ir.GetRegister(m2);
|
||||
auto passed = ir.ExclusiveWriteMemory64(address, value_lo, value_hi);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const Reg t2 = t + 1;
|
||||
const auto address = ir.GetRegister(n);
|
||||
const auto value_lo = ir.GetRegister(t);
|
||||
const auto value_hi = ir.GetRegister(t2);
|
||||
const auto passed = ir.ExclusiveWriteMemory64(address, value_lo, value_hi);
|
||||
ir.SetRegister(d, passed);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_STREXH(Cond cond, Reg n, Reg d, Reg m) {
|
||||
if (n == Reg::PC || d == Reg::PC || m == Reg::PC)
|
||||
// STREXH<c> <Rd>, <Rt>, [<Rn>]
|
||||
bool ArmTranslatorVisitor::arm_STREXH(Cond cond, Reg n, Reg d, Reg t) {
|
||||
if (n == Reg::PC || d == Reg::PC || t == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
if (d == n || d == m)
|
||||
}
|
||||
|
||||
if (d == n || d == t) {
|
||||
return UnpredictableInstruction();
|
||||
// STREXH <Rd>, <Rm>, [<Rn>]
|
||||
if (ConditionPassed(cond)) {
|
||||
auto address = ir.GetRegister(n);
|
||||
auto value = ir.LeastSignificantHalf(ir.GetRegister(m));
|
||||
auto passed = ir.ExclusiveWriteMemory16(address, value);
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto address = ir.GetRegister(n);
|
||||
const auto value = ir.LeastSignificantHalf(ir.GetRegister(t));
|
||||
const auto passed = ir.ExclusiveWriteMemory16(address, value);
|
||||
ir.SetRegister(d, passed);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_SWP(Cond cond, Reg n, Reg t, Reg t2) {
|
||||
if (t == Reg::PC || t2 == Reg::PC || n == Reg::PC || n == t || n == t2)
|
||||
return UnpredictableInstruction();
|
||||
// SWP<c> <Rt>, <Rt2>, [<Rn>]
|
||||
// TODO: UNDEFINED if current mode is Hypervisor
|
||||
// SWP <Rt>, <Rt2>, [<Rn>]
|
||||
if (ConditionPassed(cond)) {
|
||||
auto data = ir.ReadMemory32(ir.GetRegister(n));
|
||||
bool ArmTranslatorVisitor::arm_SWP(Cond cond, Reg n, Reg t, Reg t2) {
|
||||
if (t == Reg::PC || t2 == Reg::PC || n == Reg::PC || n == t || n == t2) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto data = ir.ReadMemory32(ir.GetRegister(n));
|
||||
ir.WriteMemory32(ir.GetRegister(n), ir.GetRegister(t2));
|
||||
// TODO: Alignment check
|
||||
ir.SetRegister(t, data);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArmTranslatorVisitor::arm_SWPB(Cond cond, Reg n, Reg t, Reg t2) {
|
||||
if (t == Reg::PC || t2 == Reg::PC || n == Reg::PC || n == t || n == t2)
|
||||
return UnpredictableInstruction();
|
||||
// SWPB<c> <Rt>, <Rt2>, [<Rn>]
|
||||
// TODO: UNDEFINED if current mode is Hypervisor
|
||||
// SWPB <Rt>, <Rt2>, [<Rn>]
|
||||
if (ConditionPassed(cond)) {
|
||||
auto data = ir.ReadMemory8(ir.GetRegister(n));
|
||||
bool ArmTranslatorVisitor::arm_SWPB(Cond cond, Reg n, Reg t, Reg t2) {
|
||||
if (t == Reg::PC || t2 == Reg::PC || n == Reg::PC || n == t || n == t2) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
if (!ConditionPassed(cond)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto data = ir.ReadMemory8(ir.GetRegister(n));
|
||||
ir.WriteMemory8(ir.GetRegister(n), ir.LeastSignificantByte(ir.GetRegister(t2)));
|
||||
// TODO: Alignment check
|
||||
ir.SetRegister(t, ir.ZeroExtendByteToWord(data));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -313,16 +313,16 @@ struct ArmTranslatorVisitor final {
|
|||
|
||||
// Synchronization Primitive instructions
|
||||
bool arm_CLREX();
|
||||
bool arm_LDREX(Cond cond, Reg n, Reg d);
|
||||
bool arm_LDREXB(Cond cond, Reg n, Reg d);
|
||||
bool arm_LDREXD(Cond cond, Reg n, Reg d);
|
||||
bool arm_LDREXH(Cond cond, Reg n, Reg d);
|
||||
bool arm_STREX(Cond cond, Reg n, Reg d, Reg m);
|
||||
bool arm_STREXB(Cond cond, Reg n, Reg d, Reg m);
|
||||
bool arm_STREXD(Cond cond, Reg n, Reg d, Reg m);
|
||||
bool arm_STREXH(Cond cond, Reg n, Reg d, Reg m);
|
||||
bool arm_SWP(Cond cond, Reg n, Reg d, Reg m);
|
||||
bool arm_SWPB(Cond cond, Reg n, Reg d, Reg m);
|
||||
bool arm_LDREX(Cond cond, Reg n, Reg t);
|
||||
bool arm_LDREXB(Cond cond, Reg n, Reg t);
|
||||
bool arm_LDREXD(Cond cond, Reg n, Reg t);
|
||||
bool arm_LDREXH(Cond cond, Reg n, Reg t);
|
||||
bool arm_STREX(Cond cond, Reg n, Reg d, Reg t);
|
||||
bool arm_STREXB(Cond cond, Reg n, Reg d, Reg t);
|
||||
bool arm_STREXD(Cond cond, Reg n, Reg d, Reg t);
|
||||
bool arm_STREXH(Cond cond, Reg n, Reg d, Reg t);
|
||||
bool arm_SWP(Cond cond, Reg n, Reg t, Reg t2);
|
||||
bool arm_SWPB(Cond cond, Reg n, Reg t, Reg t2);
|
||||
|
||||
// Status register access instructions
|
||||
bool arm_CPS();
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue