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

View file

@ -93,5 +93,50 @@ bool ArmTranslatorVisitor::LinkToNextInstruction() {
return false; 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 Arm
} // namespace Dynarmic } // namespace Dynarmic

View file

@ -10,9 +10,9 @@ namespace Dynarmic {
namespace Arm { namespace Arm {
bool ArmTranslatorVisitor::arm_ADC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 imm8) { 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> // ADC{S}<c> <Rd>, <Rn>, #<imm>
if (ConditionPassed(cond)) { if (ConditionPassed(cond)) {
u32 imm32 = ArmExpandImm(rotate, imm8);
auto result = ir.AddWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.GetCFlag()); auto result = ir.AddWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.GetCFlag());
if (d == Reg::PC) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { bool ArmTranslatorVisitor::arm_CMP_imm(Cond cond, Reg n, int rotate, Imm8 imm8) {
u32 imm32 = ArmExpandImm(rotate, imm8);
// CMP<c> <Rn>, #<imm> // CMP<c> <Rn>, #<imm>
if (ConditionPassed(cond)) { if (ConditionPassed(cond)) {
u32 imm32 = ArmExpandImm(rotate, imm8);
auto result = ir.SubWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(1)); auto result = ir.SubWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(1));
ir.SetNFlag(ir.MostSignificantBit(result.result)); ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { bool ArmTranslatorVisitor::arm_RSB_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 imm8) {
return InterpretThisInstruction(); return InterpretThisInstruction();
} }
bool ArmTranslatorVisitor::arm_RSB_reg(Cond cond, bool S, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m) { bool ArmTranslatorVisitor::arm_RSB_reg(Cond cond, bool S, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m) {
return InterpretThisInstruction(); return InterpretThisInstruction();
} }
bool ArmTranslatorVisitor::arm_RSB_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, ShiftType shift, Reg m) { bool ArmTranslatorVisitor::arm_RSB_rsr(Cond cond, bool S, Reg n, Reg d, Reg s, ShiftType shift, Reg m) {
return InterpretThisInstruction(); return InterpretThisInstruction();
} }
bool ArmTranslatorVisitor::arm_RSC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 imm8) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { bool ArmTranslatorVisitor::arm_TST_imm(Cond cond, Reg n, int rotate, Imm8 imm8) {
//auto result = ArmExpandImm_C(rotate, imm8); if (ConditionPassed(cond)) {
return InterpretThisInstruction(); 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) { 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) { 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 } // namespace Arm

View file

@ -43,6 +43,24 @@ struct ArmTranslatorVisitor final {
return rotr(static_cast<u32>(imm8), rotate*2); 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 // Data processing instructions
bool arm_ADC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 imm8); 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); bool arm_ADC_reg(Cond cond, bool S, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m);