mirror of
https://git.suyu.dev/suyu/dynarmic.git
synced 2026-01-03 13:14:42 +01:00
Proper implementation of Arm::Translate
This commit is contained in:
parent
d743adf518
commit
14388ea690
29 changed files with 276 additions and 90 deletions
|
|
@ -14,6 +14,7 @@ set(SRCS
|
|||
frontend/disassembler_arm.cpp
|
||||
frontend/ir/ir.cpp
|
||||
frontend/ir_emitter.cpp
|
||||
frontend/translate.cpp
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
|
|
@ -43,7 +44,9 @@ set(HEADERS
|
|||
frontend/ir/ir.h
|
||||
frontend/ir/opcodes.h
|
||||
frontend/ir_emitter.h
|
||||
frontend/translate_thumb.h
|
||||
frontend/translate.h
|
||||
frontend/translate_arm.cpp
|
||||
frontend/translate_thumb.cpp
|
||||
interface/interface.h
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "backend_x64/emit_x64.h"
|
||||
#include "common/x64/emitter.h"
|
||||
#include "frontend/arm_types.h"
|
||||
|
||||
// TODO: More optimal use of immediates.
|
||||
// TODO: Have ARM flags in host flags and not have them use up GPR registers unless necessary.
|
||||
|
|
@ -34,6 +35,9 @@ static IR::Inst* FindUseWithOpcode(IR::Inst* inst, IR::Opcode opcode) {
|
|||
}
|
||||
|
||||
CodePtr EmitX64::Emit(Arm::LocationDescriptor descriptor, Dynarmic::IR::Block block) {
|
||||
inhibit_emission.clear();
|
||||
reg_alloc.Reset();
|
||||
|
||||
code->INT3();
|
||||
CodePtr code_ptr = code->GetCodePtr();
|
||||
|
||||
|
|
@ -46,6 +50,7 @@ CodePtr EmitX64::Emit(Arm::LocationDescriptor descriptor, Dynarmic::IR::Block bl
|
|||
reg_alloc.EndOfAllocScope();
|
||||
}
|
||||
|
||||
EmitAddCycles(block.cycle_count);
|
||||
EmitReturnToDispatch();
|
||||
|
||||
return code_ptr;
|
||||
|
|
@ -378,6 +383,11 @@ void EmitX64::EmitArithmeticShiftRight(IR::Value* value_) {
|
|||
}
|
||||
}
|
||||
|
||||
void EmitX64::EmitAddCycles(size_t cycles) {
|
||||
ASSERT(cycles < std::numeric_limits<u32>::max());
|
||||
code->SUB(64, MDisp(R15, offsetof(JitState, cycles_remaining)), Imm32(cycles));
|
||||
}
|
||||
|
||||
void EmitX64::EmitReturnToDispatch() {
|
||||
// TODO: Update cycle counts
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "backend_x64/reg_alloc.h"
|
||||
#include "backend_x64/routines.h"
|
||||
|
|
@ -19,10 +20,15 @@ namespace BackendX64 {
|
|||
|
||||
class EmitX64 final {
|
||||
public:
|
||||
EmitX64(Gen::XEmitter* code, Routines* routines, UserCallbacks cb) : code(code), reg_alloc(code), routines(routines), cb(cb) {}
|
||||
EmitX64(Gen::XEmitter* code, Routines* routines, UserCallbacks cb)
|
||||
: reg_alloc(code), code(code), routines(routines), cb(cb) {}
|
||||
|
||||
CodePtr Emit(Arm::LocationDescriptor descriptor, IR::Block ir);
|
||||
CodePtr GetBasicBlock(Arm::LocationDescriptor descriptor);
|
||||
|
||||
CodePtr GetBasicBlock(Arm::LocationDescriptor descriptor) {
|
||||
auto iter = basic_blocks.find(descriptor);
|
||||
return iter != basic_blocks.end() ? iter->second : nullptr;
|
||||
}
|
||||
|
||||
void EmitImmU1(IR::Value* value);
|
||||
void EmitImmU8(IR::Value* value);
|
||||
|
|
@ -46,14 +52,17 @@ public:
|
|||
void EmitLogicalShiftRight(IR::Value* value);
|
||||
void EmitArithmeticShiftRight(IR::Value* value);
|
||||
|
||||
void EmitAddCycles(size_t cycles);
|
||||
void EmitReturnToDispatch();
|
||||
|
||||
private:
|
||||
std::set<IR::Value*> inhibit_emission;
|
||||
Gen::XEmitter* code;
|
||||
RegAlloc reg_alloc;
|
||||
|
||||
Gen::XEmitter* code;
|
||||
Routines* routines;
|
||||
UserCallbacks cb;
|
||||
std::unordered_map<Arm::LocationDescriptor, CodePtr, Arm::LocationDescriptorHash> basic_blocks;
|
||||
};
|
||||
|
||||
} // namespace BackendX64
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include "common/common_types.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "frontend/arm_types.h"
|
||||
#include "frontend/translate.h"
|
||||
#include "interface/interface.h"
|
||||
|
||||
namespace Dynarmic {
|
||||
|
|
@ -27,12 +28,13 @@ struct BlockOfCode : Gen::XCodeBlock {
|
|||
};
|
||||
|
||||
struct Jit::Impl {
|
||||
Impl(UserCallbacks callbacks) : emitter(&block_of_code, &routines, callbacks) {}
|
||||
Impl(UserCallbacks callbacks) : emitter(&block_of_code, &routines, callbacks), callbacks(callbacks) {}
|
||||
|
||||
JitState jit_state{};
|
||||
Routines routines{};
|
||||
BlockOfCode block_of_code{};
|
||||
EmitX64 emitter;
|
||||
const UserCallbacks callbacks;
|
||||
|
||||
size_t Execute(size_t cycle_count) {
|
||||
u32 pc = jit_state.Reg[15];
|
||||
|
|
@ -50,7 +52,7 @@ private:
|
|||
if (code_ptr)
|
||||
return code_ptr;
|
||||
|
||||
IR::Block ir_block = IR::Block({0, false, false}); // TODO: Do this.
|
||||
IR::Block ir_block = Arm::Translate(descriptor, callbacks.MemoryRead32);
|
||||
return emitter.Emit(descriptor, ir_block);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -201,5 +201,12 @@ void RegAlloc::EndOfAllocScope() {
|
|||
iter.second = nullptr;
|
||||
}
|
||||
|
||||
void RegAlloc::Reset() {
|
||||
hostloc_to_value.clear();
|
||||
hostloc_state.clear();
|
||||
remaining_uses.clear();
|
||||
}
|
||||
|
||||
|
||||
} // namespace BackendX64
|
||||
} // namespace Dynarmic
|
||||
|
|
|
|||
|
|
@ -78,6 +78,8 @@ public:
|
|||
|
||||
void EndOfAllocScope();
|
||||
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
HostLoc SelectARegister(std::initializer_list<HostLoc> desired_locations) const;
|
||||
std::vector<HostLoc> ValueLocations(IR::Value* value) const;
|
||||
|
|
|
|||
|
|
@ -72,5 +72,13 @@ struct LocationDescriptor {
|
|||
}
|
||||
};
|
||||
|
||||
struct LocationDescriptorHash {
|
||||
size_t operator()(const LocationDescriptor& x) const {
|
||||
return std::hash<u64>()(static_cast<u64>(x.arm_pc)
|
||||
^ (static_cast<u64>(x.TFlag) << 32)
|
||||
^ (static_cast<u64>(x.EFlag) << 33));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Arm
|
||||
} // namespace Dynarmic
|
||||
|
|
|
|||
|
|
@ -43,6 +43,9 @@ private:
|
|||
expect |= 1 << bit_position;
|
||||
mask |= 1 << bit_position;
|
||||
break;
|
||||
default:
|
||||
// Ignore
|
||||
break;
|
||||
}
|
||||
}
|
||||
return std::make_tuple(mask, expect);
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ private:
|
|||
};
|
||||
|
||||
template <typename V>
|
||||
static const std::array<Thumb1Matcher<V>, 6> g_thumb1_instruction_table {{
|
||||
static const std::array<Thumb1Matcher<V>, 7> g_thumb1_instruction_table {{
|
||||
|
||||
#define INST(fn, name, bitstring) detail::detail<Thumb1Matcher, u16, 16>::GetMatcher<decltype(fn), fn>(name, bitstring)
|
||||
|
||||
|
|
@ -138,7 +138,7 @@ static const std::array<Thumb1Matcher<V>, 6> g_thumb1_instruction_table {{
|
|||
// 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_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") },
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ public:
|
|||
|
||||
Arm::LocationDescriptor location;
|
||||
std::list<ValuePtr> instructions;
|
||||
size_t cycle_count = 0;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,10 @@ namespace Arm {
|
|||
|
||||
class IREmitter {
|
||||
public:
|
||||
IR::Block block = Dynarmic::IR::Block({0, false, false});
|
||||
explicit IREmitter(LocationDescriptor descriptor) : block(descriptor), current_location(descriptor) {}
|
||||
|
||||
IR::Block block;
|
||||
LocationDescriptor current_location;
|
||||
|
||||
struct ResultAndCarry {
|
||||
IR::ValuePtr result;
|
||||
|
|
|
|||
22
src/frontend/translate.cpp
Normal file
22
src/frontend/translate.cpp
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/* 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 "frontend/arm_types.h"
|
||||
#include "frontend/ir/ir.h"
|
||||
#include "frontend/translate.h"
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace Arm {
|
||||
|
||||
IR::Block TranslateArm(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32);
|
||||
IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32);
|
||||
|
||||
IR::Block Translate(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) {
|
||||
return (descriptor.TFlag ? TranslateThumb : TranslateArm)(descriptor, memory_read_32);
|
||||
}
|
||||
|
||||
} // namespace Arm
|
||||
} // namespace Dynarmic
|
||||
19
src/frontend/translate.h
Normal file
19
src/frontend/translate.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/* 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/ir.h"
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace Arm {
|
||||
|
||||
using MemoryRead32FuncType = u32 (*)(u32 vaddr);
|
||||
|
||||
IR::Block Translate(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32);
|
||||
|
||||
} // namespace Arm
|
||||
} // namespace Dynarmic
|
||||
21
src/frontend/translate_arm.cpp
Normal file
21
src/frontend/translate_arm.cpp
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2016 MerryMage
|
||||
* This software may be used and distributed according to the terms of the GNU
|
||||
* General Public License version 2 or any later version.
|
||||
*/
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "frontend/arm_types.h"
|
||||
#include "frontend/ir/ir.h"
|
||||
#include "frontend/translate.h"
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace Arm {
|
||||
|
||||
IR::Block TranslateArm(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) {
|
||||
ASSERT_MSG(0, "Unimplemented");
|
||||
return IR::Block(descriptor);
|
||||
}
|
||||
|
||||
} // namespace Arm
|
||||
} // namespace Dynarmic
|
||||
|
|
@ -4,19 +4,25 @@
|
|||
* General Public License version 2 or any later version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <tuple>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "frontend/arm_types.h"
|
||||
#include "frontend/decoder/thumb1.h"
|
||||
#include "frontend/ir_emitter.h"
|
||||
#include "frontend/translate.h"
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace Arm {
|
||||
|
||||
class TranslatorVisitor {
|
||||
public:
|
||||
struct TranslatorVisitor final {
|
||||
explicit TranslatorVisitor(LocationDescriptor descriptor) : ir(descriptor) {
|
||||
ASSERT_MSG(descriptor.TFlag, "The processor must be in Thumb mode");
|
||||
}
|
||||
|
||||
IREmitter ir;
|
||||
|
||||
void thumb1_LSL_imm(Imm5 imm5, Reg m, Reg d) {
|
||||
bool thumb1_LSL_imm(Imm5 imm5, Reg m, Reg d) {
|
||||
u8 shift_n = imm5;
|
||||
// LSLS <Rd>, <Rm>, #<imm5>
|
||||
auto cpsr_c = ir.GetCFlag();
|
||||
|
|
@ -25,8 +31,9 @@ public:
|
|||
ir.SetNFlag(ir.MostSignificantBit(result.result));
|
||||
ir.SetZFlag(ir.IsZero(result.result));
|
||||
ir.SetCFlag(result.carry);
|
||||
return true;
|
||||
}
|
||||
void thumb1_LSR_imm(Imm5 imm5, Reg m, Reg d) {
|
||||
bool 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();
|
||||
|
|
@ -35,8 +42,9 @@ public:
|
|||
ir.SetNFlag(ir.MostSignificantBit(result.result));
|
||||
ir.SetZFlag(ir.IsZero(result.result));
|
||||
ir.SetCFlag(result.carry);
|
||||
return true;
|
||||
}
|
||||
void thumb1_ASR_imm(Imm5 imm5, Reg m, Reg d) {
|
||||
bool 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();
|
||||
|
|
@ -45,8 +53,10 @@ public:
|
|||
ir.SetNFlag(ir.MostSignificantBit(result.result));
|
||||
ir.SetZFlag(ir.IsZero(result.result));
|
||||
ir.SetCFlag(result.carry);
|
||||
return true;
|
||||
}
|
||||
void thumb1_LSL_reg(Reg m, Reg d_n) {
|
||||
|
||||
bool 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));
|
||||
|
|
@ -56,8 +66,9 @@ public:
|
|||
ir.SetNFlag(ir.MostSignificantBit(result_carry.result));
|
||||
ir.SetZFlag(ir.IsZero(result_carry.result));
|
||||
ir.SetCFlag(result_carry.carry);
|
||||
return true;
|
||||
}
|
||||
void thumb1_LSR_reg(Reg m, Reg d_n) {
|
||||
bool 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));
|
||||
|
|
@ -67,8 +78,9 @@ public:
|
|||
ir.SetNFlag(ir.MostSignificantBit(result.result));
|
||||
ir.SetZFlag(ir.IsZero(result.result));
|
||||
ir.SetCFlag(result.carry);
|
||||
return true;
|
||||
}
|
||||
void thumb1_ASR_reg(Reg m, Reg d_n) {
|
||||
bool 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));
|
||||
|
|
@ -78,11 +90,73 @@ public:
|
|||
ir.SetNFlag(ir.MostSignificantBit(result.result));
|
||||
ir.SetZFlag(ir.IsZero(result.result));
|
||||
ir.SetCFlag(result.carry);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void thumb1_UDF() {}
|
||||
bool thumb1_UDF() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
enum class ThumbInstSize {
|
||||
Thumb16, Thumb32
|
||||
};
|
||||
|
||||
static std::tuple<u32, ThumbInstSize> ReadThumbInstruction(u32 arm_pc, MemoryRead32FuncType memory_read_32) {
|
||||
u32 first_part = (*memory_read_32)(arm_pc & 0xFFFFFFFC);
|
||||
if ((arm_pc & 0x2) != 0)
|
||||
first_part >>= 16;
|
||||
first_part &= 0xFFFF;
|
||||
|
||||
if ((first_part & 0xF800) != 0xE800 && (first_part & 0xF000) != 0xF000) {
|
||||
// 16-bit thumb instruction
|
||||
return std::make_tuple(first_part, ThumbInstSize::Thumb16);
|
||||
}
|
||||
|
||||
// 32-bit thumb instruction
|
||||
|
||||
u32 second_part = (*memory_read_32)((arm_pc+2) & 0xFFFFFFFC);
|
||||
if (((arm_pc+2) & 0x2) != 0)
|
||||
second_part >>= 16;
|
||||
second_part &= 0xFFFF;
|
||||
|
||||
return std::make_tuple(static_cast<u32>((first_part << 16) | second_part), ThumbInstSize::Thumb32);
|
||||
}
|
||||
|
||||
IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) {
|
||||
TranslatorVisitor visitor{descriptor};
|
||||
|
||||
bool should_continue = true;
|
||||
while (should_continue) {
|
||||
const u32 arm_pc = visitor.ir.current_location.arm_pc;
|
||||
|
||||
u32 thumb_instruction;
|
||||
ThumbInstSize inst_size;
|
||||
std::tie(thumb_instruction, inst_size) = ReadThumbInstruction(arm_pc, memory_read_32);
|
||||
|
||||
if (inst_size == ThumbInstSize::Thumb16) {
|
||||
auto decoder = DecodeThumb1<TranslatorVisitor>(static_cast<u16>(thumb_instruction));
|
||||
if (decoder) {
|
||||
should_continue = decoder->call(visitor, static_cast<u16>(thumb_instruction));
|
||||
} else {
|
||||
should_continue = visitor.thumb1_UDF();
|
||||
}
|
||||
} else {
|
||||
/*auto decoder = DecodeThumb2<TranslatorVisitor>(thumb_instruction);
|
||||
if (decoder) {
|
||||
should_continue = decoder->call(visitor, thumb_instruction);
|
||||
} else {
|
||||
should_continue = visitor.thumb2_UDF();
|
||||
}*/
|
||||
ASSERT_MSG(0, "Unimplemented");
|
||||
}
|
||||
|
||||
visitor.ir.current_location.arm_pc += inst_size == ThumbInstSize::Thumb16 ? 2 : 4;
|
||||
visitor.ir.block.cycle_count++;
|
||||
}
|
||||
|
||||
return visitor.ir.block;
|
||||
}
|
||||
|
||||
} // namespace Arm
|
||||
} // namepsace Dynarmic
|
||||
Loading…
Add table
Add a link
Reference in a new issue