Implement data processing instructions

ADC, ADD, AND, BIC, CMN, CMP, EOR, MOV, MVN, ORR, RSB, RSC, SBC, SUB,
TEQ, TST

The code could use some serious deduplication...
This commit is contained in:
Tillmann Karras 2016-08-03 00:44:35 +01:00
parent fe71cc9d78
commit 30a90295b9
4 changed files with 870 additions and 92 deletions

View file

@ -89,53 +89,53 @@ boost::optional<const ArmMatcher<V>&> DecodeArm(u32 instruction) {
// Data Processing instructions
INST(&V::arm_ADC_imm, "ADC (imm)", "cccc0010101Snnnnddddrrrrvvvvvvvv"), // all
//INST(&V::arm_ADC_reg, "ADC (reg)", "cccc0000101Snnnnddddvvvvvrr0mmmm"), // all
//INST(&V::arm_ADC_rsr, "ADC (rsr)", "cccc0000101Snnnnddddssss0rr1mmmm"), // all
//INST(&V::arm_ADD_imm, "ADD (imm)", "cccc0010100Snnnnddddrrrrvvvvvvvv"), // all
//INST(&V::arm_ADD_reg, "ADD (reg)", "cccc0000100Snnnnddddvvvvvrr0mmmm"), // all
//INST(&V::arm_ADD_rsr, "ADD (rsr)", "cccc0000100Snnnnddddssss0rr1mmmm"), // all
//INST(&V::arm_AND_imm, "AND (imm)", "cccc0010000Snnnnddddrrrrvvvvvvvv"), // all
//INST(&V::arm_AND_reg, "AND (reg)", "cccc0000000Snnnnddddvvvvvrr0mmmm"), // all
//INST(&V::arm_AND_rsr, "AND (rsr)", "cccc0000000Snnnnddddssss0rr1mmmm"), // all
//INST(&V::arm_BIC_imm, "BIC (imm)", "cccc0011110Snnnnddddrrrrvvvvvvvv"), // all
//INST(&V::arm_BIC_reg, "BIC (reg)", "cccc0001110Snnnnddddvvvvvrr0mmmm"), // all
//INST(&V::arm_BIC_rsr, "BIC (rsr)", "cccc0001110Snnnnddddssss0rr1mmmm"), // all
//INST(&V::arm_CMN_imm, "CMN (imm)", "cccc00110111nnnn0000rrrrvvvvvvvv"), // all
//INST(&V::arm_CMN_reg, "CMN (reg)", "cccc00010111nnnn0000vvvvvrr0mmmm"), // all
//INST(&V::arm_CMN_rsr, "CMN (rsr)", "cccc00010111nnnn0000ssss0rr1mmmm"), // all
INST(&V::arm_ADC_reg, "ADC (reg)", "cccc0000101Snnnnddddvvvvvrr0mmmm"), // all
INST(&V::arm_ADC_rsr, "ADC (rsr)", "cccc0000101Snnnnddddssss0rr1mmmm"), // all
INST(&V::arm_ADD_imm, "ADD (imm)", "cccc0010100Snnnnddddrrrrvvvvvvvv"), // all
INST(&V::arm_ADD_reg, "ADD (reg)", "cccc0000100Snnnnddddvvvvvrr0mmmm"), // all
INST(&V::arm_ADD_rsr, "ADD (rsr)", "cccc0000100Snnnnddddssss0rr1mmmm"), // all
INST(&V::arm_AND_imm, "AND (imm)", "cccc0010000Snnnnddddrrrrvvvvvvvv"), // all
INST(&V::arm_AND_reg, "AND (reg)", "cccc0000000Snnnnddddvvvvvrr0mmmm"), // all
INST(&V::arm_AND_rsr, "AND (rsr)", "cccc0000000Snnnnddddssss0rr1mmmm"), // all
INST(&V::arm_BIC_imm, "BIC (imm)", "cccc0011110Snnnnddddrrrrvvvvvvvv"), // all
INST(&V::arm_BIC_reg, "BIC (reg)", "cccc0001110Snnnnddddvvvvvrr0mmmm"), // all
INST(&V::arm_BIC_rsr, "BIC (rsr)", "cccc0001110Snnnnddddssss0rr1mmmm"), // all
INST(&V::arm_CMN_imm, "CMN (imm)", "cccc00110111nnnn0000rrrrvvvvvvvv"), // all
INST(&V::arm_CMN_reg, "CMN (reg)", "cccc00010111nnnn0000vvvvvrr0mmmm"), // all
INST(&V::arm_CMN_rsr, "CMN (rsr)", "cccc00010111nnnn0000ssss0rr1mmmm"), // all
INST(&V::arm_CMP_imm, "CMP (imm)", "cccc00110101nnnn0000rrrrvvvvvvvv"), // all
//INST(&V::arm_CMP_reg, "CMP (reg)", "cccc00010101nnnn0000vvvvvrr0mmmm"), // all
//INST(&V::arm_CMP_rsr, "CMP (rsr)", "cccc00010101nnnn0000ssss0rr1mmmm"), // all
//INST(&V::arm_EOR_imm, "EOR (imm)", "cccc0010001Snnnnddddrrrrvvvvvvvv"), // all
//INST(&V::arm_EOR_reg, "EOR (reg)", "cccc0000001Snnnnddddvvvvvrr0mmmm"), // all
//INST(&V::arm_EOR_rsr, "EOR (rsr)", "cccc0000001Snnnnddddssss0rr1mmmm"), // all
//INST(&V::arm_MOV_imm, "MOV (imm)", "cccc0011101S0000ddddrrrrvvvvvvvv"), // all
//INST(&V::arm_MOV_reg, "MOV (reg)", "cccc0001101S0000ddddvvvvvrr0mmmm"), // all
//INST(&V::arm_MOV_rsr, "MOV (rsr)", "cccc0001101S0000ddddssss0rr1mmmm"), // all
//INST(&V::arm_MVN_imm, "MVN (imm)", "cccc0011111S0000ddddrrrrvvvvvvvv"), // all
//INST(&V::arm_MVN_reg, "MVN (reg)", "cccc0001111S0000ddddvvvvvrr0mmmm"), // all
//INST(&V::arm_MVN_rsr, "MVN (rsr)", "cccc0001111S0000ddddssss0rr1mmmm"), // all
//INST(&V::arm_ORR_imm, "ORR (imm)", "cccc0011100Snnnnddddrrrrvvvvvvvv"), // all
//INST(&V::arm_ORR_reg, "ORR (reg)", "cccc0001100Snnnnddddvvvvvrr0mmmm"), // all
//INST(&V::arm_ORR_rsr, "ORR (rsr)", "cccc0001100Snnnnddddssss0rr1mmmm"), // all
//INST(&V::arm_RSB_imm, "RSB (imm)", "cccc0010011Snnnnddddrrrrvvvvvvvv"), // all
//INST(&V::arm_RSB_reg, "RSB (reg)", "cccc0000011Snnnnddddvvvvvrr0mmmm"), // all
//INST(&V::arm_RSB_rsr, "RSB (rsr)", "cccc0000011Snnnnddddssss0rr1mmmm"), // all
//INST(&V::arm_RSC_imm, "RSC (imm)", "cccc0010111Snnnnddddrrrrvvvvvvvv"), // all
//INST(&V::arm_RSC_reg, "RSC (reg)", "cccc0000111Snnnnddddvvvvvrr0mmmm"), // all
//INST(&V::arm_RSC_rsr, "RSC (rsr)", "cccc0000111Snnnnddddssss0rr1mmmm"), // all
//INST(&V::arm_SBC_imm, "SBC (imm)", "cccc0010110Snnnnddddrrrrvvvvvvvv"), // all
//INST(&V::arm_SBC_reg, "SBC (reg)", "cccc0000110Snnnnddddvvvvvrr0mmmm"), // all
//INST(&V::arm_SBC_rsr, "SBC (rsr)", "cccc0000110Snnnnddddssss0rr1mmmm"), // all
//INST(&V::arm_SUB_imm, "SUB (imm)", "cccc0010010Snnnnddddrrrrvvvvvvvv"), // all
//INST(&V::arm_SUB_reg, "SUB (reg)", "cccc0000010Snnnnddddvvvvvrr0mmmm"), // all
//INST(&V::arm_SUB_rsr, "SUB (rsr)", "cccc0000010Snnnnddddssss0rr1mmmm"), // all
//INST(&V::arm_TEQ_imm, "TEQ (imm)", "cccc00110011nnnn0000rrrrvvvvvvvv"), // all
//INST(&V::arm_TEQ_reg, "TEQ (reg)", "cccc00010011nnnn0000vvvvvrr0mmmm"), // all
//INST(&V::arm_TEQ_rsr, "TEQ (rsr)", "cccc00010011nnnn0000ssss0rr1mmmm"), // all
//INST(&V::arm_TST_imm, "TST (imm)", "cccc00110001nnnn0000rrrrvvvvvvvv"), // all
//INST(&V::arm_TST_reg, "TST (reg)", "cccc00010001nnnn0000vvvvvrr0mmmm"), // all
//INST(&V::arm_TST_rsr, "TST (rsr)", "cccc00010001nnnn0000ssss0rr1mmmm"), // all
INST(&V::arm_CMP_reg, "CMP (reg)", "cccc00010101nnnn0000vvvvvrr0mmmm"), // all
INST(&V::arm_CMP_rsr, "CMP (rsr)", "cccc00010101nnnn0000ssss0rr1mmmm"), // all
INST(&V::arm_EOR_imm, "EOR (imm)", "cccc0010001Snnnnddddrrrrvvvvvvvv"), // all
INST(&V::arm_EOR_reg, "EOR (reg)", "cccc0000001Snnnnddddvvvvvrr0mmmm"), // all
INST(&V::arm_EOR_rsr, "EOR (rsr)", "cccc0000001Snnnnddddssss0rr1mmmm"), // all
INST(&V::arm_MOV_imm, "MOV (imm)", "cccc0011101S0000ddddrrrrvvvvvvvv"), // all
INST(&V::arm_MOV_reg, "MOV (reg)", "cccc0001101S0000ddddvvvvvrr0mmmm"), // all
INST(&V::arm_MOV_rsr, "MOV (rsr)", "cccc0001101S0000ddddssss0rr1mmmm"), // all
INST(&V::arm_MVN_imm, "MVN (imm)", "cccc0011111S0000ddddrrrrvvvvvvvv"), // all
INST(&V::arm_MVN_reg, "MVN (reg)", "cccc0001111S0000ddddvvvvvrr0mmmm"), // all
INST(&V::arm_MVN_rsr, "MVN (rsr)", "cccc0001111S0000ddddssss0rr1mmmm"), // all
INST(&V::arm_ORR_imm, "ORR (imm)", "cccc0011100Snnnnddddrrrrvvvvvvvv"), // all
INST(&V::arm_ORR_reg, "ORR (reg)", "cccc0001100Snnnnddddvvvvvrr0mmmm"), // all
INST(&V::arm_ORR_rsr, "ORR (rsr)", "cccc0001100Snnnnddddssss0rr1mmmm"), // all
INST(&V::arm_RSB_imm, "RSB (imm)", "cccc0010011Snnnnddddrrrrvvvvvvvv"), // all
INST(&V::arm_RSB_reg, "RSB (reg)", "cccc0000011Snnnnddddvvvvvrr0mmmm"), // all
INST(&V::arm_RSB_rsr, "RSB (rsr)", "cccc0000011Snnnnddddssss0rr1mmmm"), // all
INST(&V::arm_RSC_imm, "RSC (imm)", "cccc0010111Snnnnddddrrrrvvvvvvvv"), // all
INST(&V::arm_RSC_reg, "RSC (reg)", "cccc0000111Snnnnddddvvvvvrr0mmmm"), // all
INST(&V::arm_RSC_rsr, "RSC (rsr)", "cccc0000111Snnnnddddssss0rr1mmmm"), // all
INST(&V::arm_SBC_imm, "SBC (imm)", "cccc0010110Snnnnddddrrrrvvvvvvvv"), // all
INST(&V::arm_SBC_reg, "SBC (reg)", "cccc0000110Snnnnddddvvvvvrr0mmmm"), // all
INST(&V::arm_SBC_rsr, "SBC (rsr)", "cccc0000110Snnnnddddssss0rr1mmmm"), // all
INST(&V::arm_SUB_imm, "SUB (imm)", "cccc0010010Snnnnddddrrrrvvvvvvvv"), // all
INST(&V::arm_SUB_reg, "SUB (reg)", "cccc0000010Snnnnddddvvvvvrr0mmmm"), // all
INST(&V::arm_SUB_rsr, "SUB (rsr)", "cccc0000010Snnnnddddssss0rr1mmmm"), // all
INST(&V::arm_TEQ_imm, "TEQ (imm)", "cccc00110011nnnn0000rrrrvvvvvvvv"), // all
INST(&V::arm_TEQ_reg, "TEQ (reg)", "cccc00010011nnnn0000vvvvvrr0mmmm"), // all
INST(&V::arm_TEQ_rsr, "TEQ (rsr)", "cccc00010011nnnn0000ssss0rr1mmmm"), // all
INST(&V::arm_TST_imm, "TST (imm)", "cccc00110001nnnn0000rrrrvvvvvvvv"), // all
INST(&V::arm_TST_reg, "TST (reg)", "cccc00010001nnnn0000vvvvvrr0mmmm"), // all
INST(&V::arm_TST_rsr, "TST (rsr)", "cccc00010001nnnn0000ssss0rr1mmmm"), // all
// Exception Generating instructions
//INST(&V::arm_BKPT, "BKPT", "cccc00010010vvvvvvvvvvvv0111vvvv"), // v5

View file

@ -93,5 +93,50 @@ bool ArmTranslatorVisitor::LinkToNextInstruction() {
return false;
}
IREmitter::ResultAndCarry ArmTranslatorVisitor::EmitImmShift(IR::Value value, ShiftType type, Imm5 imm5, IR::Value carry_in) {
IREmitter::ResultAndCarry result_and_carry;
switch (type)
{
case ShiftType::LSL:
result_and_carry = ir.LogicalShiftLeft(value, ir.Imm8(imm5), carry_in);
break;
case ShiftType::LSR:
imm5 = imm5 ? imm5 : 32;
result_and_carry = ir.LogicalShiftRight(value, ir.Imm8(imm5), carry_in);
break;
case ShiftType::ASR:
imm5 = imm5 ? imm5 : 32;
result_and_carry = ir.ArithmeticShiftRight(value, ir.Imm8(imm5), carry_in);
break;
case ShiftType::ROR:
if (imm5)
result_and_carry = ir.RotateRight(value, ir.Imm8(imm5), carry_in);
else
result_and_carry = ir.RotateRightExtended(value, carry_in);
break;
}
return result_and_carry;
}
IREmitter::ResultAndCarry ArmTranslatorVisitor::EmitRegShift(IR::Value value, ShiftType type, IR::Value amount, IR::Value carry_in) {
IREmitter::ResultAndCarry result_and_carry;
switch (type)
{
case ShiftType::LSL:
result_and_carry = ir.LogicalShiftLeft(value, amount, carry_in);
break;
case ShiftType::LSR:
result_and_carry = ir.LogicalShiftRight(value, amount, carry_in);
break;
case ShiftType::ASR:
result_and_carry = ir.ArithmeticShiftRight(value, amount, carry_in);
break;
case ShiftType::ROR:
result_and_carry = ir.RotateRight(value, amount, carry_in);
break;
}
return result_and_carry;
}
} // namespace Arm
} // namespace Dynarmic

View file

@ -10,9 +10,9 @@ namespace Dynarmic {
namespace Arm {
bool ArmTranslatorVisitor::arm_ADC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 imm8) {
u32 imm32 = ArmExpandImm(rotate, imm8);
// ADC{S}<c> <Rd>, <Rn>, #<imm>
if (ConditionPassed(cond)) {
u32 imm32 = ArmExpandImm(rotate, imm8);
auto result = ir.AddWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.GetCFlag());
if (d == Reg::PC) {
@ -34,52 +34,290 @@ bool ArmTranslatorVisitor::arm_ADC_imm(Cond cond, bool S, Reg n, Reg d, int rota
}
bool ArmTranslatorVisitor::arm_ADC_reg(Cond cond, bool S, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag());
auto result = ir.AddWithCarry(ir.GetRegister(n), shifted.result, ir.GetCFlag());
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result.result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_ADC_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (n == Reg::PC || m == Reg::PC || s == Reg::PC)
return UnpredictableInstruction();
if (ConditionPassed(cond)) {
auto shift_n = ir.LeastSignificantByte(ir.GetRegister(s));
auto carry_in = ir.GetCFlag();
auto shifted = EmitRegShift(ir.GetRegister(m), shift, shift_n, carry_in);
auto result = ir.AddWithCarry(ir.GetRegister(n), shifted.result, ir.GetCFlag());
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result.result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_ADD_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 imm8) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
u32 imm32 = ArmExpandImm(rotate, imm8);
auto result = ir.AddWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(0));
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result.result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_ADD_reg(Cond cond, bool S, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag());
auto result = ir.AddWithCarry(ir.GetRegister(n), shifted.result, ir.Imm1(0));
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result.result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_ADD_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (n == Reg::PC || m == Reg::PC || s == Reg::PC)
return UnpredictableInstruction();
if (ConditionPassed(cond)) {
auto shift_n = ir.LeastSignificantByte(ir.GetRegister(s));
auto carry_in = ir.GetCFlag();
auto shifted = EmitRegShift(ir.GetRegister(m), shift, shift_n, carry_in);
auto result = ir.AddWithCarry(ir.GetRegister(n), shifted.result, ir.Imm1(0));
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result.result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_AND_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 imm8) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto imm_carry = ArmExpandImm_C(rotate, imm8, ir.GetCFlag());
auto result = ir.And(ir.GetRegister(n), ir.Imm32(imm_carry.imm32));
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(imm_carry.carry);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_AND_reg(Cond cond, bool S, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto carry_in = ir.GetCFlag();
auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, carry_in);
auto result = ir.And(ir.GetRegister(n), shifted.result);
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_AND_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (n == Reg::PC || m == Reg::PC || s == Reg::PC)
return UnpredictableInstruction();
if (ConditionPassed(cond)) {
auto shift_n = ir.LeastSignificantByte(ir.GetRegister(s));
auto carry_in = ir.GetCFlag();
auto shifted = EmitRegShift(ir.GetRegister(m), shift, shift_n, carry_in);
auto result = ir.And(ir.GetRegister(n), shifted.result);
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_BIC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 imm8) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto imm_carry = ArmExpandImm_C(rotate, imm8, ir.GetCFlag());
auto result = ir.And(ir.GetRegister(n), ir.Not(ir.Imm32(imm_carry.imm32)));
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(imm_carry.carry);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_BIC_reg(Cond cond, bool S, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto carry_in = ir.GetCFlag();
auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, carry_in);
auto result = ir.And(ir.GetRegister(n), ir.Not(shifted.result));
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_BIC_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (n == Reg::PC || m == Reg::PC || s == Reg::PC)
return UnpredictableInstruction();
if (ConditionPassed(cond)) {
auto shift_n = ir.LeastSignificantByte(ir.GetRegister(s));
auto carry_in = ir.GetCFlag();
auto shifted = EmitRegShift(ir.GetRegister(m), shift, shift_n, carry_in);
auto result = ir.And(ir.GetRegister(n), ir.Not(shifted.result));
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_CMN_imm(Cond cond, Reg n, int rotate, Imm8 imm8) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
u32 imm32 = ArmExpandImm(rotate, imm8);
auto result = ir.AddWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(0));
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true;
}
bool ArmTranslatorVisitor::arm_CMN_reg(Cond cond, Reg n, Imm5 imm5, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag());
auto result = ir.AddWithCarry(ir.GetRegister(n), shifted.result, ir.Imm1(0));
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true;
}
bool ArmTranslatorVisitor::arm_CMN_rsr(Cond cond, Reg n, Reg s, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto shift_n = ir.LeastSignificantByte(ir.GetRegister(s));
auto carry_in = ir.GetCFlag();
auto shifted = EmitRegShift(ir.GetRegister(m), shift, shift_n, carry_in);
auto result = ir.AddWithCarry(ir.GetRegister(n), shifted.result, ir.Imm1(0));
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true;
}
bool ArmTranslatorVisitor::arm_CMP_imm(Cond cond, Reg n, int rotate, Imm8 imm8) {
u32 imm32 = ArmExpandImm(rotate, imm8);
// CMP<c> <Rn>, #<imm>
if (ConditionPassed(cond)) {
u32 imm32 = ArmExpandImm(rotate, imm8);
auto result = ir.SubWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(1));
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
@ -90,101 +328,578 @@ bool ArmTranslatorVisitor::arm_CMP_imm(Cond cond, Reg n, int rotate, Imm8 imm8)
}
bool ArmTranslatorVisitor::arm_CMP_reg(Cond cond, Reg n, Imm5 imm5, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag());
auto result = ir.SubWithCarry(ir.GetRegister(n), shifted.result, ir.Imm1(1));
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true;
}
bool ArmTranslatorVisitor::arm_CMP_rsr(Cond cond, Reg n, Reg s, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto shift_n = ir.LeastSignificantByte(ir.GetRegister(s));
auto carry_in = ir.GetCFlag();
auto shifted = EmitRegShift(ir.GetRegister(m), shift, shift_n, carry_in);
auto result = ir.SubWithCarry(ir.GetRegister(n), shifted.result, ir.Imm1(1));
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true;
}
bool ArmTranslatorVisitor::arm_EOR_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 imm8) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto imm_carry = ArmExpandImm_C(rotate, imm8, ir.GetCFlag());
auto result = ir.Eor(ir.GetRegister(n), ir.Imm32(imm_carry.imm32));
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(imm_carry.carry);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_EOR_reg(Cond cond, bool S, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto carry_in = ir.GetCFlag();
auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, carry_in);
auto result = ir.Eor(ir.GetRegister(n), shifted.result);
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_EOR_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (n == Reg::PC || m == Reg::PC || s == Reg::PC)
return UnpredictableInstruction();
if (ConditionPassed(cond)) {
auto shift_n = ir.LeastSignificantByte(ir.GetRegister(s));
auto carry_in = ir.GetCFlag();
auto shifted = EmitRegShift(ir.GetRegister(m), shift, shift_n, carry_in);
auto result = ir.Eor(ir.GetRegister(n), shifted.result);
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_MOV_imm(Cond cond, bool S, Reg d, int rotate, Imm8 imm8) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto imm_carry = ArmExpandImm_C(rotate, imm8, ir.GetCFlag());
auto result = ir.Imm32(imm_carry.imm32);
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(imm_carry.carry);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_MOV_reg(Cond cond, bool S, Reg d, Imm5 imm5, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto carry_in = ir.GetCFlag();
auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, carry_in);
auto result = shifted.result;
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_MOV_rsr(Cond cond, bool S, Reg d, Reg s, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (m == Reg::PC || s == Reg::PC)
return UnpredictableInstruction();
if (ConditionPassed(cond)) {
auto shift_n = ir.LeastSignificantByte(ir.GetRegister(s));
auto carry_in = ir.GetCFlag();
auto shifted = EmitRegShift(ir.GetRegister(m), shift, shift_n, carry_in);
auto result = shifted.result;
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_MVN_imm(Cond cond, bool S, Reg d, int rotate, Imm8 imm8) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto imm_carry = ArmExpandImm_C(rotate, imm8, ir.GetCFlag());
auto result = ir.Not(ir.Imm32(imm_carry.imm32));
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(imm_carry.carry);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_MVN_reg(Cond cond, bool S, Reg d, Imm5 imm5, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto carry_in = ir.GetCFlag();
auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, carry_in);
auto result = ir.Not(shifted.result);
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_MVN_rsr(Cond cond, bool S, Reg d, Reg s, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (m == Reg::PC || s == Reg::PC)
return UnpredictableInstruction();
if (ConditionPassed(cond)) {
auto shift_n = ir.LeastSignificantByte(ir.GetRegister(s));
auto carry_in = ir.GetCFlag();
auto shifted = EmitRegShift(ir.GetRegister(m), shift, shift_n, carry_in);
auto result = ir.Not(shifted.result);
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_ORR_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 imm8) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto imm_carry = ArmExpandImm_C(rotate, imm8, ir.GetCFlag());
auto result = ir.Or(ir.GetRegister(n), ir.Imm32(imm_carry.imm32));
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(imm_carry.carry);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_ORR_reg(Cond cond, bool S, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto carry_in = ir.GetCFlag();
auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, carry_in);
auto result = ir.Or(ir.GetRegister(n), shifted.result);
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_ORR_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (n == Reg::PC || m == Reg::PC || s == Reg::PC)
return UnpredictableInstruction();
if (ConditionPassed(cond)) {
auto shift_n = ir.LeastSignificantByte(ir.GetRegister(s));
auto carry_in = ir.GetCFlag();
auto shifted = EmitRegShift(ir.GetRegister(m), shift, shift_n, carry_in);
auto result = ir.Or(ir.GetRegister(n), shifted.result);
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_RSB_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 imm8) {
return InterpretThisInstruction();
}
bool ArmTranslatorVisitor::arm_RSB_reg(Cond cond, bool S, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m) {
return InterpretThisInstruction();
}
bool ArmTranslatorVisitor::arm_RSB_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, ShiftType shift, Reg m) {
return InterpretThisInstruction();
}
bool ArmTranslatorVisitor::arm_RSC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 imm8) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
u32 imm32 = ArmExpandImm(rotate, imm8);
auto result = ir.SubWithCarry(ir.Imm32(imm32), ir.GetRegister(n), ir.GetCFlag());
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result.result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_RSC_reg(Cond cond, bool S, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag());
auto result = ir.SubWithCarry(shifted.result, ir.GetRegister(n), ir.GetCFlag());
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result.result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_RSC_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (n == Reg::PC || m == Reg::PC || s == Reg::PC)
return UnpredictableInstruction();
if (ConditionPassed(cond)) {
auto shift_n = ir.LeastSignificantByte(ir.GetRegister(s));
auto carry_in = ir.GetCFlag();
auto shifted = EmitRegShift(ir.GetRegister(m), shift, shift_n, carry_in);
auto result = ir.SubWithCarry(shifted.result, ir.GetRegister(n), ir.GetCFlag());
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result.result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_SBC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 imm8) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
u32 imm32 = ArmExpandImm(rotate, imm8);
auto result = ir.SubWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.GetCFlag());
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result.result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_SBC_reg(Cond cond, bool S, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag());
auto result = ir.SubWithCarry(ir.GetRegister(n), shifted.result, ir.GetCFlag());
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result.result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_SBC_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (n == Reg::PC || m == Reg::PC || s == Reg::PC)
return UnpredictableInstruction();
if (ConditionPassed(cond)) {
auto shift_n = ir.LeastSignificantByte(ir.GetRegister(s));
auto carry_in = ir.GetCFlag();
auto shifted = EmitRegShift(ir.GetRegister(m), shift, shift_n, carry_in);
auto result = ir.SubWithCarry(ir.GetRegister(n), shifted.result, ir.GetCFlag());
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result.result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_SUB_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 imm8) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
u32 imm32 = ArmExpandImm(rotate, imm8);
auto result = ir.SubWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(1));
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result.result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_SUB_reg(Cond cond, bool S, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag());
auto result = ir.SubWithCarry(ir.GetRegister(n), shifted.result, ir.Imm1(1));
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result.result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_SUB_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (n == Reg::PC || m == Reg::PC || s == Reg::PC)
return UnpredictableInstruction();
if (ConditionPassed(cond)) {
auto shift_n = ir.LeastSignificantByte(ir.GetRegister(s));
auto carry_in = ir.GetCFlag();
auto shifted = EmitRegShift(ir.GetRegister(m), shift, shift_n, carry_in);
auto result = ir.SubWithCarry(ir.GetRegister(n), shifted.result, ir.Imm1(1));
if (d == Reg::PC) {
ASSERT(!S);
ir.ALUWritePC(result.result);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, result.result);
if (S) {
ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
}
return true;
}
bool ArmTranslatorVisitor::arm_TEQ_imm(Cond cond, Reg n, int rotate, Imm8 imm8) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto imm_carry = ArmExpandImm_C(rotate, imm8, ir.GetCFlag());
auto result = ir.Eor(ir.GetRegister(n), ir.Imm32(imm_carry.imm32));
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(imm_carry.carry);
}
return true;
}
bool ArmTranslatorVisitor::arm_TEQ_reg(Cond cond, Reg n, Imm5 imm5, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto carry_in = ir.GetCFlag();
auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, carry_in);
auto result = ir.Eor(ir.GetRegister(n), shifted.result);
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
}
return true;
}
bool ArmTranslatorVisitor::arm_TEQ_rsr(Cond cond, Reg n, Reg s, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (n == Reg::PC || m == Reg::PC || s == Reg::PC)
return UnpredictableInstruction();
if (ConditionPassed(cond)) {
auto shift_n = ir.LeastSignificantByte(ir.GetRegister(s));
auto carry_in = ir.GetCFlag();
auto shifted = EmitRegShift(ir.GetRegister(m), shift, shift_n, carry_in);
auto result = ir.Eor(ir.GetRegister(n), shifted.result);
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
}
return true;
}
bool ArmTranslatorVisitor::arm_TST_imm(Cond cond, Reg n, int rotate, Imm8 imm8) {
//auto result = ArmExpandImm_C(rotate, imm8);
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto imm_carry = ArmExpandImm_C(rotate, imm8, ir.GetCFlag());
auto result = ir.And(ir.GetRegister(n), ir.Imm32(imm_carry.imm32));
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(imm_carry.carry);
}
return true;
}
bool ArmTranslatorVisitor::arm_TST_reg(Cond cond, Reg n, Imm5 imm5, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (ConditionPassed(cond)) {
auto carry_in = ir.GetCFlag();
auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, carry_in);
auto result = ir.And(ir.GetRegister(n), shifted.result);
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
}
return true;
}
bool ArmTranslatorVisitor::arm_TST_rsr(Cond cond, Reg n, Reg s, ShiftType shift, Reg m) {
return InterpretThisInstruction();
if (n == Reg::PC || m == Reg::PC || s == Reg::PC)
return UnpredictableInstruction();
if (ConditionPassed(cond)) {
auto shift_n = ir.LeastSignificantByte(ir.GetRegister(s));
auto carry_in = ir.GetCFlag();
auto shifted = EmitRegShift(ir.GetRegister(m), shift, shift_n, carry_in);
auto result = ir.And(ir.GetRegister(n), shifted.result);
ir.SetNFlag(ir.MostSignificantBit(result));
ir.SetZFlag(ir.IsZero(result));
ir.SetCFlag(shifted.carry);
}
return true;
}
} // namespace Arm

View file

@ -43,6 +43,24 @@ struct ArmTranslatorVisitor final {
return rotr(static_cast<u32>(imm8), rotate*2);
}
struct ImmAndCarry {
u32 imm32;
IR::Value carry;
};
ImmAndCarry ArmExpandImm_C(int rotate, u32 imm8, IR::Value carry_in) {
u32 imm32 = imm8;
auto carry_out = carry_in;
if (rotate) {
imm32 = rotr(imm8, rotate * 2);
carry_out = ir.Imm1(imm32 >> 31 == 1);
}
return {imm32, carry_out};
}
IREmitter::ResultAndCarry EmitImmShift(IR::Value value, ShiftType type, Imm5 imm5, IR::Value carry_in);
IREmitter::ResultAndCarry EmitRegShift(IR::Value value, ShiftType type, IR::Value amount, IR::Value carry_in);
// Data processing instructions
bool arm_ADC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 imm8);
bool arm_ADC_reg(Cond cond, bool S, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m);