dynarmic/src/frontend/translate/translate_arm/data_processing.cpp
Tillmann Karras 30a90295b9 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...
2016-08-03 00:47:16 +01:00

906 lines
32 KiB
C++

/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* This software may be used and distributed according to the terms of the GNU
* General Public License version 2 or any later version.
*/
#include "translate_arm.h"
namespace Dynarmic {
namespace Arm {
bool ArmTranslatorVisitor::arm_ADC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 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) {
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_reg(Cond cond, bool S, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
// 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));
ir.SetCFlag(result.carry);
ir.SetVFlag(result.overflow);
}
return true;
}
bool ArmTranslatorVisitor::arm_CMP_reg(Cond cond, Reg n, Imm5 imm5, ShiftType shift, Reg m) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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 Dynarmic