2016-07-04 10:22:11 +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.
|
|
|
|
*/
|
|
|
|
|
2016-07-04 14:37:50 +01:00
|
|
|
#include <tuple>
|
2016-07-04 10:22:11 +01:00
|
|
|
|
2016-07-04 14:37:50 +01:00
|
|
|
#include "common/assert.h"
|
2016-07-04 10:22:11 +01:00
|
|
|
#include "frontend/arm_types.h"
|
2016-07-04 14:37:50 +01:00
|
|
|
#include "frontend/decoder/thumb1.h"
|
2016-07-04 10:22:11 +01:00
|
|
|
#include "frontend/ir_emitter.h"
|
2016-07-04 14:37:50 +01:00
|
|
|
#include "frontend/translate.h"
|
2016-07-04 10:22:11 +01:00
|
|
|
|
|
|
|
namespace Dynarmic {
|
|
|
|
namespace Arm {
|
|
|
|
|
2016-07-04 14:37:50 +01:00
|
|
|
struct TranslatorVisitor final {
|
|
|
|
explicit TranslatorVisitor(LocationDescriptor descriptor) : ir(descriptor) {
|
|
|
|
ASSERT_MSG(descriptor.TFlag, "The processor must be in Thumb mode");
|
|
|
|
}
|
|
|
|
|
2016-07-04 10:22:11 +01:00
|
|
|
IREmitter ir;
|
|
|
|
|
2016-07-04 14:37:50 +01:00
|
|
|
bool thumb1_LSL_imm(Imm5 imm5, Reg m, Reg d) {
|
2016-07-04 10:22:11 +01:00
|
|
|
u8 shift_n = imm5;
|
|
|
|
// LSLS <Rd>, <Rm>, #<imm5>
|
|
|
|
auto cpsr_c = ir.GetCFlag();
|
|
|
|
auto result = ir.LogicalShiftLeft(ir.GetRegister(m), ir.Imm8(shift_n), cpsr_c);
|
|
|
|
ir.SetRegister(d, result.result);
|
|
|
|
ir.SetNFlag(ir.MostSignificantBit(result.result));
|
|
|
|
ir.SetZFlag(ir.IsZero(result.result));
|
|
|
|
ir.SetCFlag(result.carry);
|
2016-07-04 14:37:50 +01:00
|
|
|
return true;
|
2016-07-04 10:22:11 +01:00
|
|
|
}
|
2016-07-04 14:37:50 +01:00
|
|
|
bool thumb1_LSR_imm(Imm5 imm5, Reg m, Reg d) {
|
2016-07-04 10:22:11 +01:00
|
|
|
u8 shift_n = imm5 != 0 ? imm5 : 32;
|
|
|
|
// LSRS <Rd>, <Rm>, #<imm5>
|
|
|
|
auto cpsr_c = ir.GetCFlag();
|
|
|
|
auto result = ir.LogicalShiftRight(ir.GetRegister(m), ir.Imm8(shift_n), cpsr_c);
|
|
|
|
ir.SetRegister(d, result.result);
|
|
|
|
ir.SetNFlag(ir.MostSignificantBit(result.result));
|
|
|
|
ir.SetZFlag(ir.IsZero(result.result));
|
|
|
|
ir.SetCFlag(result.carry);
|
2016-07-04 14:37:50 +01:00
|
|
|
return true;
|
2016-07-04 10:22:11 +01:00
|
|
|
}
|
2016-07-04 14:37:50 +01:00
|
|
|
bool thumb1_ASR_imm(Imm5 imm5, Reg m, Reg d) {
|
2016-07-04 10:22:11 +01:00
|
|
|
u8 shift_n = imm5 != 0 ? imm5 : 32;
|
|
|
|
// ASRS <Rd>, <Rm>, #<imm5>
|
|
|
|
auto cpsr_c = ir.GetCFlag();
|
|
|
|
auto result = ir.ArithmeticShiftRight(ir.GetRegister(m), ir.Imm8(shift_n), cpsr_c);
|
|
|
|
ir.SetRegister(d, result.result);
|
|
|
|
ir.SetNFlag(ir.MostSignificantBit(result.result));
|
|
|
|
ir.SetZFlag(ir.IsZero(result.result));
|
|
|
|
ir.SetCFlag(result.carry);
|
2016-07-04 14:37:50 +01:00
|
|
|
return true;
|
2016-07-04 10:22:11 +01:00
|
|
|
}
|
2016-07-04 14:37:50 +01:00
|
|
|
|
|
|
|
bool thumb1_LSL_reg(Reg m, Reg d_n) {
|
2016-07-04 10:22:11 +01:00
|
|
|
const Reg d = d_n, n = d_n;
|
|
|
|
// LSLS <Rdn>, <Rm>
|
|
|
|
auto shift_n = ir.LeastSignificantByte(ir.GetRegister(m));
|
|
|
|
auto apsr_c = ir.GetCFlag();
|
|
|
|
auto result_carry = ir.LogicalShiftLeft(ir.GetRegister(n), shift_n, apsr_c);
|
|
|
|
ir.SetRegister(d, result_carry.result);
|
|
|
|
ir.SetNFlag(ir.MostSignificantBit(result_carry.result));
|
|
|
|
ir.SetZFlag(ir.IsZero(result_carry.result));
|
|
|
|
ir.SetCFlag(result_carry.carry);
|
2016-07-04 14:37:50 +01:00
|
|
|
return true;
|
2016-07-04 10:22:11 +01:00
|
|
|
}
|
2016-07-04 14:37:50 +01:00
|
|
|
bool thumb1_LSR_reg(Reg m, Reg d_n) {
|
2016-07-04 10:22:11 +01:00
|
|
|
const Reg d = d_n, n = d_n;
|
|
|
|
// LSRS <Rdn>, <Rm>
|
|
|
|
auto shift_n = ir.LeastSignificantByte(ir.GetRegister(m));
|
|
|
|
auto cpsr_c = ir.GetCFlag();
|
|
|
|
auto result = ir.LogicalShiftRight(ir.GetRegister(n), shift_n, cpsr_c);
|
|
|
|
ir.SetRegister(d, result.result);
|
|
|
|
ir.SetNFlag(ir.MostSignificantBit(result.result));
|
|
|
|
ir.SetZFlag(ir.IsZero(result.result));
|
|
|
|
ir.SetCFlag(result.carry);
|
2016-07-04 14:37:50 +01:00
|
|
|
return true;
|
2016-07-04 10:22:11 +01:00
|
|
|
}
|
2016-07-04 14:37:50 +01:00
|
|
|
bool thumb1_ASR_reg(Reg m, Reg d_n) {
|
2016-07-04 10:22:11 +01:00
|
|
|
const Reg d = d_n, n = d_n;
|
|
|
|
// ASRS <Rdn>, <Rm>
|
|
|
|
auto shift_n = ir.LeastSignificantByte(ir.GetRegister(m));
|
|
|
|
auto cpsr_c = ir.GetCFlag();
|
|
|
|
auto result = ir.ArithmeticShiftRight(ir.GetRegister(n), shift_n, cpsr_c);
|
|
|
|
ir.SetRegister(d, result.result);
|
|
|
|
ir.SetNFlag(ir.MostSignificantBit(result.result));
|
|
|
|
ir.SetZFlag(ir.IsZero(result.result));
|
|
|
|
ir.SetCFlag(result.carry);
|
2016-07-04 14:37:50 +01:00
|
|
|
return true;
|
2016-07-04 10:22:11 +01:00
|
|
|
}
|
|
|
|
|
2016-07-04 14:37:50 +01:00
|
|
|
bool thumb1_UDF() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
2016-07-04 10:22:11 +01:00
|
|
|
|
2016-07-04 14:37:50 +01:00
|
|
|
enum class ThumbInstSize {
|
|
|
|
Thumb16, Thumb32
|
2016-07-04 10:22:11 +01:00
|
|
|
};
|
|
|
|
|
2016-07-04 14:37:50 +01:00
|
|
|
static std::tuple<u32, ThumbInstSize> ReadThumbInstruction(u32 arm_pc, MemoryRead32FuncType memory_read_32) {
|
|
|
|
u32 first_part = (*memory_read_32)(arm_pc & 0xFFFFFFFC);
|
|
|
|
if ((arm_pc & 0x2) != 0)
|
|
|
|
first_part >>= 16;
|
|
|
|
first_part &= 0xFFFF;
|
|
|
|
|
|
|
|
if ((first_part & 0xF800) != 0xE800 && (first_part & 0xF000) != 0xF000) {
|
|
|
|
// 16-bit thumb instruction
|
|
|
|
return std::make_tuple(first_part, ThumbInstSize::Thumb16);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 32-bit thumb instruction
|
|
|
|
|
|
|
|
u32 second_part = (*memory_read_32)((arm_pc+2) & 0xFFFFFFFC);
|
|
|
|
if (((arm_pc+2) & 0x2) != 0)
|
|
|
|
second_part >>= 16;
|
|
|
|
second_part &= 0xFFFF;
|
|
|
|
|
|
|
|
return std::make_tuple(static_cast<u32>((first_part << 16) | second_part), ThumbInstSize::Thumb32);
|
|
|
|
}
|
|
|
|
|
|
|
|
IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) {
|
|
|
|
TranslatorVisitor visitor{descriptor};
|
|
|
|
|
|
|
|
bool should_continue = true;
|
|
|
|
while (should_continue) {
|
|
|
|
const u32 arm_pc = visitor.ir.current_location.arm_pc;
|
|
|
|
|
|
|
|
u32 thumb_instruction;
|
|
|
|
ThumbInstSize inst_size;
|
|
|
|
std::tie(thumb_instruction, inst_size) = ReadThumbInstruction(arm_pc, memory_read_32);
|
|
|
|
|
|
|
|
if (inst_size == ThumbInstSize::Thumb16) {
|
|
|
|
auto decoder = DecodeThumb1<TranslatorVisitor>(static_cast<u16>(thumb_instruction));
|
|
|
|
if (decoder) {
|
|
|
|
should_continue = decoder->call(visitor, static_cast<u16>(thumb_instruction));
|
|
|
|
} else {
|
|
|
|
should_continue = visitor.thumb1_UDF();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*auto decoder = DecodeThumb2<TranslatorVisitor>(thumb_instruction);
|
|
|
|
if (decoder) {
|
|
|
|
should_continue = decoder->call(visitor, thumb_instruction);
|
|
|
|
} else {
|
|
|
|
should_continue = visitor.thumb2_UDF();
|
|
|
|
}*/
|
|
|
|
ASSERT_MSG(0, "Unimplemented");
|
|
|
|
}
|
|
|
|
|
|
|
|
visitor.ir.current_location.arm_pc += inst_size == ThumbInstSize::Thumb16 ? 2 : 4;
|
|
|
|
visitor.ir.block.cycle_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return visitor.ir.block;
|
|
|
|
}
|
|
|
|
|
2016-07-04 10:22:11 +01:00
|
|
|
} // namespace Arm
|
|
|
|
} // namepsace Dynarmic
|