A32: Ensure existing thumb code is ITState-correct

This commit is contained in:
MerryMage 2021-02-07 20:33:20 +00:00
parent 68bd9547c5
commit 97d8b50c25
2 changed files with 179 additions and 78 deletions

View file

@ -12,13 +12,19 @@ namespace Dynarmic::A32 {
// LSLS <Rd>, <Rm>, #<imm5> // LSLS <Rd>, <Rm>, #<imm5>
bool ThumbTranslatorVisitor::thumb16_LSL_imm(Imm<5> imm5, Reg m, Reg d) { bool ThumbTranslatorVisitor::thumb16_LSL_imm(Imm<5> imm5, Reg m, Reg d) {
const u8 shift_n = imm5.ZeroExtend<u8>(); const u8 shift_n = imm5.ZeroExtend<u8>();
if (shift_n == 0 && ir.current_location.IT().IsInITBlock()) {
return UnpredictableInstruction();
}
const auto cpsr_c = ir.GetCFlag(); const auto cpsr_c = ir.GetCFlag();
const auto result = ir.LogicalShiftLeft(ir.GetRegister(m), ir.Imm8(shift_n), cpsr_c); const auto result = ir.LogicalShiftLeft(ir.GetRegister(m), ir.Imm8(shift_n), cpsr_c);
ir.SetRegister(d, result.result); ir.SetRegister(d, result.result);
ir.SetNFlag(ir.MostSignificantBit(result.result)); if (!ir.current_location.IT().IsInITBlock()) {
ir.SetZFlag(ir.IsZero(result.result)); ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetCFlag(result.carry); ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
}
return true; return true;
} }
@ -29,9 +35,11 @@ bool ThumbTranslatorVisitor::thumb16_LSR_imm(Imm<5> imm5, Reg m, Reg d) {
const auto result = ir.LogicalShiftRight(ir.GetRegister(m), ir.Imm8(shift_n), cpsr_c); const auto result = ir.LogicalShiftRight(ir.GetRegister(m), ir.Imm8(shift_n), cpsr_c);
ir.SetRegister(d, result.result); ir.SetRegister(d, result.result);
ir.SetNFlag(ir.MostSignificantBit(result.result)); if (!ir.current_location.IT().IsInITBlock()) {
ir.SetZFlag(ir.IsZero(result.result)); ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetCFlag(result.carry); ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
}
return true; return true;
} }
@ -42,9 +50,11 @@ bool ThumbTranslatorVisitor::thumb16_ASR_imm(Imm<5> imm5, Reg m, Reg d) {
const auto result = ir.ArithmeticShiftRight(ir.GetRegister(m), ir.Imm8(shift_n), cpsr_c); const auto result = ir.ArithmeticShiftRight(ir.GetRegister(m), ir.Imm8(shift_n), cpsr_c);
ir.SetRegister(d, result.result); ir.SetRegister(d, result.result);
ir.SetNFlag(ir.MostSignificantBit(result.result)); if (!ir.current_location.IT().IsInITBlock()) {
ir.SetZFlag(ir.IsZero(result.result)); ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetCFlag(result.carry); ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
}
return true; return true;
} }
@ -52,11 +62,14 @@ bool ThumbTranslatorVisitor::thumb16_ASR_imm(Imm<5> imm5, Reg m, Reg d) {
// Note that it is not possible to encode Rd == R15. // Note that it is not possible to encode Rd == R15.
bool ThumbTranslatorVisitor::thumb16_ADD_reg_t1(Reg m, Reg n, Reg d) { bool ThumbTranslatorVisitor::thumb16_ADD_reg_t1(Reg m, Reg n, Reg d) {
const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.GetRegister(m), ir.Imm1(0)); const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.GetRegister(m), ir.Imm1(0));
ir.SetRegister(d, result.result); ir.SetRegister(d, result.result);
ir.SetNFlag(ir.MostSignificantBit(result.result)); if (!ir.current_location.IT().IsInITBlock()) {
ir.SetZFlag(ir.IsZero(result.result)); ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetCFlag(result.carry); ir.SetZFlag(ir.IsZero(result.result));
ir.SetVFlag(result.overflow); ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true; return true;
} }
@ -64,11 +77,14 @@ bool ThumbTranslatorVisitor::thumb16_ADD_reg_t1(Reg m, Reg n, Reg d) {
// Note that it is not possible to encode Rd == R15. // Note that it is not possible to encode Rd == R15.
bool ThumbTranslatorVisitor::thumb16_SUB_reg(Reg m, Reg n, Reg d) { bool ThumbTranslatorVisitor::thumb16_SUB_reg(Reg m, Reg n, Reg d) {
const auto result = ir.SubWithCarry(ir.GetRegister(n), ir.GetRegister(m), ir.Imm1(1)); const auto result = ir.SubWithCarry(ir.GetRegister(n), ir.GetRegister(m), ir.Imm1(1));
ir.SetRegister(d, result.result); ir.SetRegister(d, result.result);
ir.SetNFlag(ir.MostSignificantBit(result.result)); if (!ir.current_location.IT().IsInITBlock()) {
ir.SetZFlag(ir.IsZero(result.result)); ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetCFlag(result.carry); ir.SetZFlag(ir.IsZero(result.result));
ir.SetVFlag(result.overflow); ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true; return true;
} }
@ -79,10 +95,12 @@ bool ThumbTranslatorVisitor::thumb16_ADD_imm_t1(Imm<3> imm3, Reg n, Reg d) {
const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(0)); const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(0));
ir.SetRegister(d, result.result); ir.SetRegister(d, result.result);
ir.SetNFlag(ir.MostSignificantBit(result.result)); if (!ir.current_location.IT().IsInITBlock()) {
ir.SetZFlag(ir.IsZero(result.result)); ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetCFlag(result.carry); ir.SetZFlag(ir.IsZero(result.result));
ir.SetVFlag(result.overflow); ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true; return true;
} }
@ -93,10 +111,12 @@ bool ThumbTranslatorVisitor::thumb16_SUB_imm_t1(Imm<3> imm3, Reg n, Reg d) {
const auto result = ir.SubWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(1)); const auto result = ir.SubWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(1));
ir.SetRegister(d, result.result); ir.SetRegister(d, result.result);
ir.SetNFlag(ir.MostSignificantBit(result.result)); if (!ir.current_location.IT().IsInITBlock()) {
ir.SetZFlag(ir.IsZero(result.result)); ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetCFlag(result.carry); ir.SetZFlag(ir.IsZero(result.result));
ir.SetVFlag(result.overflow); ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true; return true;
} }
@ -107,8 +127,10 @@ bool ThumbTranslatorVisitor::thumb16_MOV_imm(Reg d, Imm<8> imm8) {
const auto result = ir.Imm32(imm32); const auto result = ir.Imm32(imm32);
ir.SetRegister(d, result); ir.SetRegister(d, result);
ir.SetNFlag(ir.MostSignificantBit(result)); if (!ir.current_location.IT().IsInITBlock()) {
ir.SetZFlag(ir.IsZero(result)); ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
}
return true; return true;
} }
@ -133,10 +155,12 @@ bool ThumbTranslatorVisitor::thumb16_ADD_imm_t2(Reg d_n, Imm<8> imm8) {
const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(0)); const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(0));
ir.SetRegister(d, result.result); ir.SetRegister(d, result.result);
ir.SetNFlag(ir.MostSignificantBit(result.result)); if (!ir.current_location.IT().IsInITBlock()) {
ir.SetZFlag(ir.IsZero(result.result)); ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetCFlag(result.carry); ir.SetZFlag(ir.IsZero(result.result));
ir.SetVFlag(result.overflow); ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true; return true;
} }
@ -149,10 +173,12 @@ bool ThumbTranslatorVisitor::thumb16_SUB_imm_t2(Reg d_n, Imm<8> imm8) {
const auto result = ir.SubWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(1)); const auto result = ir.SubWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(1));
ir.SetRegister(d, result.result); ir.SetRegister(d, result.result);
ir.SetNFlag(ir.MostSignificantBit(result.result)); if (!ir.current_location.IT().IsInITBlock()) {
ir.SetZFlag(ir.IsZero(result.result)); ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetCFlag(result.carry); ir.SetZFlag(ir.IsZero(result.result));
ir.SetVFlag(result.overflow); ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true; return true;
} }
@ -164,8 +190,10 @@ bool ThumbTranslatorVisitor::thumb16_AND_reg(Reg m, Reg d_n) {
const auto result = ir.And(ir.GetRegister(n), ir.GetRegister(m)); const auto result = ir.And(ir.GetRegister(n), ir.GetRegister(m));
ir.SetRegister(d, result); ir.SetRegister(d, result);
ir.SetNFlag(ir.MostSignificantBit(result)); if (!ir.current_location.IT().IsInITBlock()) {
ir.SetZFlag(ir.IsZero(result)); ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
}
return true; return true;
} }
@ -177,8 +205,10 @@ bool ThumbTranslatorVisitor::thumb16_EOR_reg(Reg m, Reg d_n) {
const auto result = ir.Eor(ir.GetRegister(n), ir.GetRegister(m)); const auto result = ir.Eor(ir.GetRegister(n), ir.GetRegister(m));
ir.SetRegister(d, result); ir.SetRegister(d, result);
ir.SetNFlag(ir.MostSignificantBit(result)); if (!ir.current_location.IT().IsInITBlock()) {
ir.SetZFlag(ir.IsZero(result)); ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
}
return true; return true;
} }
@ -191,9 +221,11 @@ bool ThumbTranslatorVisitor::thumb16_LSL_reg(Reg m, Reg d_n) {
const auto result_carry = ir.LogicalShiftLeft(ir.GetRegister(n), shift_n, apsr_c); const auto result_carry = ir.LogicalShiftLeft(ir.GetRegister(n), shift_n, apsr_c);
ir.SetRegister(d, result_carry.result); ir.SetRegister(d, result_carry.result);
ir.SetNFlag(ir.MostSignificantBit(result_carry.result)); if (!ir.current_location.IT().IsInITBlock()) {
ir.SetZFlag(ir.IsZero(result_carry.result)); ir.SetNFlag(ir.MostSignificantBit(result_carry.result));
ir.SetCFlag(result_carry.carry); ir.SetZFlag(ir.IsZero(result_carry.result));
ir.SetCFlag(result_carry.carry);
}
return true; return true;
} }
@ -206,9 +238,11 @@ bool ThumbTranslatorVisitor::thumb16_LSR_reg(Reg m, Reg d_n) {
const auto result = ir.LogicalShiftRight(ir.GetRegister(n), shift_n, cpsr_c); const auto result = ir.LogicalShiftRight(ir.GetRegister(n), shift_n, cpsr_c);
ir.SetRegister(d, result.result); ir.SetRegister(d, result.result);
ir.SetNFlag(ir.MostSignificantBit(result.result)); if (!ir.current_location.IT().IsInITBlock()) {
ir.SetZFlag(ir.IsZero(result.result)); ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetCFlag(result.carry); ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
}
return true; return true;
} }
@ -221,9 +255,11 @@ bool ThumbTranslatorVisitor::thumb16_ASR_reg(Reg m, Reg d_n) {
const auto result = ir.ArithmeticShiftRight(ir.GetRegister(n), shift_n, cpsr_c); const auto result = ir.ArithmeticShiftRight(ir.GetRegister(n), shift_n, cpsr_c);
ir.SetRegister(d, result.result); ir.SetRegister(d, result.result);
ir.SetNFlag(ir.MostSignificantBit(result.result)); if (!ir.current_location.IT().IsInITBlock()) {
ir.SetZFlag(ir.IsZero(result.result)); ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetCFlag(result.carry); ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
}
return true; return true;
} }
@ -236,10 +272,12 @@ bool ThumbTranslatorVisitor::thumb16_ADC_reg(Reg m, Reg d_n) {
const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.GetRegister(m), aspr_c); const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.GetRegister(m), aspr_c);
ir.SetRegister(d, result.result); ir.SetRegister(d, result.result);
ir.SetNFlag(ir.MostSignificantBit(result.result)); if (!ir.current_location.IT().IsInITBlock()) {
ir.SetZFlag(ir.IsZero(result.result)); ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetCFlag(result.carry); ir.SetZFlag(ir.IsZero(result.result));
ir.SetVFlag(result.overflow); ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true; return true;
} }
@ -252,10 +290,12 @@ bool ThumbTranslatorVisitor::thumb16_SBC_reg(Reg m, Reg d_n) {
const auto result = ir.SubWithCarry(ir.GetRegister(n), ir.GetRegister(m), aspr_c); const auto result = ir.SubWithCarry(ir.GetRegister(n), ir.GetRegister(m), aspr_c);
ir.SetRegister(d, result.result); ir.SetRegister(d, result.result);
ir.SetNFlag(ir.MostSignificantBit(result.result)); if (!ir.current_location.IT().IsInITBlock()) {
ir.SetZFlag(ir.IsZero(result.result)); ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetCFlag(result.carry); ir.SetZFlag(ir.IsZero(result.result));
ir.SetVFlag(result.overflow); ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true; return true;
} }
@ -268,9 +308,11 @@ bool ThumbTranslatorVisitor::thumb16_ROR_reg(Reg m, Reg d_n) {
const auto result = ir.RotateRight(ir.GetRegister(n), shift_n, cpsr_c); const auto result = ir.RotateRight(ir.GetRegister(n), shift_n, cpsr_c);
ir.SetRegister(d, result.result); ir.SetRegister(d, result.result);
ir.SetNFlag(ir.MostSignificantBit(result.result)); if (!ir.current_location.IT().IsInITBlock()) {
ir.SetZFlag(ir.IsZero(result.result)); ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetCFlag(result.carry); ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
}
return true; return true;
} }
@ -287,10 +329,12 @@ bool ThumbTranslatorVisitor::thumb16_TST_reg(Reg m, Reg n) {
bool ThumbTranslatorVisitor::thumb16_RSB_imm(Reg n, Reg d) { bool ThumbTranslatorVisitor::thumb16_RSB_imm(Reg n, Reg d) {
const auto result = ir.SubWithCarry(ir.Imm32(0), ir.GetRegister(n), ir.Imm1(1)); const auto result = ir.SubWithCarry(ir.Imm32(0), ir.GetRegister(n), ir.Imm1(1));
ir.SetRegister(d, result.result); ir.SetRegister(d, result.result);
ir.SetNFlag(ir.MostSignificantBit(result.result)); if (!ir.current_location.IT().IsInITBlock()) {
ir.SetZFlag(ir.IsZero(result.result)); ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetCFlag(result.carry); ir.SetZFlag(ir.IsZero(result.result));
ir.SetVFlag(result.overflow); ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true; return true;
} }
@ -322,8 +366,10 @@ bool ThumbTranslatorVisitor::thumb16_ORR_reg(Reg m, Reg d_n) {
const auto result = ir.Or(ir.GetRegister(m), ir.GetRegister(n)); const auto result = ir.Or(ir.GetRegister(m), ir.GetRegister(n));
ir.SetRegister(d, result); ir.SetRegister(d, result);
ir.SetNFlag(ir.MostSignificantBit(result)); if (!ir.current_location.IT().IsInITBlock()) {
ir.SetZFlag(ir.IsZero(result)); ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
}
return true; return true;
} }
@ -335,8 +381,10 @@ bool ThumbTranslatorVisitor::thumb16_MUL_reg(Reg n, Reg d_m) {
const auto result = ir.Mul(ir.GetRegister(m), ir.GetRegister(n)); const auto result = ir.Mul(ir.GetRegister(m), ir.GetRegister(n));
ir.SetRegister(d, result); ir.SetRegister(d, result);
ir.SetNFlag(ir.MostSignificantBit(result)); if (!ir.current_location.IT().IsInITBlock()) {
ir.SetZFlag(ir.IsZero(result)); ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
}
return true; return true;
} }
@ -348,8 +396,10 @@ bool ThumbTranslatorVisitor::thumb16_BIC_reg(Reg m, Reg d_n) {
const auto result = ir.And(ir.GetRegister(n), ir.Not(ir.GetRegister(m))); const auto result = ir.And(ir.GetRegister(n), ir.Not(ir.GetRegister(m)));
ir.SetRegister(d, result); ir.SetRegister(d, result);
ir.SetNFlag(ir.MostSignificantBit(result)); if (!ir.current_location.IT().IsInITBlock()) {
ir.SetZFlag(ir.IsZero(result)); ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
}
return true; return true;
} }
@ -357,9 +407,12 @@ bool ThumbTranslatorVisitor::thumb16_BIC_reg(Reg m, Reg d_n) {
// Rd cannot encode R15. // Rd cannot encode R15.
bool ThumbTranslatorVisitor::thumb16_MVN_reg(Reg m, Reg d) { bool ThumbTranslatorVisitor::thumb16_MVN_reg(Reg m, Reg d) {
const auto result = ir.Not(ir.GetRegister(m)); const auto result = ir.Not(ir.GetRegister(m));
ir.SetRegister(d, result); ir.SetRegister(d, result);
ir.SetNFlag(ir.MostSignificantBit(result)); if (!ir.current_location.IT().IsInITBlock()) {
ir.SetZFlag(ir.IsZero(result)); ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
}
return true; return true;
} }
@ -367,13 +420,17 @@ bool ThumbTranslatorVisitor::thumb16_MVN_reg(Reg m, Reg d) {
bool ThumbTranslatorVisitor::thumb16_ADD_reg_t2(bool d_n_hi, Reg m, Reg d_n_lo) { bool ThumbTranslatorVisitor::thumb16_ADD_reg_t2(bool d_n_hi, Reg m, Reg d_n_lo) {
const Reg d_n = d_n_hi ? (d_n_lo + 8) : d_n_lo; const Reg d_n = d_n_hi ? (d_n_lo + 8) : d_n_lo;
const Reg n = d_n; const Reg n = d_n;
const Reg d = d_n;
if (n == Reg::PC && m == Reg::PC) { if (n == Reg::PC && m == Reg::PC) {
return UnpredictableInstruction(); return UnpredictableInstruction();
} }
if (d == Reg::PC && ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock()) {
return UnpredictableInstruction();
}
const Reg d = d_n;
const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.GetRegister(m), ir.Imm1(0)); const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.GetRegister(m), ir.Imm1(0));
if (d == Reg::PC) { if (d == Reg::PC) {
ir.UpdateUpperLocationDescriptor();
ir.ALUWritePC(result.result); ir.ALUWritePC(result.result);
// Return to dispatch as we can't predict what PC is going to be. Stop compilation. // Return to dispatch as we can't predict what PC is going to be. Stop compilation.
ir.SetTerm(IR::Term::FastDispatchHint{}); ir.SetTerm(IR::Term::FastDispatchHint{});
@ -405,9 +462,14 @@ bool ThumbTranslatorVisitor::thumb16_CMP_reg_t2(bool n_hi, Reg m, Reg n_lo) {
// MOV <Rd>, <Rm> // MOV <Rd>, <Rm>
bool ThumbTranslatorVisitor::thumb16_MOV_reg(bool d_hi, Reg m, Reg d_lo) { bool ThumbTranslatorVisitor::thumb16_MOV_reg(bool d_hi, Reg m, Reg d_lo) {
const Reg d = d_hi ? (d_lo + 8) : d_lo; const Reg d = d_hi ? (d_lo + 8) : d_lo;
if (d == Reg::PC && ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock()) {
return UnpredictableInstruction();
}
const auto result = ir.GetRegister(m); const auto result = ir.GetRegister(m);
if (d == Reg::PC) { if (d == Reg::PC) {
ir.UpdateUpperLocationDescriptor();
ir.ALUWritePC(result); ir.ALUWritePC(result);
ir.SetTerm(IR::Term::FastDispatchHint{}); ir.SetTerm(IR::Term::FastDispatchHint{});
return false; return false;
@ -761,6 +823,7 @@ bool ThumbTranslatorVisitor::thumb16_POP(bool P, RegList reg_list) {
if (Common::Bit<15>(reg_list)) { if (Common::Bit<15>(reg_list)) {
// TODO(optimization): Possible location for an RSB pop. // TODO(optimization): Possible location for an RSB pop.
const auto data = ir.ReadMemory32(address); const auto data = ir.ReadMemory32(address);
ir.UpdateUpperLocationDescriptor();
ir.LoadWritePC(data); ir.LoadWritePC(data);
address = ir.Add(address, ir.Imm32(4)); address = ir.Add(address, ir.Imm32(4));
ir.SetRegister(Reg::SP, address); ir.SetRegister(Reg::SP, address);
@ -774,6 +837,10 @@ bool ThumbTranslatorVisitor::thumb16_POP(bool P, RegList reg_list) {
// SETEND <endianness> // SETEND <endianness>
bool ThumbTranslatorVisitor::thumb16_SETEND(bool E) { bool ThumbTranslatorVisitor::thumb16_SETEND(bool E) {
if (ir.current_location.IT().IsInITBlock()) {
return UnpredictableInstruction();
}
if (E == ir.current_location.EFlag()) { if (E == ir.current_location.EFlag()) {
return true; return true;
} }
@ -822,6 +889,8 @@ bool ThumbTranslatorVisitor::thumb16_REVSH(Reg m, Reg d) {
// BKPT #<imm8> // BKPT #<imm8>
bool ThumbTranslatorVisitor::thumb16_BKPT([[maybe_unused]] Imm<8> imm8) { bool ThumbTranslatorVisitor::thumb16_BKPT([[maybe_unused]] Imm<8> imm8) {
ir.ExceptionRaised(Exception::Breakpoint); ir.ExceptionRaised(Exception::Breakpoint);
ir.UpdateUpperLocationDescriptor();
ir.LoadWritePC(ir.Imm32(ir.current_location.PC()));
ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}}); ir.SetTerm(IR::Term::CheckHalt{IR::Term::ReturnToDispatch{}});
return false; return false;
} }
@ -873,6 +942,10 @@ bool ThumbTranslatorVisitor::thumb16_LDMIA(Reg n, RegList reg_list) {
// CB{N}Z <Rn>, <label> // CB{N}Z <Rn>, <label>
bool ThumbTranslatorVisitor::thumb16_CBZ_CBNZ(bool nonzero, Imm<1> i, Imm<5> imm5, Reg n) { bool ThumbTranslatorVisitor::thumb16_CBZ_CBNZ(bool nonzero, Imm<1> i, Imm<5> imm5, Reg n) {
if (ir.current_location.IT().IsInITBlock()) {
return UnpredictableInstruction();
}
const u32 imm = concatenate(i, imm5, Imm<1>{0}).ZeroExtend(); const u32 imm = concatenate(i, imm5, Imm<1>{0}).ZeroExtend();
const IR::U32 rn = ir.GetRegister(n); const IR::U32 rn = ir.GetRegister(n);
@ -889,7 +962,7 @@ bool ThumbTranslatorVisitor::thumb16_CBZ_CBNZ(bool nonzero, Imm<1> i, Imm<5> imm
} }
}(); }();
ir.SetTerm(IR::Term::CheckBit{cond_pass, cond_fail}); ir.SetTerm(IR::Term::CheckBit{cond_pass, cond_fail});
return false; return false;
} }
@ -899,6 +972,11 @@ bool ThumbTranslatorVisitor::thumb16_UDF() {
// BX <Rm> // BX <Rm>
bool ThumbTranslatorVisitor::thumb16_BX(Reg m) { bool ThumbTranslatorVisitor::thumb16_BX(Reg m) {
if (ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock()) {
return UnpredictableInstruction();
}
ir.UpdateUpperLocationDescriptor();
ir.BXWritePC(ir.GetRegister(m)); ir.BXWritePC(ir.GetRegister(m));
if (m == Reg::R14) if (m == Reg::R14)
ir.SetTerm(IR::Term::PopRSBHint{}); ir.SetTerm(IR::Term::PopRSBHint{});
@ -909,7 +987,12 @@ bool ThumbTranslatorVisitor::thumb16_BX(Reg m) {
// BLX <Rm> // BLX <Rm>
bool ThumbTranslatorVisitor::thumb16_BLX_reg(Reg m) { bool ThumbTranslatorVisitor::thumb16_BLX_reg(Reg m) {
if (ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock()) {
return UnpredictableInstruction();
}
ir.PushRSB(ir.current_location.AdvancePC(2)); ir.PushRSB(ir.current_location.AdvancePC(2));
ir.UpdateUpperLocationDescriptor();
ir.BXWritePC(ir.GetRegister(m)); ir.BXWritePC(ir.GetRegister(m));
ir.SetRegister(Reg::LR, ir.Imm32((ir.current_location.PC() + 2) | 1)); ir.SetRegister(Reg::LR, ir.Imm32((ir.current_location.PC() + 2) | 1));
ir.SetTerm(IR::Term::FastDispatchHint{}); ir.SetTerm(IR::Term::FastDispatchHint{});
@ -919,6 +1002,7 @@ bool ThumbTranslatorVisitor::thumb16_BLX_reg(Reg m) {
// SVC #<imm8> // SVC #<imm8>
bool ThumbTranslatorVisitor::thumb16_SVC(Imm<8> imm8) { bool ThumbTranslatorVisitor::thumb16_SVC(Imm<8> imm8) {
const u32 imm32 = imm8.ZeroExtend(); const u32 imm32 = imm8.ZeroExtend();
ir.UpdateUpperLocationDescriptor();
ir.BranchWritePC(ir.Imm32(ir.current_location.PC() + 2)); ir.BranchWritePC(ir.Imm32(ir.current_location.PC() + 2));
ir.PushRSB(ir.current_location.AdvancePC(2)); ir.PushRSB(ir.current_location.AdvancePC(2));
ir.CallSupervisor(ir.Imm32(imm32)); ir.CallSupervisor(ir.Imm32(imm32));
@ -928,13 +1012,17 @@ bool ThumbTranslatorVisitor::thumb16_SVC(Imm<8> imm8) {
// B<cond> <label> // B<cond> <label>
bool ThumbTranslatorVisitor::thumb16_B_t1(Cond cond, Imm<8> imm8) { bool ThumbTranslatorVisitor::thumb16_B_t1(Cond cond, Imm<8> imm8) {
if (ir.current_location.IT().IsInITBlock()) {
return UnpredictableInstruction();
}
if (cond == Cond::AL) { if (cond == Cond::AL) {
return thumb16_UDF(); return thumb16_UDF();
} }
const s32 imm32 = static_cast<s32>((imm8.SignExtend<u32>() << 1) + 4); const s32 imm32 = static_cast<s32>((imm8.SignExtend<u32>() << 1) + 4);
const auto then_location = ir.current_location.AdvancePC(imm32); const auto then_location = ir.current_location.AdvancePC(imm32).AdvanceIT();
const auto else_location = ir.current_location.AdvancePC(2); const auto else_location = ir.current_location.AdvancePC(2).AdvanceIT();
ir.SetTerm(IR::Term::If{cond, IR::Term::LinkBlock{then_location}, IR::Term::LinkBlock{else_location}}); ir.SetTerm(IR::Term::If{cond, IR::Term::LinkBlock{then_location}, IR::Term::LinkBlock{else_location}});
return false; return false;
@ -942,8 +1030,12 @@ bool ThumbTranslatorVisitor::thumb16_B_t1(Cond cond, Imm<8> imm8) {
// B <label> // B <label>
bool ThumbTranslatorVisitor::thumb16_B_t2(Imm<11> imm11) { bool ThumbTranslatorVisitor::thumb16_B_t2(Imm<11> imm11) {
if (ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock()) {
return UnpredictableInstruction();
}
const s32 imm32 = static_cast<s32>((imm11.SignExtend<u32>() << 1) + 4); const s32 imm32 = static_cast<s32>((imm11.SignExtend<u32>() << 1) + 4);
const auto next_location = ir.current_location.AdvancePC(imm32); const auto next_location = ir.current_location.AdvancePC(imm32).AdvanceIT();
ir.SetTerm(IR::Term::LinkBlock{next_location}); ir.SetTerm(IR::Term::LinkBlock{next_location});
return false; return false;

View file

@ -9,17 +9,25 @@ namespace Dynarmic::A32 {
// BL <label> // BL <label>
bool ThumbTranslatorVisitor::thumb32_BL_imm(Imm<11> hi, Imm<11> lo) { bool ThumbTranslatorVisitor::thumb32_BL_imm(Imm<11> hi, Imm<11> lo) {
if (ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock()) {
return UnpredictableInstruction();
}
ir.PushRSB(ir.current_location.AdvancePC(4)); ir.PushRSB(ir.current_location.AdvancePC(4));
ir.SetRegister(Reg::LR, ir.Imm32((ir.current_location.PC() + 4) | 1)); ir.SetRegister(Reg::LR, ir.Imm32((ir.current_location.PC() + 4) | 1));
const s32 imm32 = static_cast<s32>((concatenate(hi, lo).SignExtend<u32>() << 1) + 4); const s32 imm32 = static_cast<s32>((concatenate(hi, lo).SignExtend<u32>() << 1) + 4);
const auto new_location = ir.current_location.AdvancePC(imm32); const auto new_location = ir.current_location.AdvancePC(imm32).AdvanceIT();
ir.SetTerm(IR::Term::LinkBlock{new_location}); ir.SetTerm(IR::Term::LinkBlock{new_location});
return false; return false;
} }
// BLX <label> // BLX <label>
bool ThumbTranslatorVisitor::thumb32_BLX_imm(Imm<11> hi, Imm<11> lo) { bool ThumbTranslatorVisitor::thumb32_BLX_imm(Imm<11> hi, Imm<11> lo) {
if (ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock()) {
return UnpredictableInstruction();
}
if (lo.Bit<0>()) { if (lo.Bit<0>()) {
return UnpredictableInstruction(); return UnpredictableInstruction();
} }
@ -30,7 +38,8 @@ bool ThumbTranslatorVisitor::thumb32_BLX_imm(Imm<11> hi, Imm<11> lo) {
const s32 imm32 = static_cast<s32>(concatenate(hi, lo).SignExtend<u32>() << 1); const s32 imm32 = static_cast<s32>(concatenate(hi, lo).SignExtend<u32>() << 1);
const auto new_location = ir.current_location const auto new_location = ir.current_location
.SetPC(ir.AlignPC(4) + imm32) .SetPC(ir.AlignPC(4) + imm32)
.SetTFlag(false); .SetTFlag(false)
.AdvanceIT();
ir.SetTerm(IR::Term::LinkBlock{new_location}); ir.SetTerm(IR::Term::LinkBlock{new_location});
return false; return false;
} }