From 30a90295b94dd6368e33587f2ca88a82fbd2fd57 Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Wed, 3 Aug 2016 00:44:35 +0100 Subject: [PATCH] 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... --- src/frontend/decoder/arm.h | 92 +- src/frontend/translate/translate_arm.cpp | 45 + .../translate_arm/data_processing.cpp | 807 +++++++++++++++++- .../translate/translate_arm/translate_arm.h | 18 + 4 files changed, 870 insertions(+), 92 deletions(-) diff --git a/src/frontend/decoder/arm.h b/src/frontend/decoder/arm.h index d7ffd709..cda45304 100644 --- a/src/frontend/decoder/arm.h +++ b/src/frontend/decoder/arm.h @@ -89,53 +89,53 @@ boost::optional&> 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 diff --git a/src/frontend/translate/translate_arm.cpp b/src/frontend/translate/translate_arm.cpp index 2170883b..cff8de81 100644 --- a/src/frontend/translate/translate_arm.cpp +++ b/src/frontend/translate/translate_arm.cpp @@ -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 diff --git a/src/frontend/translate/translate_arm/data_processing.cpp b/src/frontend/translate/translate_arm/data_processing.cpp index c07f8e71..2356896d 100644 --- a/src/frontend/translate/translate_arm/data_processing.cpp +++ b/src/frontend/translate/translate_arm/data_processing.cpp @@ -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} , , # 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 , # 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 diff --git a/src/frontend/translate/translate_arm/translate_arm.h b/src/frontend/translate/translate_arm/translate_arm.h index c79594d0..b1ade784 100644 --- a/src/frontend/translate/translate_arm/translate_arm.h +++ b/src/frontend/translate/translate_arm/translate_arm.h @@ -43,6 +43,24 @@ struct ArmTranslatorVisitor final { return rotr(static_cast(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);