Reorganisation, Import Skyeye, This is a mess

This commit is contained in:
MerryMage 2016-07-04 17:22:11 +08:00
parent be1c1de552
commit d743adf518
55 changed files with 14939 additions and 591 deletions

View file

@ -1,6 +1,52 @@
include_directories(.)
add_subdirectory(backend_x64)
add_subdirectory(common)
add_subdirectory(frontend_arm)
add_subdirectory(tests)
set(SRCS
backend_x64/emit_x64.cpp
backend_x64/interface_x64.cpp
backend_x64/reg_alloc.cpp
backend_x64/routines.cpp
common/logging/log.cpp
common/memory_util.cpp
common/string_util.cpp
common/x64/abi.cpp
common/x64/cpu_detect.cpp
common/x64/emitter.cpp
frontend/disassembler_arm.cpp
frontend/ir/ir.cpp
frontend/ir_emitter.cpp
)
set(HEADERS
backend_x64/emit_x64.h
backend_x64/jitstate.h
backend_x64/reg_alloc.h
backend_x64/routines.h
common/assert.h
common/bit_set.h
common/bit_util.h
common/code_block.h
common/common_types.h
common/logging/log.h
common/memory_util.h
common/mp.h
common/scope_exit.h
common/string_util.h
common/x64/abi.h
common/x64/cpu_detect.h
common/x64/emitter.h
frontend/arm_types.h
frontend/decoder/arm.h
frontend/decoder/decoder_detail.h
frontend/decoder/thumb1.h
frontend/disassembler_arm.h
frontend/frontend_arm.h
frontend/ir/ir.h
frontend/ir/opcodes.h
frontend/ir_emitter.h
frontend/translate_thumb.h
interface/interface.h
)
source_group(dynarmic FILES ${SRCS} ${HEADERS})
add_library(dynarmic STATIC ${SRCS} ${HEADERS})
set_target_properties(dynarmic PROPERTIES LINKER_LANGUAGE CXX)

View file

@ -1,18 +0,0 @@
set(SRCS
emit_x64.cpp
reg_alloc.cpp
routines.cpp
)
set(HEADERS
../interface/interface.h
emit_x64.h
jitstate.h
reg_alloc.h
routines.h
)
source_group(frontend_x64 FILES ${SRCS} ${HEADERS})
add_library(dynarmic_backend_x64 STATIC ${SRCS} ${HEADERS})
target_link_libraries(dynarmic_backend_x64 dynarmic_common)
set_target_properties(dynarmic_backend_x64 PROPERTIES LINKER_LANGUAGE CXX)

View file

@ -22,7 +22,7 @@ namespace BackendX64 {
// Mapping from opcode to Emit* member function.
const static std::map<IR::Opcode, void (EmitX64::*)(IR::Value*)> emit_fns {
#define OPCODE(name, type, ...) { IR::Opcode::name, &EmitX64::Emit##name },
#include "frontend_arm/ir/opcodes.inc"
#include "frontend/ir/opcodes.inc"
#undef OPCODE
};
@ -33,7 +33,7 @@ static IR::Inst* FindUseWithOpcode(IR::Inst* inst, IR::Opcode opcode) {
return iter == uses.end() ? nullptr : reinterpret_cast<IR::Inst*>(iter->get());
}
CodePtr EmitX64::Emit(Dynarmic::IR::Block block) {
CodePtr EmitX64::Emit(Arm::LocationDescriptor descriptor, Dynarmic::IR::Block block) {
code->INT3();
CodePtr code_ptr = code->GetCodePtr();
@ -98,6 +98,8 @@ void EmitX64::EmitGetNFlag(IR::Value* value_) {
X64Reg result = reg_alloc.DefRegister(value);
// TODO: Flag optimization
code->MOV(32, R(result), MDisp(R15, offsetof(JitState, Cpsr)));
code->SHR(32, R(result), Imm8(31));
}
@ -107,6 +109,8 @@ void EmitX64::EmitSetNFlag(IR::Value* value_) {
X64Reg to_store = reg_alloc.UseRegister(value->GetArg(0).get());
// TODO: Flag optimization
code->SHL(32, R(to_store), Imm8(31));
code->AND(32, MDisp(R15, offsetof(JitState, Cpsr)), Imm32(~static_cast<u32>(1 << 31)));
code->OR(32, MDisp(R15, offsetof(JitState, Cpsr)), R(to_store));
@ -117,6 +121,8 @@ void EmitX64::EmitGetZFlag(IR::Value* value_) {
X64Reg result = reg_alloc.DefRegister(value);
// TODO: Flag optimization
code->MOV(32, R(result), MDisp(R15, offsetof(JitState, Cpsr)));
code->SHR(32, R(result), Imm8(30));
code->AND(32, R(result), Imm32(1));
@ -127,6 +133,8 @@ void EmitX64::EmitSetZFlag(IR::Value* value_) {
X64Reg to_store = reg_alloc.UseRegister(value->GetArg(0).get());
// TODO: Flag optimization
code->SHL(32, R(to_store), Imm8(30));
code->AND(32, MDisp(R15, offsetof(JitState, Cpsr)), Imm32(~static_cast<u32>(1 << 30)));
code->OR(32, MDisp(R15, offsetof(JitState, Cpsr)), R(to_store));
@ -137,6 +145,8 @@ void EmitX64::EmitGetCFlag(IR::Value* value_) {
X64Reg result = reg_alloc.DefRegister(value);
// TODO: Flag optimization
code->MOV(32, R(result), MDisp(R15, offsetof(JitState, Cpsr)));
code->SHR(32, R(result), Imm8(29));
code->AND(32, R(result), Imm32(1));
@ -147,6 +157,8 @@ void EmitX64::EmitSetCFlag(IR::Value* value_) {
X64Reg to_store = reg_alloc.UseRegister(value->GetArg(0).get());
// TODO: Flag optimization
code->SHL(32, R(to_store), Imm8(29));
code->AND(32, MDisp(R15, offsetof(JitState, Cpsr)), Imm32(~static_cast<u32>(1 << 29)));
code->OR(32, MDisp(R15, offsetof(JitState, Cpsr)), R(to_store));
@ -157,6 +169,8 @@ void EmitX64::EmitGetVFlag(IR::Value* value_) {
X64Reg result = reg_alloc.DefRegister(value);
// TODO: Flag optimization
code->MOV(32, R(result), MDisp(R15, offsetof(JitState, Cpsr)));
code->SHR(32, R(result), Imm8(28));
code->AND(32, R(result), Imm32(1));
@ -167,6 +181,8 @@ void EmitX64::EmitSetVFlag(IR::Value* value_) {
X64Reg to_store = reg_alloc.UseRegister(value->GetArg(0).get());
// TODO: Flag optimization
code->SHL(32, R(to_store), Imm8(28));
code->AND(32, MDisp(R15, offsetof(JitState, Cpsr)), Imm32(~static_cast<u32>(1 << 28)));
code->OR(32, MDisp(R15, offsetof(JitState, Cpsr)), R(to_store));
@ -179,6 +195,8 @@ void EmitX64::EmitGetCarryFromOp(IR::Value*) {
void EmitX64::EmitLeastSignificantByte(IR::Value* value_) {
auto value = reinterpret_cast<IR::Inst*>(value_);
// TODO: Flag optimization
reg_alloc.UseDefRegister(value->GetArg(0).get(), value);
}
@ -187,6 +205,8 @@ void EmitX64::EmitMostSignificantBit(IR::Value* value_) {
X64Reg result = reg_alloc.UseDefRegister(value->GetArg(0).get(), value);
// TODO: Flag optimization
code->SHL(32, R(result), Imm8(31));
}
@ -195,6 +215,8 @@ void EmitX64::EmitIsZero(IR::Value* value_) {
X64Reg result = reg_alloc.UseDefRegister(value->GetArg(0).get(), value);
// TODO: Flag optimization
code->TEST(32, R(result), R(result));
code->SETcc(CCFlags::CC_E, R(result));
code->MOVZX(32, 8, result, R(result));
@ -303,7 +325,62 @@ void EmitX64::EmitLogicalShiftRight(IR::Value* value_) {
}
}
void EmitX64::EmitArithmeticShiftRight(IR::Value* value_) {
auto value = reinterpret_cast<IR::Inst*>(value_);
auto carry_inst = FindUseWithOpcode(value, IR::Opcode::GetCarryFromOp);
if (!carry_inst) {
X64Reg shift = reg_alloc.UseRegister(value->GetArg(1).get(), {HostLoc::RCX});
X64Reg result = reg_alloc.UseDefRegister(value->GetArg(0).get(), value);
//X64Reg zero = reg_alloc.ScratchRegister();
// The 32-bit x64 SAR instruction masks the shift count by 0x1F before performing the shift.
// ARM differs from the behaviour: It does not mask the count, so shifts above 31 result in zeros.
// TODO: Optimize this.
code->CMP(8, R(shift), Imm8(31));
auto Rs_gt31 = code->J_CC(CC_A);
// if (Rs & 0xFF <= 31) {
code->SAR(32, R(result), R(shift));
auto jmp_to_end = code->J();
// } else {
code->SetJumpTarget(Rs_gt31);
code->SAR(32, R(result), Imm8(31)); // Verified.
// }
code->SetJumpTarget(jmp_to_end);
} else {
inhibit_emission.insert(carry_inst);
X64Reg shift = reg_alloc.UseRegister(value->GetArg(1).get(), {HostLoc::RCX});
X64Reg result = reg_alloc.UseDefRegister(value->GetArg(0).get(), value);
X64Reg carry = reg_alloc.UseDefRegister(value->GetArg(2).get(), carry_inst);
// TODO: Optimize this.
code->CMP(8, R(shift), Imm8(31));
auto Rs_gt31 = code->J_CC(CC_A);
// if (Rs & 0xFF == 0) goto end;
code->TEST(8, R(shift), R(shift));
auto Rs_zero = code->J_CC(CC_Z);
// if (Rs & 0xFF <= 31) {
code->SAR(32, R(result), R(CL));
code->SETcc(CC_C, R(carry));
auto jmp_to_end = code->J();
// } else if (Rs & 0xFF > 31) {
code->SetJumpTarget(Rs_gt31);
code->SAR(32, R(result), Imm8(31)); // Verified.
code->BT(32, R(result), Imm8(31));
code->SETcc(CC_C, R(carry));
// }
code->SetJumpTarget(jmp_to_end);
code->SetJumpTarget(Rs_zero);
}
}
void EmitX64::EmitReturnToDispatch() {
// TODO: Update cycle counts
code->JMP(routines->RunCodeReturnAddress(), true);
}

View file

@ -11,7 +11,7 @@
#include "backend_x64/reg_alloc.h"
#include "backend_x64/routines.h"
#include "common/x64/emitter.h"
#include "frontend_arm/ir/ir.h"
#include "frontend/ir/ir.h"
#include "interface/interface.h"
namespace Dynarmic {
@ -21,7 +21,8 @@ class EmitX64 final {
public:
EmitX64(Gen::XEmitter* code, Routines* routines, UserCallbacks cb) : code(code), reg_alloc(code), routines(routines), cb(cb) {}
CodePtr Emit(IR::Block ir);
CodePtr Emit(Arm::LocationDescriptor descriptor, IR::Block ir);
CodePtr GetBasicBlock(Arm::LocationDescriptor descriptor);
void EmitImmU1(IR::Value* value);
void EmitImmU8(IR::Value* value);
@ -43,6 +44,7 @@ public:
void EmitIsZero(IR::Value* value);
void EmitLogicalShiftLeft(IR::Value* value);
void EmitLogicalShiftRight(IR::Value* value);
void EmitArithmeticShiftRight(IR::Value* value);
void EmitReturnToDispatch();

View file

@ -0,0 +1,102 @@
/* 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 <memory>
#include "backend_x64/emit_x64.h"
#include "backend_x64/jitstate.h"
#include "backend_x64/routines.h"
#include "common/assert.h"
#include "common/bit_util.h"
#include "common/common_types.h"
#include "common/scope_exit.h"
#include "frontend/arm_types.h"
#include "interface/interface.h"
namespace Dynarmic {
using namespace BackendX64;
struct BlockOfCode : Gen::XCodeBlock {
BlockOfCode() {
AllocCodeSpace(128 * 1024 * 1024);
}
};
struct Jit::Impl {
Impl(UserCallbacks callbacks) : emitter(&block_of_code, &routines, callbacks) {}
JitState jit_state{};
Routines routines{};
BlockOfCode block_of_code{};
EmitX64 emitter;
size_t Execute(size_t cycle_count) {
u32 pc = jit_state.Reg[15];
bool TFlag = Common::Bit<5>(jit_state.Cpsr);
bool EFlag = Common::Bit<9>(jit_state.Cpsr);
Arm::LocationDescriptor descriptor{pc, TFlag, EFlag};
CodePtr code_ptr = GetBasicBlock(descriptor);
return routines.RunCode(&jit_state, code_ptr, cycle_count);
}
private:
CodePtr GetBasicBlock(Arm::LocationDescriptor descriptor) {
CodePtr code_ptr = emitter.GetBasicBlock(descriptor);
if (code_ptr)
return code_ptr;
IR::Block ir_block = IR::Block({0, false, false}); // TODO: Do this.
return emitter.Emit(descriptor, ir_block);
}
};
Jit::Jit(UserCallbacks callbacks) : callbacks(callbacks), impl(std::make_unique<Impl>(callbacks)) {}
Jit::~Jit() {}
size_t Jit::Run(size_t cycle_count) {
ASSERT(!is_executing);
is_executing = true;
SCOPE_EXIT({ this->is_executing = false; });
halt_requested = false;
size_t cycles_executed = 0;
while (cycles_executed < cycle_count && !halt_requested) {
cycles_executed += impl->Execute(cycle_count - cycles_executed);
}
return cycles_executed;
}
void Jit::ClearCache(bool poison_memory) {
ASSERT(!is_executing);
}
void Jit::HaltExecution() {
ASSERT(is_executing);
halt_requested = true;
// TODO: Uh do other stuff to JitState pls.
}
std::array<u32, 16>& Jit::Regs() {
return impl->jit_state.Reg;
}
std::array<u32, 16> Jit::Regs() const {
return impl->jit_state.Reg;
}
u32& Jit::Cpsr() {
return impl->jit_state.Cpsr;
}
u32 Jit::Cpsr() const {
return impl->jit_state.Cpsr;
}
} // namespace Dynarmic

View file

@ -15,15 +15,15 @@ namespace BackendX64 {
constexpr size_t SpillCount = 32;
struct JitState {
u32 Cpsr;
u32 Cpsr = 0;
std::array<u32, 16> Reg{}; // Current register file.
// TODO: Mode-specific register sets unimplemented.
std::array<u32, SpillCount> Spill{}; // Spill.
// For internal use (See: Routines::RunCode)
u64 save_host_RSP;
s64 cycles_remaining;
u64 save_host_RSP = 0;
s64 cycles_remaining = 0;
};
using CodePtr = const u8*;

View file

@ -14,22 +14,23 @@
namespace Dynarmic {
namespace BackendX64 {
// TODO: Just turn this into a function that indexes a std::array.
const static std::map<HostLoc, Gen::X64Reg> hostloc_to_x64 = {
{ HostLoc::RAX, Gen::RAX },
{ HostLoc::RBX, Gen::RBX },
{ HostLoc::RCX, Gen::RCX },
{ HostLoc::RDX, Gen::RDX },
{ HostLoc::RSI, Gen::RSI },
{ HostLoc::RDI, Gen::RDI },
{ HostLoc::RBP, Gen::RBP },
{ HostLoc::RSP, Gen::RSP },
{ HostLoc::R8, Gen::R8 },
{ HostLoc::R9, Gen::R9 },
{ HostLoc::R10, Gen::R10 },
{ HostLoc::R11, Gen::R11 },
{ HostLoc::R12, Gen::R12 },
{ HostLoc::R13, Gen::R13 },
{ HostLoc::R14, Gen::R14 },
{ HostLoc::RAX, Gen::RAX },
{ HostLoc::RBX, Gen::RBX },
{ HostLoc::RCX, Gen::RCX },
{ HostLoc::RDX, Gen::RDX },
{ HostLoc::RSI, Gen::RSI },
{ HostLoc::RDI, Gen::RDI },
{ HostLoc::RBP, Gen::RBP },
{ HostLoc::RSP, Gen::RSP },
{ HostLoc::R8, Gen::R8 },
{ HostLoc::R9, Gen::R9 },
{ HostLoc::R10, Gen::R10 },
{ HostLoc::R11, Gen::R11 },
{ HostLoc::R12, Gen::R12 },
{ HostLoc::R13, Gen::R13 },
{ HostLoc::R14, Gen::R14 },
};
static Gen::OpArg SpillToOpArg(HostLoc loc) {

View file

@ -11,7 +11,7 @@
#include "backend_x64/jitstate.h"
#include "common/common_types.h"
#include "common/x64/emitter.h"
#include "frontend_arm/ir/ir.h"
#include "frontend/ir/ir.h"
namespace Dynarmic {
namespace BackendX64 {

View file

@ -1,28 +0,0 @@
set(SRCS
logging/log.cpp
memory_util.cpp
string_util.cpp
x64/abi.cpp
x64/cpu_detect.cpp
x64/emitter.cpp
)
set(HEADERS
assert.h
bit_set.h
bit_util.h
code_block.h
common_types.h
logging/log.h
memory_util.h
mp.h
scope_exit.h
string_util.h
x64/abi.h
x64/cpu_detect.h
x64/emitter.h
)
source_group(common FILES ${SRCS} ${HEADERS})
add_library(dynarmic_common STATIC ${SRCS} ${HEADERS})
set_target_properties(dynarmic_common PROPERTIES LINKER_LANGUAGE CXX)

View file

@ -32,7 +32,7 @@ constexpr T Bits(const T value) {
/// Extracts a single bit at bit_position from value of type T.
template<size_t bit_position, typename T>
constexpr T Bit(const T value) {
constexpr bool Bit(const T value) {
static_assert(bit_position < BitSize<T>(), "bit_position must be smaller than size of T");
return (value >> bit_position) & 1;
@ -44,8 +44,8 @@ inline T SignExtend(const T value) {
static_assert(bit_count <= BitSize<T>(), "bit_count larger than bitsize of T");
constexpr T mask = static_cast<T>(1ULL << bit_count) - 1;
const T signbit = Bit<bit_count - 1>(value);
if (signbit != 0) {
const bool signbit = Bit<bit_count - 1, T>(value);
if (signbit) {
return value | ~mask;
}
return value;

View file

@ -34,6 +34,7 @@ enum class Class : ClassType {
Log,
Common,
Common_Memory,
Core_ARM11,
Debug,
Count ///< Total number of logging classes
};

View file

@ -16,7 +16,7 @@
#include <boost/optional.hpp>
#include "common/common_types.h"
#include "frontend_arm/decoder/decoder_detail.h"
#include "frontend/decoder/decoder_detail.h"
namespace Dynarmic {
namespace Arm {

View file

@ -0,0 +1,165 @@
/* 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.
*/
#pragma once
#include <array>
#include <functional>
#include <tuple>
#include <boost/optional.hpp>
#include "common/common_types.h"
#include "frontend/decoder/decoder_detail.h"
namespace Dynarmic {
namespace Arm {
template <typename Visitor>
struct Thumb1Matcher {
using CallRetT = typename mp::MemFnInfo<decltype(&Visitor::thumb1_UDF), &Visitor::thumb1_UDF>::return_type;
Thumb1Matcher(const char* const name, u16 mask, u16 expect, std::function<CallRetT(Visitor&, u16)> fn)
: name(name), mask(mask), expect(expect), fn(fn) {}
/// Gets the name of this type of instruction.
const char* GetName() const {
return name;
}
/**
* Tests to see if the instruction is this type of instruction.
* @param instruction The instruction to test
* @returns true if the instruction is
*/
bool Matches(u16 instruction) const {
return (instruction & mask) == expect;
}
/**
* Calls the corresponding instruction handler on visitor for this type of instruction.
* @param v The visitor to use
* @param instruction The instruction to decode.
*/
CallRetT call(Visitor& v, u16 instruction) const {
assert(Matches(instruction));
return fn(v, instruction);
}
private:
const char* name;
u16 mask, expect;
std::function<CallRetT(Visitor&, u16)> fn;
};
template <typename V>
static const std::array<Thumb1Matcher<V>, 6> g_thumb1_instruction_table {{
#define INST(fn, name, bitstring) detail::detail<Thumb1Matcher, u16, 16>::GetMatcher<decltype(fn), fn>(name, bitstring)
// Shift (immediate), add, subtract, move and compare instructions
{ INST(&V::thumb1_LSL_imm, "LSL (imm)", "00000vvvvvmmmddd") },
{ INST(&V::thumb1_LSR_imm, "LSR (imm)", "00001vvvvvmmmddd") },
{ INST(&V::thumb1_ASR_imm, "ASR (imm)", "00010vvvvvmmmddd") },
//{ INST(&V::thumb1_ADD_rrr, "ADD (rrr)", "0001100mmmnnnddd") },
//{ INST(&V::thumb1_SUB_rrr, "SUB (rrr)", "0001101mmmnnnddd") },
//{ INST(&V::thumb1_ADD_rri, "ADD (rri)", "0001110mmmnnnddd") },
//{ INST(&V::thumb1_SUB_rri, "SUB (rri)", "0001111mmmnnnddd") },
//{ INST(&V::thumb1_MOV_ri, "MOV (ri)", "00100dddvvvvvvvv") },
//{ INST(&V::thumb1_CMP_ri, "CMP (ri)", "00101dddvvvvvvvv") },
//{ INST(&V::thumb1_ADD_ri, "ADD (ri)", "00110dddvvvvvvvv") },
//{ INST(&V::thumb1_SUB_ri, "SUB (ri)", "00111dddvvvvvvvv") },
// Data-processing instructions
// { INST(&V::thumb1_AND_reg, "AND (reg)", "0100000000mmmddd") },
// { INST(&V::thumb1_EOR_reg, "EOR (reg)", "0100000001mmmddd") },
{ INST(&V::thumb1_LSL_reg, "LSL (reg)", "0100000010mmmddd") },
{ INST(&V::thumb1_LSR_reg, "LSR (reg)", "0100000011sssddd") },
{ INST(&V::thumb1_ASR_reg, "ASR (reg)", "0100000100sssddd") },
//{ INST(&V::thumb1_ADCS_rr, "ADCS (rr)", "0100000101mmmddd") },
//{ INST(&V::thumb1_SBCS_rr, "SBCS (rr)", "0100000110mmmddd") },
//{ INST(&V::thumb1_RORS_rr, "RORS (rr)", "0100000111sssddd") },
//{ INST(&V::thumb1_TST_rr, "TST (rr)", "0100001000mmmnnn") },
//{ INST(&V::thumb1_NEGS_rr, "NEGS (rr)", "0100001001mmmddd") },
//{ INST(&V::thumb1_CMP_rr, "CMP (rr)", "0100001010mmmnnn") },
//{ INST(&V::thumb1_CMN_rr, "CMN (rr)", "0100001011mmmnnn") },
//{ INST(&V::thumb1_ORRS_rr, "ORRS (rr)", "0100001100mmmddd") },
//{ INST(&V::thumb1_MULS_rr, "MULS (rr)", "0100001101mmmddd") },
//{ INST(&V::thumb1_BICS_rr, "BICS (rr)", "0100001110mmmddd") },
//{ INST(&V::thumb1_MVNS_rr, "MVNS (rr)", "0100001111mmmddd") },
// Special data instructions
//{ INST(&V::thumb1_ADD_high, "ADD (high)", "01000100dmmmmddd") }, // v4T, Low regs: v6T2
//{ INST(&V::thumb1_CMP_high, "CMP (high)", "01000101dmmmmddd") }, // v4T
//{ INST(&V::thumb1_MOV_high, "MOV (high)", "01000110dmmmmddd") }, // v4T, Low regs: v6
// Store/Load single data item instructions
//{ INST(&V::thumb1_LDR_lit, "LDR (literal)", "01001dddvvvvvvvv") },
//{ INST(&V::thumb1_STR_rrr, "STR (rrr)", "0101000mmmnnnddd") },
//{ INST(&V::thumb1_STRH_rrr, "STRH (rrr)", "0101001mmmnnnddd") },
//{ INST(&V::thumb1_STRB_rrr, "STRB (rrr)", "0101010mmmnnnddd") },
//{ INST(&V::thumb1_LDRSB_rrr, "LDRSB (rrr)", "0101011mmmnnnddd") },
//{ INST(&V::thumb1_LDR_rrr, "LDR (rrr)", "0101100mmmnnnddd") },
//{ INST(&V::thumb1_LDRH_rrr, "LDRH (rrr)", "0101101mmmnnnddd") },
//{ INST(&V::thumb1_LDRB_rrr, "LDRB (rrr)", "0101110mmmnnnddd") },
//{ INST(&V::thumb1_LDRSH_rrr, "LDRSH (rrr)", "0101111mmmnnnddd") },
//{ INST(&V::thumb1_STRH_rri, "STRH (rri)", "10000vvvvvnnnddd") },
//{ INST(&V::thumb1_LDRH_rri, "LDRH (rri)", "10001vvvvvnnnddd") },
//{ INST(&V::thumb1_STR_sp, "STR (SP)", "10010dddvvvvvvvv") },
//{ INST(&V::thumb1_LDR_sp, "LDR (SP)", "10011dddvvvvvvvv") },
// Generate relative address instruction
//{ INST(&V::thumb1_ADR, "ADR", "10100dddvvvvvvvv") },
//{ INST(&V::thumb1_ADD_sp, "ADD (relative to SP)", "10101dddvvvvvvvv") },
// Miscellaneous 16-bit instructions
//{ INST(&V::thumb1_ADD_spsp, "ADD (imm to SP)", "101100000vvvvvvv") }, // v4T
//{ INST(&V::thumb1_SUB_spsp, "SUB (imm from SP)", "101100001vvvvvvv") }, // v4T
//{ INST(&V::thumb1_SXTH, "SXTH", "1011001000mmmddd") }, // v6
//{ INST(&V::thumb1_SXTB, "SXTB", "1011001001mmmddd") }, // v6
//{ INST(&V::thumb1_UXTH, "UXTH", "1011001010mmmddd") }, // v6
//{ INST(&V::thumb1_UXTB, "UXTB", "1011001011mmmddd") }, // v6
//{ INST(&V::thumb1_PUSH, "PUSH", "1011010rxxxxxxxx") }, // v4T
//{ INST(&V::thumb1_POP, "POP", "1011110rxxxxxxxx") }, // v4T
//{ INST(&V::thumb1_SETEND, "SETEND", "101101100101x000") }, // v6
//{ INST(&V::thumb1_CPS, "CPS", "10110110011m0aif") }, // v6
//{ INST(&V::thumb1_REV, "REV", "1011101000nnnddd") }, // v6
//{ INST(&V::thumb1_REV16, "REV16", "1011101001nnnddd") }, // v6
//{ INST(&V::thumb1_REVSH, "REVSH", "1011101011nnnddd") }, // v6
//{ INST(&V::thumb1_BKPT, "BKPT", "10111110xxxxxxxx") }, // v5
// Store/Load multiple registers
//{ INST(&V::thumb1_STMIA, "STMIA", "11000nnnxxxxxxxx") },
//{ INST(&V::thumb1_LDMIA, "LDMIA", "11001nnnxxxxxxxx") },
// Branch instructions
//{ INST(&V::thumb1_BX, "BX (reg)", "010001110mmmm000") }, // v4T
//{ INST(&V::thumb1_BLX, "BLX (reg)", "010001111mmmm000") }, // v5T
//{ INST(&V::thumb1_UDF, "UDF", "11011110--------") },
//{ INST(&V::thumb1_SWI, "SWI", "11011111xxxxxxxx") },
//{ INST(&V::thumb1_B_cond, "B (cond)", "1101ccccxxxxxxxx") },
//{ INST(&V::thumb1_B_imm, "B (imm)", "11100xxxxxxxxxxx") },
//{ INST(&V::thumb1_BLX_suffix, "BLX (imm, suffix)", "11101xxxxxxxxxx0") },
//{ INST(&V::thumb1_BLX_prefix, "BL/BLX (imm, prefix)", "11110xxxxxxxxxxx") },
//{ INST(&V::thumb1_BL_suffix, "BL (imm, suffix)", "11111xxxxxxxxxxx") },
#undef INST
}};
template<typename Visitor>
boost::optional<const Thumb1Matcher<Visitor>&> DecodeThumb1(u16 instruction) {
const auto& table = g_thumb1_instruction_table<Visitor>;
auto matches_instruction = [instruction](const auto& matcher){ return matcher.Matches(instruction); };
assert(std::count_if(table.begin(), table.end(), matches_instruction) <= 1);
auto iter = std::find_if(table.begin(), table.end(), matches_instruction);
return iter != table.end() ? boost::make_optional<const Thumb1Matcher<Visitor>&>(*iter) : boost::none;
}
} // namespace Arm
} // namespace Dynarmic

View file

@ -9,8 +9,8 @@
#include "common/bit_util.h"
#include "common/string_util.h"
#include "frontend_arm/arm_types.h"
#include "frontend_arm/decoder/arm.h"
#include "frontend/arm_types.h"
#include "frontend/decoder/arm.h"
namespace Dynarmic {
namespace Arm {
@ -512,8 +512,6 @@ public:
std::string arm_RFE() { return "ice"; }
std::string arm_SETEND(bool E) { return "ice"; }
std::string arm_SRS() { return "ice"; }
};
std::string DisassembleArm(u32 instruction) {

View file

@ -8,7 +8,7 @@
#include <map>
#include "common/assert.h"
#include "frontend_arm/ir/ir.h"
#include "frontend/ir/ir.h"
namespace Dynarmic {
namespace IR {

View file

@ -13,8 +13,8 @@
#include <boost/variant.hpp>
#include "common/common_types.h"
#include "frontend_arm/arm_types.h"
#include "frontend_arm/ir/opcodes.h"
#include "frontend/arm_types.h"
#include "frontend/ir/opcodes.h"
namespace Dynarmic {
namespace IR {

View file

@ -27,3 +27,4 @@ OPCODE(MostSignificantBit, T::U1, T::U32
OPCODE(IsZero, T::U1, T::U32 )
OPCODE(LogicalShiftLeft, T::U32, T::U32, T::U8, T::U1 )
OPCODE(LogicalShiftRight, T::U32, T::U32, T::U8, T::U1 )
OPCODE(ArithmeticShiftRight, T::U32, T::U32, T::U8, T::U1 )

View file

@ -67,6 +67,11 @@ IREmitter::ResultAndCarry IREmitter::LogicalShiftRight(IR::ValuePtr value_in, IR
return {result, carry_out};
}
IREmitter::ResultAndCarry IREmitter::ArithmeticShiftRight(IR::ValuePtr value_in, IR::ValuePtr shift_amount, IR::ValuePtr carry_in) {
auto result = Inst(IR::Opcode::ArithmeticShiftRight, {value_in, shift_amount, carry_in});
auto carry_out = Inst(IR::Opcode::GetCarryFromOp, {result});
return {result, carry_out};
}
IR::ValuePtr IREmitter::Inst(IR::Opcode op, std::initializer_list<IR::ValuePtr> args) {
auto inst = std::make_shared<IR::Inst>(op);

View file

@ -6,9 +6,9 @@
#pragma once
#include "frontend_arm/arm_types.h"
#include "frontend_arm/ir/ir.h"
#include "frontend_arm/ir/opcodes.h"
#include "frontend/arm_types.h"
#include "frontend/ir/ir.h"
#include "frontend/ir/opcodes.h"
namespace Dynarmic {
namespace Arm {
@ -40,6 +40,7 @@ public:
ResultAndCarry LogicalShiftLeft(IR::ValuePtr value_in, IR::ValuePtr shift_amount, IR::ValuePtr carry_in);
ResultAndCarry LogicalShiftRight(IR::ValuePtr value_in, IR::ValuePtr shift_amount, IR::ValuePtr carry_in);
ResultAndCarry ArithmeticShiftRight(IR::ValuePtr value_in, IR::ValuePtr shift_amount, IR::ValuePtr carry_in);
private:
IR::ValuePtr Inst(IR::Opcode op, std::initializer_list<IR::ValuePtr> args);

View file

@ -0,0 +1,88 @@
/* 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.
*/
#pragma once
#include "frontend/arm_types.h"
#include "frontend/ir_emitter.h"
namespace Dynarmic {
namespace Arm {
class TranslatorVisitor {
public:
IREmitter ir;
void thumb1_LSL_imm(Imm5 imm5, Reg m, Reg d) {
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);
}
void thumb1_LSR_imm(Imm5 imm5, Reg m, Reg d) {
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);
}
void thumb1_ASR_imm(Imm5 imm5, Reg m, Reg d) {
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);
}
void thumb1_LSL_reg(Reg m, Reg d_n) {
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);
}
void thumb1_LSR_reg(Reg m, Reg d_n) {
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);
}
void thumb1_ASR_reg(Reg m, Reg d_n) {
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);
}
void thumb1_UDF() {}
};
} // namespace Arm
} // namepsace Dynarmic

View file

@ -1,23 +0,0 @@
set(SRCS
arm_disassembler.cpp
ir/ir.cpp
ir_emitter.cpp
)
set(HEADERS
arm_disassembler.h
arm_types.h
decoder/arm.h
decoder/decoder_detail.h
decoder/thumb1.h
frontend_arm.h
ir/ir.h
ir/opcodes.h
ir_emitter.h
translate_thumb.h
)
source_group(frontend_arm FILES ${SRCS} ${HEADERS})
add_library(dynarmic_frontend_arm STATIC ${SRCS} ${HEADERS})
target_link_libraries(dynarmic_frontend_arm dynarmic_common)
set_target_properties(dynarmic_frontend_arm PROPERTIES LINKER_LANGUAGE CXX)

View file

@ -1,166 +0,0 @@
/* 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.
*/
#pragma once
#include <array>
#include <functional>
#include <tuple>
#include <boost/optional.hpp>
#include "common/common_types.h"
#include "frontend_arm/decoder/decoder_detail.h"
namespace Dynarmic {
namespace Arm {
template <typename Visitor>
struct Thumb1Matcher {
using CallRetT = typename mp::MemFnInfo<decltype(&Visitor::thumb1_UDF), &Visitor::thumb1_UDF>::return_type;
Thumb1Matcher(const char* const name, u16 mask, u16 expect, std::function<CallRetT(Visitor&, u16)> fn)
: name(name), mask(mask), expect(expect), fn(fn) {}
/// Gets the name of this type of instruction.
const char* GetName() const {
return name;
}
/**
* Tests to see if the instruction is this type of instruction.
* @param instruction The instruction to test
* @returns true if the instruction is
*/
bool Matches(u16 instruction) const {
return (instruction & mask) == expect;
}
/**
* Calls the corresponding instruction handler on visitor for this type of instruction.
* @param v The visitor to use
* @param instruction The instruction to decode.
*/
CallRetT call(Visitor& v, u16 instruction) const {
assert(Matches(instruction));
return fn(v, instruction);
}
private:
const char* name;
u16 mask, expect;
std::function<CallRetT(Visitor&, u16)> fn;
};
template <typename V>
static const std::array<Thumb1Matcher<V>, 2> g_thumb1_instruction_table {{
#define INST(fn, name, bitstring) detail::detail<Thumb1Matcher, u16, 16>::GetMatcher<decltype(fn), fn>(name, bitstring)
// Shift (immediate), add, subtract, move and compare instructions
{ INST(&V::thumb1_LSL_imm, "LSL (imm)", "00000vvvvvmmmddd") },
{ INST(&V::thumb1_LSR_imm, "LSR (imm)", "00001vvvvvmmmddd") },
/*
{ INST(&V::thumb1_ASR_rri, "ASR (rri)", "00010vvvvvmmmddd") },
{ INST(&V::thumb1_ADD_rrr, "ADD (rrr)", "0001100mmmnnnddd") },
{ INST(&V::thumb1_SUB_rrr, "SUB (rrr)", "0001101mmmnnnddd") },
{ INST(&V::thumb1_ADD_rri, "ADD (rri)", "0001110mmmnnnddd") },
{ INST(&V::thumb1_SUB_rri, "SUB (rri)", "0001111mmmnnnddd") },
{ INST(&V::thumb1_MOV_ri, "MOV (ri)", "00100dddvvvvvvvv") },
{ INST(&V::thumb1_CMP_ri, "CMP (ri)", "00101dddvvvvvvvv") },
{ INST(&V::thumb1_ADD_ri, "ADD (ri)", "00110dddvvvvvvvv") },
{ INST(&V::thumb1_SUB_ri, "SUB (ri)", "00111dddvvvvvvvv") },
// Data-processing instructions
{ INST(&V::thumb1_ANDS_rr, "ANDS (rr)", "0100000000mmmddd") },
{ INST(&V::thumb1_EORS_rr, "EORS (rr)", "0100000001mmmddd") },
{ INST(&V::thumb1_LSLS_reg, "LSLS (reg)", "0100000010mmmddd") },
{ INST(&V::thumb1_LSRS_rr, "LSRS (rr)", "0100000011sssddd") },
{ INST(&V::thumb1_ASRS_rr, "ASRS (rr)", "0100000100sssddd") },
{ INST(&V::thumb1_ADCS_rr, "ADCS (rr)", "0100000101mmmddd") },
{ INST(&V::thumb1_SBCS_rr, "SBCS (rr)", "0100000110mmmddd") },
{ INST(&V::thumb1_RORS_rr, "RORS (rr)", "0100000111sssddd") },
{ INST(&V::thumb1_TST_rr, "TST (rr)", "0100001000mmmnnn") },
{ INST(&V::thumb1_NEGS_rr, "NEGS (rr)", "0100001001mmmddd") },
{ INST(&V::thumb1_CMP_rr, "CMP (rr)", "0100001010mmmnnn") },
{ INST(&V::thumb1_CMN_rr, "CMN (rr)", "0100001011mmmnnn") },
{ INST(&V::thumb1_ORRS_rr, "ORRS (rr)", "0100001100mmmddd") },
{ INST(&V::thumb1_MULS_rr, "MULS (rr)", "0100001101mmmddd") },
{ INST(&V::thumb1_BICS_rr, "BICS (rr)", "0100001110mmmddd") },
{ INST(&V::thumb1_MVNS_rr, "MVNS (rr)", "0100001111mmmddd") },
// Special data instructions
{ INST(&V::thumb1_ADD_high, "ADD (high)", "01000100dmmmmddd") }, // v4T, Low regs: v6T2
{ INST(&V::thumb1_CMP_high, "CMP (high)", "01000101dmmmmddd") }, // v4T
{ INST(&V::thumb1_MOV_high, "MOV (high)", "01000110dmmmmddd") }, // v4T, Low regs: v6
// Store/Load single data item instructions
{ INST(&V::thumb1_LDR_lit, "LDR (literal)", "01001dddvvvvvvvv") },
{ INST(&V::thumb1_STR_rrr, "STR (rrr)", "0101000mmmnnnddd") },
{ INST(&V::thumb1_STRH_rrr, "STRH (rrr)", "0101001mmmnnnddd") },
{ INST(&V::thumb1_STRB_rrr, "STRB (rrr)", "0101010mmmnnnddd") },
{ INST(&V::thumb1_LDRSB_rrr, "LDRSB (rrr)", "0101011mmmnnnddd") },
{ INST(&V::thumb1_LDR_rrr, "LDR (rrr)", "0101100mmmnnnddd") },
{ INST(&V::thumb1_LDRH_rrr, "LDRH (rrr)", "0101101mmmnnnddd") },
{ INST(&V::thumb1_LDRB_rrr, "LDRB (rrr)", "0101110mmmnnnddd") },
{ INST(&V::thumb1_LDRSH_rrr, "LDRSH (rrr)", "0101111mmmnnnddd") },
{ INST(&V::thumb1_STRH_rri, "STRH (rri)", "10000vvvvvnnnddd") },
{ INST(&V::thumb1_LDRH_rri, "LDRH (rri)", "10001vvvvvnnnddd") },
{ INST(&V::thumb1_STR_sp, "STR (SP)", "10010dddvvvvvvvv") },
{ INST(&V::thumb1_LDR_sp, "LDR (SP)", "10011dddvvvvvvvv") },
// Generate relative address instruction
{ INST(&V::thumb1_ADR, "ADR", "10100dddvvvvvvvv") },
{ INST(&V::thumb1_ADD_sp, "ADD (relative to SP)", "10101dddvvvvvvvv") },
// Miscellaneous 16-bit instructions
{ INST(&V::thumb1_ADD_spsp, "ADD (imm to SP)", "101100000vvvvvvv") }, // v4T
{ INST(&V::thumb1_SUB_spsp, "SUB (imm from SP)", "101100001vvvvvvv") }, // v4T
{ INST(&V::thumb1_SXTH, "SXTH", "1011001000mmmddd") }, // v6
{ INST(&V::thumb1_SXTB, "SXTB", "1011001001mmmddd") }, // v6
{ INST(&V::thumb1_UXTH, "UXTH", "1011001010mmmddd") }, // v6
{ INST(&V::thumb1_UXTB, "UXTB", "1011001011mmmddd") }, // v6
{ INST(&V::thumb1_PUSH, "PUSH", "1011010rxxxxxxxx") }, // v4T
{ INST(&V::thumb1_POP, "POP", "1011110rxxxxxxxx") }, // v4T
{ INST(&V::thumb1_SETEND, "SETEND", "101101100101x000") }, // v6
{ INST(&V::thumb1_CPS, "CPS", "10110110011m0aif") }, // v6
{ INST(&V::thumb1_REV, "REV", "1011101000nnnddd") }, // v6
{ INST(&V::thumb1_REV16, "REV16", "1011101001nnnddd") }, // v6
{ INST(&V::thumb1_REVSH, "REVSH", "1011101011nnnddd") }, // v6
{ INST(&V::thumb1_BKPT, "BKPT", "10111110xxxxxxxx") }, // v5
// Store/Load multiple registers
{ INST(&V::thumb1_STMIA, "STMIA", "11000nnnxxxxxxxx") },
{ INST(&V::thumb1_LDMIA, "LDMIA", "11001nnnxxxxxxxx") },
// Branch instructions
{ INST(&V::thumb1_BX, "BX (reg)", "010001110mmmm000") }, // v4T
{ INST(&V::thumb1_BLX, "BLX (reg)", "010001111mmmm000") }, // v5T
{ INST(&V::thumb1_UDF, "UDF", "11011110--------") },
{ INST(&V::thumb1_SWI, "SWI", "11011111xxxxxxxx") },
{ INST(&V::thumb1_B_cond, "B (cond)", "1101ccccxxxxxxxx") },
{ INST(&V::thumb1_B_imm, "B (imm)", "11100xxxxxxxxxxx") },
{ INST(&V::thumb1_BLX_suffix, "BLX (imm, suffix)", "11101xxxxxxxxxx0") },
{ INST(&V::thumb1_BLX_prefix, "BL/BLX (imm, prefix)", "11110xxxxxxxxxxx") },
{ INST(&V::thumb1_BL_suffix, "BL (imm, suffix)", "11111xxxxxxxxxxx") },*/
#undef INST
}};
template<typename Visitor>
boost::optional<const Thumb1Matcher<Visitor>&> DecodeThumb1(u16 instruction) {
const auto& table = g_thumb1_instruction_table<Visitor>;
auto matches_instruction = [instruction](const auto& matcher){ return matcher.Matches(instruction); };
assert(std::count_if(table.begin(), table.end(), matches_instruction) <= 1);
auto iter = std::find_if(table.begin(), table.end(), matches_instruction);
return iter != table.end() ? boost::make_optional<const Thumb1Matcher<Visitor>&>(*iter) : boost::none;
}
} // namespace Arm
} // namespace Dynarmic

View file

@ -1,293 +0,0 @@
/* 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.
*/
#pragma once
#include "frontend_arm/arm_types.h"
#include "frontend_arm/ir_emitter.h"
namespace Dynarmic {
namespace Arm {
class TranslatorVisitor {
public:
IREmitter ir;
void thumb1_LSL_imm(Imm5 imm5, Reg m, Reg d) {
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);
}
void thumb1_LSR_imm(Imm5 imm5, Reg m, Reg d) {
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);
}
void thumb1_ASR_rri(Imm5 imm5, Reg m, Reg d) {
ir.Unimplemented();
}
void thumb1_ADD_rrr(Reg m, Reg n, Reg d) {
ir.Unimplemented();
}
void thumb1_SUB_rrr(Reg m, Reg n, Reg d) {
ir.Unimplemented();
}
void thumb1_ADD_rri() {
ir.Unimplemented();
}
void thumb1_SUB_rri() {
ir.Unimplemented();
}
void thumb1_MOV_ri() {
ir.Unimplemented();
}
void thumb1_CMP_ri() {
ir.Unimplemented();
}
void thumb1_ADD_ri() {
ir.Unimplemented();
}
void thumb1_SUB_ri() {
ir.Unimplemented();
}
void thumb1_ANDS_rr() {
ir.Unimplemented();
}
void thumb1_EORS_rr() {
ir.Unimplemented();
}
void thumb1_LSLS_reg(Reg m, Reg d_n) {
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(d), 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);
}
void thumb1_LSRS_rr() {
ir.Unimplemented();
}
void thumb1_ASRS_rr() {
ir.Unimplemented();
}
void thumb1_ADCS_rr() {
ir.Unimplemented();
}
void thumb1_SBCS_rr() {
ir.Unimplemented();
}
void thumb1_RORS_rr() {
ir.Unimplemented();
}
void thumb1_TST_rr() {
ir.Unimplemented();
}
void thumb1_NEGS_rr() {
ir.Unimplemented();
}
void thumb1_CMP_rr() {
ir.Unimplemented();
}
void thumb1_CMN_rr() {
ir.Unimplemented();
}
void thumb1_ORRS_rr() {
ir.Unimplemented();
}
void thumb1_MULS_rr() {
ir.Unimplemented();
}
void thumb1_BICS_rr() {
ir.Unimplemented();
}
void thumb1_MVNS_rr() {
ir.Unimplemented();
}
void thumb1_ADD_high() {
ir.Unimplemented();
}
void thumb1_CMP_high() {
ir.Unimplemented();
}
void thumb1_MOV_high() {
ir.Unimplemented();
}
void thumb1_LDR_lit() {
ir.Unimplemented();
}
void thumb1_STR_rrr() {
ir.Unimplemented();
}
void thumb1_STRH_rrr() {
ir.Unimplemented();
}
void thumb1_STRB_rrr() {
ir.Unimplemented();
}
void thumb1_LDRSB_rrr() {
ir.Unimplemented();
}
void thumb1_LDR_rrr() {
ir.Unimplemented();
}
void thumb1_LDRH_rrr() {
ir.Unimplemented();
}
void thumb1_LDRB_rrr() {
ir.Unimplemented();
}
void thumb1_LDRSH_rrr() {
ir.Unimplemented();
}
void thumb1_STRH_rri() {
ir.Unimplemented();
}
void thumb1_LDRH_rri() {
ir.Unimplemented();
}
void thumb1_STR_sp() {
ir.Unimplemented();
}
void thumb1_LDR_sp() {
ir.Unimplemented();
}
void thumb1_ADR() {
ir.Unimplemented();
}
void thumb1_ADD_sp() {
ir.Unimplemented();
}
void thumb1_ADD_spsp() {
ir.Unimplemented();
}
void thumb1_SUB_spsp() {
ir.Unimplemented();
}
void thumb1_SXTH() {
ir.Unimplemented();
}
void thumb1_SXTB() {
ir.Unimplemented();
}
void thumb1_UXTH() {
ir.Unimplemented();
}
void thumb1_UXTB() {
ir.Unimplemented();
}
void thumb1_PUSH() {
ir.Unimplemented();
}
void thumb1_POP() {
ir.Unimplemented();
}
void thumb1_SETEND() {
ir.Unimplemented();
}
void thumb1_CPS() {
ir.Unimplemented();
}
void thumb1_REV() {
ir.Unimplemented();
}
void thumb1_REV16() {
ir.Unimplemented();
}
void thumb1_REVSH() {
ir.Unimplemented();
}
void thumb1_BKPT() {
ir.Unimplemented();
}
void thumb1_STMIA() {
ir.Unimplemented();
}
void thumb1_LDMIA() {
ir.Unimplemented();
}
void thumb1_BX() {
ir.Unimplemented();
}
void thumb1_BLX() {
ir.Unimplemented();
}
void thumb1_BEQ() {
ir.Unimplemented();
}
void thumb1_BNE() {
ir.Unimplemented();
}
void thumb1_BCS() {
ir.Unimplemented();
}
void thumb1_BCC() {
ir.Unimplemented();
}
void thumb1_BMI() {
ir.Unimplemented();
}
void thumb1_BPL() {
ir.Unimplemented();
}
void thumb1_BVS() {
ir.Unimplemented();
}
void thumb1_BVC() {
ir.Unimplemented();
}
void thumb1_BHI() {
ir.Unimplemented();
}
void thumb1_BLS() {
ir.Unimplemented();
}
void thumb1_BGE() {
ir.Unimplemented();
}
void thumb1_BLT() {
ir.Unimplemented();
}
void thumb1_BGT() {
ir.Unimplemented();
}
void thumb1_BLE() {
ir.Unimplemented();
}
void thumb1_UDF() {
ir.Unimplemented();
}
void thumb1_SWI() {
ir.Unimplemented();
}
void thumb1_B() {
ir.Unimplemented();
}
void thumb1_BLX_suffix() {
ir.Unimplemented();
}
void thumb1_BLX_prefix() {
ir.Unimplemented();
}
void thumb1_BL_suffix() {
ir.Unimplemented();
}
};
} // namespace Arm
} // namepsace Dynarmic

View file

@ -6,10 +6,15 @@
#pragma once
#include <memory>
#include "common/common_types.h"
namespace Dynarmic {
class Jit;
/// These function pointers may be inserted into compiled code.
struct UserCallbacks {
u8 (*MemoryRead8)(u32 vaddr);
u16 (*MemoryRead16)(u32 vaddr);
@ -21,9 +26,62 @@ struct UserCallbacks {
void (*MemoryWrite32)(u32 vaddr, u32 value);
void (*MemoryWrite64)(u32 vaddr, u64 value);
void (*InterpreterFallback)(u32 pc, void* jit_state);
bool (*IsReadOnlyMemory)(u32 vaddr);
bool (*SoftwareInterrupt)(u32 swi);
void (*InterpreterFallback)(u32 pc, Jit* jit);
bool (*CallSVC)(u32 swi);
};
class Jit final {
public:
explicit Jit(Dynarmic::UserCallbacks callbacks);
~Jit();
/**
* Runs the emulated CPU for about cycle_count cycles.
* Cannot be recursively called.
* @param cycle_count Estimated number of cycles to run the CPU for.
* @returns Actual cycle count.
*/
size_t Run(size_t cycle_count);
/**
* Clears the code cache of all compiled code.
* Cannot be called from a callback.
* @param poison_memory If true, poisons memory to crash if any stray code pointers are called.
*/
void ClearCache(bool poison_memory = true);
/**
* Stops execution in Jit::Run.
* Can only be called from a callback.
*/
void HaltExecution();
/// View and modify registers.
std::array<u32, 16>& Regs();
std::array<u32, 16> Regs() const;
/// View and modify CPSR.
u32& Cpsr();
u32 Cpsr() const;
/**
* Returns true if Jit::Run was called but hasn't returned yet.
* i.e.: We're in a callback.
*/
bool IsExecuting() const {
return is_executing;
}
private:
bool halt_requested = false;
bool is_executing = false;
Dynarmic::UserCallbacks callbacks;
struct Impl;
std::unique_ptr<Impl> impl;
};
} // namespace Dynarmic

View file

@ -1,14 +0,0 @@
set(SRCS
arm/fuzz_thumb.cpp
arm/test_arm_disassembler.cpp
arm/test_thumb_instructions.cpp
main.cpp
)
set(HEADERS
)
source_group(tests FILES ${SRCS} ${HEADERS})
add_executable(dynarmic_tests ${SRCS})
target_link_libraries(dynarmic_tests dynarmic_common dynarmic_frontend_arm dynarmic_backend_x64)
set_target_properties(dynarmic_tests PROPERTIES LINKER_LANGUAGE CXX)

View file

@ -1,6 +0,0 @@
/* 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.
*/

View file

@ -1,24 +0,0 @@
/* 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 <catch.hpp>
#include "frontend_arm/arm_disassembler.h"
TEST_CASE( "Disassemble branch instructions", "[arm][disassembler]" ) {
REQUIRE(Dynarmic::Arm::DisassembleArm(0xEAFFFFFE) == "b +#0");
REQUIRE(Dynarmic::Arm::DisassembleArm(0xEB000008) == "bl +#40");
REQUIRE(Dynarmic::Arm::DisassembleArm(0xFBFFFFFE) == "blx +#2");
REQUIRE(Dynarmic::Arm::DisassembleArm(0xFAFFFFFF) == "blx +#4");
REQUIRE(Dynarmic::Arm::DisassembleArm(0xFBE1E7FE) == "blx -#7888894");
REQUIRE(Dynarmic::Arm::DisassembleArm(0xE12FFF3D) == "blx sp");
REQUIRE(Dynarmic::Arm::DisassembleArm(0x312FFF13) == "bxcc r3");
REQUIRE(Dynarmic::Arm::DisassembleArm(0x012FFF29) == "bxjeq r9");
}
TEST_CASE( "Disassemble data processing instructions", "[arm][disassembler]" ) {
REQUIRE(Dynarmic::Arm::DisassembleArm(0xE2853004) == "add r3, r5, #4");
}

View file

@ -1,59 +0,0 @@
/* 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 <catch.hpp>
#include "backend_x64/emit_x64.h"
#include "common/common_types.h"
#include "frontend_arm/decoder/thumb1.h"
#include "frontend_arm/translate_thumb.h"
struct TinyBlockOfCode : Gen::XCodeBlock {
TinyBlockOfCode() {
AllocCodeSpace(256);
}
};
void RunSingleThumbInstruction(u16 thumb_instruction, Dynarmic::BackendX64::JitState* jit_state_ptr) {
Dynarmic::Arm::TranslatorVisitor visitor;
auto decoder = Dynarmic::Arm::DecodeThumb1<Dynarmic::Arm::TranslatorVisitor>(thumb_instruction);
REQUIRE(!!decoder);
decoder->call(visitor, thumb_instruction);
TinyBlockOfCode block_of_code;
Dynarmic::BackendX64::Routines routines;
Dynarmic::UserCallbacks callbacks;
Dynarmic::BackendX64::EmitX64 emitter(&block_of_code, &routines, callbacks);
Dynarmic::BackendX64::CodePtr code = emitter.Emit(visitor.ir.block);
routines.RunCode(jit_state_ptr, code, 1);
}
TEST_CASE( "thumb: lsls r0, r1, #2", "[thumb]" ) {
Dynarmic::BackendX64::JitState jit_state;
jit_state.Reg[0] = 1;
jit_state.Reg[1] = 2;
jit_state.Cpsr = 0;
RunSingleThumbInstruction(0x0088, &jit_state);
REQUIRE( jit_state.Reg[0] == 8 );
REQUIRE( jit_state.Reg[1] == 2 );
REQUIRE( jit_state.Cpsr == 0 );
}
TEST_CASE( "thumb: lsls r0, r1, #31", "[thumb]" ) {
Dynarmic::BackendX64::JitState jit_state;
jit_state.Reg[0] = 1;
jit_state.Reg[1] = 0xFFFFFFFF;
jit_state.Cpsr = 0;
RunSingleThumbInstruction(0x07C8, &jit_state);
REQUIRE( jit_state.Reg[0] == 0x80000000 );
REQUIRE( jit_state.Reg[1] == 0xffffffff );
REQUIRE( jit_state.Cpsr == 0x20000000 );
}

View file

@ -1,8 +0,0 @@
/* 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.
*/
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#include <catch.hpp>