2016-07-04 14:37:50 +01:00
|
|
|
/* 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 "common/assert.h"
|
|
|
|
#include "frontend/arm_types.h"
|
2016-07-14 13:28:20 +01:00
|
|
|
#include "frontend/decoder/arm.h"
|
2016-07-04 14:37:50 +01:00
|
|
|
#include "frontend/ir/ir.h"
|
2016-07-18 09:25:33 +01:00
|
|
|
#include "frontend/translate/translate.h"
|
2016-08-01 20:20:22 +01:00
|
|
|
#include "frontend/translate/translate_arm/translate_arm.h"
|
2016-07-04 14:37:50 +01:00
|
|
|
|
|
|
|
namespace Dynarmic {
|
|
|
|
namespace Arm {
|
|
|
|
|
|
|
|
IR::Block TranslateArm(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) {
|
2016-07-14 13:28:20 +01:00
|
|
|
ArmTranslatorVisitor visitor{descriptor};
|
|
|
|
|
|
|
|
bool should_continue = true;
|
2016-07-14 14:04:43 +01:00
|
|
|
while (should_continue && visitor.cond_state == ConditionalState::None) {
|
2016-08-01 20:03:13 +01:00
|
|
|
const u32 arm_pc = visitor.ir.current_location.PC();
|
2016-07-14 13:28:20 +01:00
|
|
|
const u32 arm_instruction = (*memory_read_32)(arm_pc);
|
|
|
|
|
|
|
|
const auto decoder = DecodeArm<ArmTranslatorVisitor>(arm_instruction);
|
|
|
|
if (decoder) {
|
|
|
|
should_continue = decoder->call(visitor, arm_instruction);
|
|
|
|
} else {
|
|
|
|
should_continue = visitor.arm_UDF();
|
|
|
|
}
|
|
|
|
|
2016-07-14 14:04:43 +01:00
|
|
|
if (visitor.cond_state == ConditionalState::Break) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-08-01 20:03:13 +01:00
|
|
|
visitor.ir.current_location = visitor.ir.current_location.AdvancePC(4);
|
2016-07-14 13:28:20 +01:00
|
|
|
visitor.ir.block.cycle_count++;
|
|
|
|
}
|
|
|
|
|
2016-07-14 14:04:43 +01:00
|
|
|
if (visitor.cond_state == ConditionalState::Translating) {
|
|
|
|
if (should_continue) {
|
|
|
|
visitor.ir.SetTerm(IR::Term::LinkBlock{visitor.ir.current_location});
|
|
|
|
}
|
|
|
|
visitor.ir.block.cond_failed = { visitor.ir.current_location };
|
|
|
|
}
|
|
|
|
|
2016-07-22 23:55:00 +01:00
|
|
|
return std::move(visitor.ir.block);
|
2016-07-04 14:37:50 +01:00
|
|
|
}
|
|
|
|
|
2016-08-01 20:20:22 +01:00
|
|
|
bool ArmTranslatorVisitor::ConditionPassed(Cond cond) {
|
|
|
|
ASSERT_MSG(cond_state != ConditionalState::Translating,
|
|
|
|
"In the current impl, ConditionPassed should never be called again once a non-AL cond is hit. "
|
|
|
|
"(i.e.: one and only one conditional instruction per block)");
|
|
|
|
ASSERT_MSG(cond_state != ConditionalState::Break,
|
|
|
|
"This should never happen. We requested a break but that wasn't honored.");
|
|
|
|
|
|
|
|
if (cond == Cond::AL) {
|
|
|
|
// Everything is fine with the world
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-08-05 04:14:15 +01:00
|
|
|
if (cond == Cond::NV) {
|
|
|
|
// NV conditional is obsolete, but still seems to be used in some places!
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-08-01 20:20:22 +01:00
|
|
|
// non-AL cond
|
|
|
|
|
|
|
|
if (!ir.block.instructions.empty()) {
|
|
|
|
// We've already emitted instructions. Quit for now, we'll make a new block here later.
|
|
|
|
cond_state = ConditionalState::Break;
|
|
|
|
ir.SetTerm(IR::Term::LinkBlock{ir.current_location});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We've not emitted instructions yet.
|
|
|
|
// We'll emit one instruction, and set the block-entry conditional appropriately.
|
|
|
|
|
|
|
|
cond_state = ConditionalState::Translating;
|
|
|
|
ir.block.cond = cond;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::InterpretThisInstruction() {
|
|
|
|
ir.SetTerm(IR::Term::Interpret(ir.current_location));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::UnpredictableInstruction() {
|
|
|
|
ASSERT_MSG(false, "UNPREDICTABLE");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::LinkToNextInstruction() {
|
|
|
|
auto next_location = ir.current_location.AdvancePC(4);
|
|
|
|
ir.SetTerm(IR::Term::LinkBlock{next_location});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
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:44:35 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-07-04 14:37:50 +01:00
|
|
|
} // namespace Arm
|
|
|
|
} // namespace Dynarmic
|