mirror of
https://git.suyu.dev/suyu/dynarmic.git
synced 2026-01-08 23:48:18 +01:00
Reorganisation, Import Skyeye, This is a mess
This commit is contained in:
parent
be1c1de552
commit
d743adf518
55 changed files with 14939 additions and 591 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
102
src/backend_x64/interface_x64.cpp
Normal file
102
src/backend_x64/interface_x64.cpp
Normal 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
|
||||
|
|
@ -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*;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ enum class Class : ClassType {
|
|||
Log,
|
||||
Common,
|
||||
Common_Memory,
|
||||
Core_ARM11,
|
||||
Debug,
|
||||
Count ///< Total number of logging classes
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
165
src/frontend/decoder/thumb1.h
Normal file
165
src/frontend/decoder/thumb1.h
Normal 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
|
||||
|
|
@ -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) {
|
||||
|
|
@ -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 {
|
||||
|
|
@ -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 {
|
||||
|
|
@ -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 )
|
||||
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
88
src/frontend/translate_thumb.h
Normal file
88
src/frontend/translate_thumb.h
Normal 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
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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 );
|
||||
}
|
||||
|
|
@ -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>
|
||||
Loading…
Add table
Add a link
Reference in a new issue