diff --git a/src/binary_translation/CMakeLists.txt b/src/binary_translation/CMakeLists.txt index 089e952b5..a71ba222f 100644 --- a/src/binary_translation/CMakeLists.txt +++ b/src/binary_translation/CMakeLists.txt @@ -2,10 +2,14 @@ set(SRCS main.cpp CodeGen.cpp ModuleGen.cpp + Disassembler.cpp + Instruction.cpp ) set(HEADERS CodeGen.h ModuleGen.h + Disassembler.h + Instruction.h ) create_directory_groups(${SRCS} ${HEADERS}) diff --git a/src/binary_translation/Disassembler.cpp b/src/binary_translation/Disassembler.cpp new file mode 100644 index 000000000..1884c3a70 --- /dev/null +++ b/src/binary_translation/Disassembler.cpp @@ -0,0 +1,23 @@ +#include "Disassembler.h" +#include "Instruction.h" +#include + +std::vector g_read_functions; + +RegisterInstructionBase::RegisterInstructionBase(CreateFunctionType create_function) +{ + g_read_functions.push_back(create_function); +} + +std::unique_ptr Disassmbler::Disassemble(u32 instruction, u32 address) +{ + for (auto read_function : g_read_functions) + { + auto result = read_function(instruction, address); + if (result != nullptr) + { + return std::unique_ptr(result); + } + } + return nullptr; +} \ No newline at end of file diff --git a/src/binary_translation/Disassembler.h b/src/binary_translation/Disassembler.h new file mode 100644 index 000000000..aef3469a6 --- /dev/null +++ b/src/binary_translation/Disassembler.h @@ -0,0 +1,43 @@ +#include "common/common_types.h" +#include + +class Instruction; + +class Disassmbler +{ +public: + /* + * Returns the instruction at address or null if unknown or not translatable + * address is used for PC relative operations + */ + static std::unique_ptr Disassemble(u32 instruction, u32 address); +}; + +class RegisterInstructionBase +{ +public: + typedef Instruction *(*CreateFunctionType)(u32 instruction, u32 address); + + RegisterInstructionBase(CreateFunctionType create_function); +}; + +/* + * Instantiate this class in a source file to register instruction in the disassembler + */ +template +class RegisterInstruction : RegisterInstructionBase +{ +public: + RegisterInstruction() : RegisterInstructionBase(&RegisterInstruction::Create) {} +private: + static Instruction *Create(u32 instruction, u32 address) + { + auto result = new DerivedInstruction(instruction, address); + if (!result->Read()) + { + delete result; + return nullptr; + } + return result; + } +}; \ No newline at end of file diff --git a/src/binary_translation/Instruction.cpp b/src/binary_translation/Instruction.cpp new file mode 100644 index 000000000..f7960e36a --- /dev/null +++ b/src/binary_translation/Instruction.cpp @@ -0,0 +1,52 @@ +#include "Instruction.h" +#include + +Instruction::Instruction(u32 instruction, u32 address) : instruction(instruction), address(address) +{ +} + +Instruction::~Instruction() +{ +} + +bool Instruction::ReadFields(const std::initializer_list &fields) +{ + size_t total_bit_count = 0; + auto current_instruction = instruction; + + for (auto &field : fields) + { + total_bit_count += field.BitCount(); + // Read the upper bits + auto value = current_instruction >> (32 - field.BitCount()); + if (!field.Read(value)) return false; + // Remove the upper bits + current_instruction <<= field.BitCount(); + } + assert(total_bit_count == 32); + + return true; +} + +Instruction::FieldDefObject::FieldDefObject(u32 bit_count, u32 const_value) + : bit_count(bit_count), const_value(const_value), constant(true) +{ +} + +Instruction::FieldDefObject::FieldDefObject(u32 bit_count, void* field_address, WriteFunctionType write_function) + : bit_count(bit_count), field_address(field_address), write_function(write_function), constant(false) +{ +} + +bool Instruction::FieldDefObject::Read(u32 value) const +{ + if (constant) + { + return value == const_value; + } + else + { + write_function(value, field_address); + return true; + } +} \ No newline at end of file diff --git a/src/binary_translation/Instruction.h b/src/binary_translation/Instruction.h new file mode 100644 index 000000000..c784d1f86 --- /dev/null +++ b/src/binary_translation/Instruction.h @@ -0,0 +1,87 @@ +#pragma once +#include "common/common_types.h" +#include + +class Instruction +{ +protected: + class FieldDefObject; +public: + Instruction(u32 instruction, u32 address); + virtual ~Instruction(); + + /* + * Reads the instruction. + * Returns true on success, or false otherwise + */ + virtual bool Read() = 0; +protected: + /* + * Reads fields from the instruction + * The fields come most significant first + */ + bool ReadFields(const std::initializer_list &fields); + + /* + * Creates a field definition for a constant + */ + template + static FieldDefObject FieldDef(u32 value); + /* + * Creates a field definition for a field + */ + template + static FieldDefObject FieldDef(Type *field); + +private: + /* + * Function used by FieldDefObject to write to a field + */ + template + static void WriteFunction(u32 value, void *field_address); + + // Instruction value + u32 instruction; + // Instruction address + u32 address; +}; + +/* + * Object produced by FieldDef + */ +class Instruction::FieldDefObject +{ +public: + typedef void(*WriteFunctionType)(u32 value, void *field_address); +public: + // Constant + FieldDefObject(u32 bit_count, u32 const_value); + // Field + FieldDefObject(u32 bit_count, void *field_address, WriteFunctionType write_function); + bool Read(u32 value) const; + u32 BitCount() const { return bit_count; } +private: + u32 bit_count; + u32 const_value; + void *field_address; + WriteFunctionType write_function; + bool constant; +}; + +template +Instruction::FieldDefObject Instruction::FieldDef(u32 value) +{ + return FieldDefObject(BitCount, value); +} + +template +Instruction::FieldDefObject Instruction::FieldDef(Type* field) +{ + return FieldDefObject(BitCount, field, &Instruction::WriteFunction); +} + +template +void Instruction::WriteFunction(u32 value, void *field_address) +{ + *static_cast(field_address) = static_cast(value); +} \ No newline at end of file