mirror of
https://git.suyu.dev/suyu/dynarmic.git
synced 2026-01-05 22:18:16 +01:00
Update documentation (2016-08-12)
This commit is contained in:
parent
3808938c98
commit
1029fd27ce
17 changed files with 205 additions and 138 deletions
|
|
@ -64,6 +64,12 @@ enum class SignExtendRotation {
|
|||
ROR_24 ///< ROR #24
|
||||
};
|
||||
|
||||
/**
|
||||
* LocationDescriptor describes the location of a basic block.
|
||||
* The location is not solely based on the PC because other flags influence the way
|
||||
* instructions should be translated. The CPSR.T flag is most notable since it
|
||||
* tells us if the processor is in Thumb or Arm mode.
|
||||
*/
|
||||
struct LocationDescriptor {
|
||||
static constexpr u32 FPSCR_MASK = 0x3F79F9F;
|
||||
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ private:
|
|||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4800)
|
||||
#pragma warning(disable:4800) // forcing value to bool 'true' or 'false' (performance warning)
|
||||
#endif
|
||||
template<typename Visitor, typename ...Args, typename CallRetT>
|
||||
struct VisitorCaller<CallRetT(Visitor::*)(Args...)> {
|
||||
|
|
|
|||
|
|
@ -10,48 +10,37 @@
|
|||
#include "common/assert.h"
|
||||
#include "common/string_util.h"
|
||||
#include "frontend/ir/ir.h"
|
||||
#include "frontend/ir/opcodes.h"
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace IR {
|
||||
|
||||
// Opcode information
|
||||
|
||||
namespace OpcodeInfo {
|
||||
|
||||
using T = Dynarmic::IR::Type;
|
||||
|
||||
struct Meta {
|
||||
const char* name;
|
||||
Type type;
|
||||
std::vector<Type> arg_types;
|
||||
};
|
||||
|
||||
static const std::map<Opcode, Meta> opcode_info {{
|
||||
#define OPCODE(name, type, ...) { Opcode::name, { #name, type, { __VA_ARGS__ } } },
|
||||
#include "opcodes.inc"
|
||||
#undef OPCODE
|
||||
}};
|
||||
|
||||
} // namespace OpcodeInfo
|
||||
|
||||
Type GetTypeOf(Opcode op) {
|
||||
return OpcodeInfo::opcode_info.at(op).type;
|
||||
}
|
||||
|
||||
size_t GetNumArgsOf(Opcode op) {
|
||||
return OpcodeInfo::opcode_info.at(op).arg_types.size();
|
||||
}
|
||||
|
||||
Type GetArgTypeOf(Opcode op, size_t arg_index) {
|
||||
return OpcodeInfo::opcode_info.at(op).arg_types.at(arg_index);
|
||||
}
|
||||
|
||||
const char* GetNameOf(Opcode op) {
|
||||
return OpcodeInfo::opcode_info.at(op).name;
|
||||
}
|
||||
|
||||
// Value class member definitions
|
||||
|
||||
Value::Value(Inst* value) : type(Type::Opaque) {
|
||||
inner.inst = value;
|
||||
}
|
||||
|
||||
Value::Value(Arm::Reg value) : type(Type::RegRef) {
|
||||
inner.imm_regref = value;
|
||||
}
|
||||
|
||||
Value::Value(Arm::ExtReg value) : type(Type::ExtRegRef) {
|
||||
inner.imm_extregref = value;
|
||||
}
|
||||
|
||||
Value::Value(bool value) : type(Type::U1) {
|
||||
inner.imm_u1 = value;
|
||||
}
|
||||
|
||||
Value::Value(u8 value) : type(Type::U8) {
|
||||
inner.imm_u8 = value;
|
||||
}
|
||||
|
||||
Value::Value(u32 value) : type(Type::U32) {
|
||||
inner.imm_u32 = value;
|
||||
}
|
||||
|
||||
bool Value::IsImmediate() const {
|
||||
if (type == Type::Opaque)
|
||||
return inner.inst->GetOpcode() == Opcode::Identity ? inner.inst->GetArg(0).IsImmediate() : false;
|
||||
|
|
|
|||
|
|
@ -32,62 +32,24 @@ namespace IR {
|
|||
//
|
||||
// A basic block is represented as an IR::Block.
|
||||
|
||||
enum class Type {
|
||||
Void = 1 << 0,
|
||||
RegRef = 1 << 1,
|
||||
ExtRegRef = 1 << 2,
|
||||
Opaque = 1 << 3,
|
||||
U1 = 1 << 4,
|
||||
U8 = 1 << 5,
|
||||
U16 = 1 << 6,
|
||||
U32 = 1 << 7,
|
||||
U64 = 1 << 8,
|
||||
F32 = 1 << 9,
|
||||
F64 = 1 << 10,
|
||||
};
|
||||
|
||||
Type GetTypeOf(Opcode op);
|
||||
size_t GetNumArgsOf(Opcode op);
|
||||
Type GetArgTypeOf(Opcode op, size_t arg_index);
|
||||
const char* GetNameOf(Opcode op);
|
||||
|
||||
// Type declarations
|
||||
|
||||
/**
|
||||
* A representation of a microinstruction. A single ARM/Thumb instruction may be
|
||||
* converted into zero or more microinstructions.
|
||||
*/
|
||||
|
||||
struct Value;
|
||||
class Inst;
|
||||
|
||||
/**
|
||||
* A representation of a value in the IR.
|
||||
* A value may either be an immediate or the result of a microinstruction.
|
||||
*/
|
||||
struct Value final {
|
||||
public:
|
||||
Value() : type(Type::Void) {}
|
||||
|
||||
explicit Value(Inst* value) : type(Type::Opaque) {
|
||||
inner.inst = value;
|
||||
}
|
||||
|
||||
explicit Value(Arm::Reg value) : type(Type::RegRef) {
|
||||
inner.imm_regref = value;
|
||||
}
|
||||
|
||||
explicit Value(Arm::ExtReg value) : type(Type::ExtRegRef) {
|
||||
inner.imm_extregref = value;
|
||||
}
|
||||
|
||||
explicit Value(bool value) : type(Type::U1) {
|
||||
inner.imm_u1 = value;
|
||||
}
|
||||
|
||||
explicit Value(u8 value) : type(Type::U8) {
|
||||
inner.imm_u8 = value;
|
||||
}
|
||||
|
||||
explicit Value(u32 value) : type(Type::U32) {
|
||||
inner.imm_u32 = value;
|
||||
}
|
||||
explicit Value(Inst* value);
|
||||
explicit Value(Arm::Reg value);
|
||||
explicit Value(Arm::ExtReg value);
|
||||
explicit Value(bool value);
|
||||
explicit Value(u8 value);
|
||||
explicit Value(u32 value);
|
||||
|
||||
bool IsEmpty() const;
|
||||
bool IsImmediate() const;
|
||||
|
|
@ -113,6 +75,10 @@ private:
|
|||
} inner;
|
||||
};
|
||||
|
||||
/**
|
||||
* A representation of a microinstruction. A single ARM/Thumb instruction may be
|
||||
* converted into zero or more microinstructions.
|
||||
*/
|
||||
class Inst final : public Common::IntrusiveListNode<Inst> {
|
||||
public:
|
||||
Inst(Opcode op) : op(op) {}
|
||||
|
|
@ -151,7 +117,7 @@ struct Invalid {};
|
|||
|
||||
/**
|
||||
* This terminal instruction calls the interpreter, starting at `next`.
|
||||
* The interpreter must interpret at least 1 instruction but may choose to interpret more.
|
||||
* The interpreter must interpret exactly one instruction.
|
||||
*/
|
||||
struct Interpret {
|
||||
explicit Interpret(const Arm::LocationDescriptor& next_) : next(next_) {}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,11 @@
|
|||
namespace Dynarmic {
|
||||
namespace Arm {
|
||||
|
||||
/**
|
||||
* Convenience class to construct a basic block of the intermediate representation.
|
||||
* `block` is the resulting block.
|
||||
* The user of this class updates `current_location` as appropriate.
|
||||
*/
|
||||
class IREmitter {
|
||||
public:
|
||||
explicit IREmitter(LocationDescriptor descriptor) : block(descriptor), current_location(descriptor) {}
|
||||
|
|
|
|||
52
src/frontend/ir/opcodes.cpp
Normal file
52
src/frontend/ir/opcodes.cpp
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/* 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 <map>
|
||||
#include <vector>
|
||||
|
||||
#include "frontend/ir/opcodes.h"
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace IR {
|
||||
|
||||
// Opcode information
|
||||
|
||||
namespace OpcodeInfo {
|
||||
|
||||
using T = Dynarmic::IR::Type;
|
||||
|
||||
struct Meta {
|
||||
const char* name;
|
||||
Type type;
|
||||
std::vector<Type> arg_types;
|
||||
};
|
||||
|
||||
static const std::map<Opcode, Meta> opcode_info {{
|
||||
#define OPCODE(name, type, ...) { Opcode::name, { #name, type, { __VA_ARGS__ } } },
|
||||
#include "opcodes.inc"
|
||||
#undef OPCODE
|
||||
}};
|
||||
|
||||
} // namespace OpcodeInfo
|
||||
|
||||
Type GetTypeOf(Opcode op) {
|
||||
return OpcodeInfo::opcode_info.at(op).type;
|
||||
}
|
||||
|
||||
size_t GetNumArgsOf(Opcode op) {
|
||||
return OpcodeInfo::opcode_info.at(op).arg_types.size();
|
||||
}
|
||||
|
||||
Type GetArgTypeOf(Opcode op, size_t arg_index) {
|
||||
return OpcodeInfo::opcode_info.at(op).arg_types.at(arg_index);
|
||||
}
|
||||
|
||||
const char* GetNameOf(Opcode op) {
|
||||
return OpcodeInfo::opcode_info.at(op).name;
|
||||
}
|
||||
|
||||
} // namespace IR
|
||||
} // namespace Dynarmic
|
||||
|
|
@ -11,6 +11,10 @@
|
|||
namespace Dynarmic {
|
||||
namespace IR {
|
||||
|
||||
/**
|
||||
* The Opcodes of our intermediate representation.
|
||||
* Type signatures for each opcode can be found in opcodes.inc
|
||||
*/
|
||||
enum class Opcode {
|
||||
#define OPCODE(name, type, ...) name,
|
||||
#include "opcodes.inc"
|
||||
|
|
@ -20,5 +24,34 @@ enum class Opcode {
|
|||
|
||||
constexpr size_t OpcodeCount = static_cast<size_t>(Opcode::NUM_OPCODE);
|
||||
|
||||
/**
|
||||
* The intermediate representation is typed. These are the used by our IR.
|
||||
*/
|
||||
enum class Type {
|
||||
Void = 1 << 0,
|
||||
RegRef = 1 << 1,
|
||||
ExtRegRef = 1 << 2,
|
||||
Opaque = 1 << 3,
|
||||
U1 = 1 << 4,
|
||||
U8 = 1 << 5,
|
||||
U16 = 1 << 6,
|
||||
U32 = 1 << 7,
|
||||
U64 = 1 << 8,
|
||||
F32 = 1 << 9,
|
||||
F64 = 1 << 10,
|
||||
};
|
||||
|
||||
/// Get return type of an opcode
|
||||
Type GetTypeOf(Opcode op);
|
||||
|
||||
/// Get the number of arguments an opcode accepts
|
||||
size_t GetNumArgsOf(Opcode op);
|
||||
|
||||
/// Get the required type of an argument of an opcode
|
||||
Type GetArgTypeOf(Opcode op, size_t arg_index);
|
||||
|
||||
/// Get the name of an opcode.
|
||||
const char* GetNameOf(Opcode op);
|
||||
|
||||
} // namespace Arm
|
||||
} // namespace Dynarmic
|
||||
|
|
|
|||
|
|
@ -13,6 +13,12 @@ namespace Arm {
|
|||
|
||||
using MemoryRead32FuncType = u32 (*)(u32 vaddr);
|
||||
|
||||
/**
|
||||
* This function translates instructions in memory into our intermediate representation.
|
||||
* @param descriptor The starting location of the basic block. Includes information like PC, Thumb state, &c.
|
||||
* @param memory_read_32 The function we should use to read emulated memory.
|
||||
* @return A translated basic block in the intermediate representation.
|
||||
*/
|
||||
IR::Block Translate(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32);
|
||||
|
||||
} // namespace Arm
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue