mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-24 13:41:05 +00:00
Generates mov reg, reg
This commit is contained in:
parent
a91f373f36
commit
3731d28ca9
@ -3,6 +3,7 @@ set(SRCS
|
|||||||
CodeGen.cpp
|
CodeGen.cpp
|
||||||
ModuleGen.cpp
|
ModuleGen.cpp
|
||||||
Disassembler.cpp
|
Disassembler.cpp
|
||||||
|
InstructionBlock.cpp
|
||||||
|
|
||||||
Instructions/Instruction.cpp
|
Instructions/Instruction.cpp
|
||||||
Instructions/DataProcessing.cpp
|
Instructions/DataProcessing.cpp
|
||||||
@ -11,6 +12,7 @@ set(HEADERS
|
|||||||
CodeGen.h
|
CodeGen.h
|
||||||
ModuleGen.h
|
ModuleGen.h
|
||||||
Disassembler.h
|
Disassembler.h
|
||||||
|
InstructionBlock.h
|
||||||
|
|
||||||
Instructions/Types.h
|
Instructions/Types.h
|
||||||
Instructions/Instruction.h
|
Instructions/Instruction.h
|
||||||
|
49
src/binary_translation/InstructionBlock.cpp
Normal file
49
src/binary_translation/InstructionBlock.cpp
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#include "InstructionBlock.h"
|
||||||
|
#include "ModuleGen.h"
|
||||||
|
#include "Instructions/Instruction.h"
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
InstructionBlock::InstructionBlock(ModuleGen* module, Instruction* instruction)
|
||||||
|
: module(module),
|
||||||
|
instruction(std::unique_ptr<Instruction>(instruction))
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << std::hex << std::setfill('0') << std::setw(8) << instruction->Address();
|
||||||
|
address_string = ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
InstructionBlock::~InstructionBlock()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void InstructionBlock::GenerateEntryBlock()
|
||||||
|
{
|
||||||
|
entry_basic_block = llvm::BasicBlock::Create(llvm::getGlobalContext(), address_string + "_Entry");
|
||||||
|
}
|
||||||
|
|
||||||
|
void InstructionBlock::GenerateCode()
|
||||||
|
{
|
||||||
|
Module()->IrBuilder()->SetInsertPoint(entry_basic_block);
|
||||||
|
|
||||||
|
instruction->GenerateCode(this);
|
||||||
|
|
||||||
|
exit_basic_block = Module()->IrBuilder()->GetInsertBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Value *InstructionBlock::Read(Register reg)
|
||||||
|
{
|
||||||
|
auto ib = module->IrBuilder();
|
||||||
|
return ib->CreateAlignedLoad(module->GetRegisterPtr(reg), 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Value *InstructionBlock::Write(Register reg, llvm::Value *value)
|
||||||
|
{
|
||||||
|
auto ib = module->IrBuilder();
|
||||||
|
return ib->CreateAlignedStore(value, module->GetRegisterPtr(reg), 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t InstructionBlock::Address()
|
||||||
|
{
|
||||||
|
return instruction->Address();
|
||||||
|
}
|
64
src/binary_translation/InstructionBlock.h
Normal file
64
src/binary_translation/InstructionBlock.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace llvm
|
||||||
|
{
|
||||||
|
class Value;
|
||||||
|
class BasicBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ModuleGen;
|
||||||
|
class Instruction;
|
||||||
|
|
||||||
|
enum class Register;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An instruction blocks
|
||||||
|
* Holds the entry and exit points for an instruction
|
||||||
|
* Responsible to generate the code
|
||||||
|
*/
|
||||||
|
class InstructionBlock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InstructionBlock(ModuleGen *module, Instruction *instruction);
|
||||||
|
~InstructionBlock();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generates the basic block of the instruction
|
||||||
|
*/
|
||||||
|
void GenerateEntryBlock();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generates the code for the instruction
|
||||||
|
*/
|
||||||
|
void GenerateCode();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generates code to read the register
|
||||||
|
*/
|
||||||
|
llvm::Value *Read(Register reg);
|
||||||
|
/*
|
||||||
|
* Generates code to write the value
|
||||||
|
* Returns the write instruction = written value
|
||||||
|
*/
|
||||||
|
llvm::Value *Write(Register reg, llvm::Value *value);
|
||||||
|
|
||||||
|
size_t Address();
|
||||||
|
ModuleGen *Module() { return module; }
|
||||||
|
|
||||||
|
llvm::BasicBlock *GetEntryBasicBlock() { return entry_basic_block; }
|
||||||
|
llvm::BasicBlock *GetExitBasicBlock() { return exit_basic_block; }
|
||||||
|
private:
|
||||||
|
// Textual representation of the address
|
||||||
|
// Used to generate names
|
||||||
|
std::string address_string;
|
||||||
|
|
||||||
|
ModuleGen *module;
|
||||||
|
std::unique_ptr<Instruction> instruction;
|
||||||
|
|
||||||
|
// The block at the entry to instruction
|
||||||
|
llvm::BasicBlock *entry_basic_block;
|
||||||
|
|
||||||
|
// The block at the exit from the instruction
|
||||||
|
llvm::BasicBlock *exit_basic_block;
|
||||||
|
};
|
@ -1,15 +1,35 @@
|
|||||||
#include "DataProcessing.h"
|
#include "DataProcessing.h"
|
||||||
#include "Disassembler.h"
|
#include "Disassembler.h"
|
||||||
|
#include "InstructionBlock.h"
|
||||||
|
|
||||||
static RegisterInstruction<DataProcessing> register_instruction;
|
static RegisterInstruction<DataProcessing> register_instruction;
|
||||||
|
|
||||||
bool DataProcessing::Decode()
|
bool DataProcessing::Decode()
|
||||||
{
|
{
|
||||||
|
// Mov and shifts must have zeroes at some operands of different data processing instructions
|
||||||
|
if (ReadFields({ FieldDef<4>(&cond), FieldDef<3>(0), FieldDef<4>((u32)ShortOpType::MoveAndShifts), FieldDef<1>(&s), FieldDef<4>(0),
|
||||||
|
FieldDef<4>(&rd), FieldDef<5>(&imm5), FieldDef<3>(0), FieldDef<4>(&rm) }))
|
||||||
|
{
|
||||||
|
form = Form::Register;
|
||||||
|
if (imm5 != 0) return false; // Shifts
|
||||||
|
if (s != 0) return false; // Set flags
|
||||||
|
if (rd == Register::PC) return false; // Jump
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (ReadFields({ FieldDef<4>(&cond), FieldDef<3>(1), FieldDef<4>(&short_op), FieldDef<1>(&s), FieldDef<4>(&rn),
|
if (ReadFields({ FieldDef<4>(&cond), FieldDef<3>(1), FieldDef<4>(&short_op), FieldDef<1>(&s), FieldDef<4>(&rn),
|
||||||
FieldDef<4>(&rd), FieldDef<12>(&imm12) }))
|
FieldDef<4>(&rd), FieldDef<12>(&imm12) }))
|
||||||
{
|
{
|
||||||
|
// TODO: not implemented
|
||||||
form = Form::Immediate;
|
form = Form::Immediate;
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DataProcessing::GenerateCode(InstructionBlock* instruction_block)
|
||||||
|
{
|
||||||
|
// Currently supports only mov reg, reg
|
||||||
|
|
||||||
|
auto value = instruction_block->Read(rm);
|
||||||
|
instruction_block->Write(rd, value);
|
||||||
|
}
|
@ -16,7 +16,7 @@ public:
|
|||||||
{
|
{
|
||||||
BitwiseAnd = 0, BitwiseXor, Subtract, RevSubtract, Add, AddWithCarry, SubtractWithCarry, ReverseSubtractWithCarry,
|
BitwiseAnd = 0, BitwiseXor, Subtract, RevSubtract, Add, AddWithCarry, SubtractWithCarry, ReverseSubtractWithCarry,
|
||||||
// Compare, Test, Misc
|
// Compare, Test, Misc
|
||||||
BitwiseOr = 12, Move, BitwiseBitClear, BitwiseNot
|
BitwiseOr = 12, MoveAndShifts, BitwiseBitClear, BitwiseNot
|
||||||
};
|
};
|
||||||
enum class Form
|
enum class Form
|
||||||
{
|
{
|
||||||
@ -25,6 +25,7 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
virtual bool Decode() override;
|
virtual bool Decode() override;
|
||||||
|
void GenerateCode(InstructionBlock* instruction_block) override;
|
||||||
private:
|
private:
|
||||||
Form form;
|
Form form;
|
||||||
Condition cond;
|
Condition cond;
|
||||||
@ -32,5 +33,7 @@ private:
|
|||||||
bool s;
|
bool s;
|
||||||
Register rn;
|
Register rn;
|
||||||
Register rd;
|
Register rd;
|
||||||
|
Register rm;
|
||||||
u32 imm12;
|
u32 imm12;
|
||||||
|
u32 imm5;
|
||||||
};
|
};
|
@ -2,6 +2,8 @@
|
|||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
|
|
||||||
|
class InstructionBlock;
|
||||||
|
|
||||||
class Instruction
|
class Instruction
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
@ -15,9 +17,17 @@ public:
|
|||||||
* Returns true on success, or false otherwise
|
* Returns true on success, or false otherwise
|
||||||
*/
|
*/
|
||||||
bool Read(u32 instruction, u32 address);
|
bool Read(u32 instruction, u32 address);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generates code for the instruction into the instruction block
|
||||||
|
* Derived classes must override this
|
||||||
|
*/
|
||||||
|
virtual void GenerateCode(InstructionBlock *instruction_block) = 0;
|
||||||
|
|
||||||
|
u32 Address() { return address; }
|
||||||
protected:
|
protected:
|
||||||
/*
|
/*
|
||||||
* Derived classes should override this, and implement it by calling ReadFields
|
* Derived classes must override this, and implement it by calling ReadFields
|
||||||
*/
|
*/
|
||||||
virtual bool Decode() = 0;
|
virtual bool Decode() = 0;
|
||||||
/*
|
/*
|
||||||
@ -36,7 +46,6 @@ protected:
|
|||||||
*/
|
*/
|
||||||
template<size_t BitCount, typename Type>
|
template<size_t BitCount, typename Type>
|
||||||
static FieldDefObject FieldDef(Type *field);
|
static FieldDefObject FieldDef(Type *field);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*
|
/*
|
||||||
* Function used by FieldDefObject to write to a field
|
* Function used by FieldDefObject to write to a field
|
||||||
|
@ -3,8 +3,11 @@
|
|||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
#include "core/mem_map.h"
|
#include "core/mem_map.h"
|
||||||
#include "Instructions/Instruction.h"
|
#include "Instructions/Instruction.h"
|
||||||
|
#include "Instructions/Types.h"
|
||||||
|
#include "InstructionBlock.h"
|
||||||
#include <llvm/IR/Function.h>
|
#include <llvm/IR/Function.h>
|
||||||
#include <llvm/IR/GlobalVariable.h>
|
#include <llvm/IR/GlobalVariable.h>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
@ -21,10 +24,37 @@ ModuleGen::~ModuleGen()
|
|||||||
void ModuleGen::Run()
|
void ModuleGen::Run()
|
||||||
{
|
{
|
||||||
GenerateGlobals();
|
GenerateGlobals();
|
||||||
|
|
||||||
|
DecodeInstructions();
|
||||||
|
GenerateInstructionsEntry();
|
||||||
|
|
||||||
GenerateCanRunFunction();
|
GenerateCanRunFunction();
|
||||||
GenerateRunFunction();
|
GenerateRunFunction();
|
||||||
|
GenerateGetBlockAddressFunction();
|
||||||
|
|
||||||
GenerateBlocks();
|
GenerateInstructionsCode();
|
||||||
|
GenerateInstructionsTermination();
|
||||||
|
AddInstructionsToRunFunction();
|
||||||
|
|
||||||
|
GenerateBlockAddressArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
Value *ModuleGen::GetRegisterPtr(Register reg)
|
||||||
|
{
|
||||||
|
Value *global;
|
||||||
|
unsigned index;
|
||||||
|
if (reg <= Register::PC)
|
||||||
|
{
|
||||||
|
global = registers_global;
|
||||||
|
index = static_cast<unsigned>(reg)-static_cast<unsigned>(Register::R0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
global = flags_global;
|
||||||
|
index = static_cast<unsigned>(reg)-static_cast<unsigned>(Register::N);
|
||||||
|
}
|
||||||
|
auto base = ir_builder->CreateAlignedLoad(global, 4);
|
||||||
|
return ir_builder->CreateConstInBoundsGEP1_32(base, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModuleGen::GenerateGlobals()
|
void ModuleGen::GenerateGlobals()
|
||||||
@ -35,36 +65,193 @@ void ModuleGen::GenerateGlobals()
|
|||||||
// Flags is stored internally as i1* indexed in multiples of 4
|
// Flags is stored internally as i1* indexed in multiples of 4
|
||||||
auto flags_global_initializer = ConstantPointerNull::get(IntegerType::getInt1PtrTy(getGlobalContext()));
|
auto flags_global_initializer = ConstantPointerNull::get(IntegerType::getInt1PtrTy(getGlobalContext()));
|
||||||
flags_global = new GlobalVariable(*module, flags_global_initializer->getType(), false, GlobalValue::ExternalLinkage, flags_global_initializer, "Flags");
|
flags_global = new GlobalVariable(*module, flags_global_initializer->getType(), false, GlobalValue::ExternalLinkage, flags_global_initializer, "Flags");
|
||||||
|
|
||||||
|
auto get_block_address_function_type = FunctionType::get(ir_builder->getInt8PtrTy(), ir_builder->getInt32Ty(), false);
|
||||||
|
get_block_address_function = Function::Create(get_block_address_function_type, GlobalValue::PrivateLinkage, "GetBlockAddress", module);
|
||||||
|
|
||||||
|
auto can_run_function_type = FunctionType::get(ir_builder->getInt1Ty(), false);
|
||||||
|
can_run_function = Function::Create(can_run_function_type, GlobalValue::ExternalLinkage, "CanRun", module);
|
||||||
|
|
||||||
|
auto run_function_type = FunctionType::get(ir_builder->getVoidTy(), false);
|
||||||
|
run_function = Function::Create(run_function_type, GlobalValue::ExternalLinkage, "Run", module);
|
||||||
|
|
||||||
|
block_address_array_base = Loader::ROMCodeStart / 4;
|
||||||
|
block_address_array_size = Loader::ROMCodeSize / 4;
|
||||||
|
|
||||||
|
block_address_array_type = ArrayType::get(ir_builder->getInt8PtrTy(), block_address_array_size);
|
||||||
|
block_address_array = new GlobalVariable(*module, block_address_array_type, true, GlobalValue::ExternalLinkage, nullptr, "BlockAddressArray");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModuleGen::GenerateBlockAddressArray()
|
||||||
|
{
|
||||||
|
auto local_block_address_array_values = std::make_unique<Constant*[]>(block_address_array_size);
|
||||||
|
|
||||||
|
std::fill(
|
||||||
|
local_block_address_array_values.get(),
|
||||||
|
local_block_address_array_values.get() + block_address_array_size,
|
||||||
|
ConstantPointerNull::get(ir_builder->getInt8PtrTy()));
|
||||||
|
|
||||||
|
for (auto i = 0; i < instruction_blocks.size(); ++i)
|
||||||
|
{
|
||||||
|
auto &block = instruction_blocks[i];
|
||||||
|
auto entry_basic_block = block->GetEntryBasicBlock();
|
||||||
|
auto index = block->Address() / 4 - block_address_array_base;
|
||||||
|
local_block_address_array_values[index] = BlockAddress::get(entry_basic_block->getParent(), entry_basic_block);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto local_block_address_array_values_ref = ArrayRef<Constant*>(local_block_address_array_values.get(), block_address_array_size);
|
||||||
|
auto local_blocks_address_array = ConstantArray::get(block_address_array_type, local_block_address_array_values_ref);
|
||||||
|
block_address_array->setInitializer(local_blocks_address_array);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModuleGen::GenerateGetBlockAddressFunction()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
entry_basic_block:
|
||||||
|
auto index = (pc - block_address_array_base) / 4;
|
||||||
|
if(index < block_address_array_size)
|
||||||
|
{
|
||||||
|
index_in_bounds_basic_block:
|
||||||
|
return block_address_array[index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
index_out_of_bounds_basic_block:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
auto pc = &*get_block_address_function->arg_begin();
|
||||||
|
auto entry_basic_block = BasicBlock::Create(getGlobalContext(), "Entry", get_block_address_function);
|
||||||
|
auto index_in_bounds_basic_block = BasicBlock::Create(getGlobalContext(), "IndexInBounds", get_block_address_function);
|
||||||
|
auto index_out_of_bounds_basic_block = BasicBlock::Create(getGlobalContext(), "IndexOutOfBounds", get_block_address_function);
|
||||||
|
|
||||||
|
ir_builder->SetInsertPoint(entry_basic_block);
|
||||||
|
auto index = ir_builder->CreateUDiv(pc, ir_builder->getInt32(4));
|
||||||
|
index = ir_builder->CreateSub(index, ir_builder->getInt32(block_address_array_base));
|
||||||
|
auto in_bounds_pred = ir_builder->CreateICmpULT(index, ir_builder->getInt32(block_address_array_size));
|
||||||
|
ir_builder->CreateCondBr(in_bounds_pred, index_in_bounds_basic_block, index_out_of_bounds_basic_block);
|
||||||
|
|
||||||
|
ir_builder->SetInsertPoint(index_in_bounds_basic_block);
|
||||||
|
Value *gep_values[] = { ir_builder->getInt32(0), index };
|
||||||
|
auto block_address = ir_builder->CreateLoad(ir_builder->CreateInBoundsGEP(block_address_array, gep_values));
|
||||||
|
ir_builder->CreateRet(block_address);
|
||||||
|
|
||||||
|
ir_builder->SetInsertPoint(index_out_of_bounds_basic_block);
|
||||||
|
ir_builder->CreateRet(ConstantPointerNull::get(ir_builder->getInt8PtrTy()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModuleGen::GenerateCanRunFunction()
|
void ModuleGen::GenerateCanRunFunction()
|
||||||
{
|
{
|
||||||
auto can_run_function_type = FunctionType::get(ir_builder->getInt1Ty(), false);
|
// return GetBlockAddress(Read(PC)) != nullptr;
|
||||||
can_run_function = Function::Create(can_run_function_type, GlobalValue::ExternalLinkage, "CanRun", module);
|
|
||||||
auto basic_block = BasicBlock::Create(getGlobalContext(), "Entry", can_run_function);
|
auto basic_block = BasicBlock::Create(getGlobalContext(), "Entry", can_run_function);
|
||||||
|
|
||||||
ir_builder->SetInsertPoint(basic_block);
|
ir_builder->SetInsertPoint(basic_block);
|
||||||
ir_builder->CreateRet(ir_builder->getInt1(false));
|
auto block_address = ir_builder->CreateCall(get_block_address_function, ir_builder->CreateAlignedLoad(GetRegisterPtr(Register::PC), 4));
|
||||||
|
ir_builder->CreateRet(ir_builder->CreateICmpNE(block_address, ConstantPointerNull::get(ir_builder->getInt8PtrTy())));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModuleGen::GenerateRunFunction()
|
void ModuleGen::GenerateRunFunction()
|
||||||
{
|
{
|
||||||
auto run_function_type = FunctionType::get(ir_builder->getVoidTy(), false);
|
/*
|
||||||
run_function = Function::Create(run_function_type, GlobalValue::ExternalLinkage, "Run", module);
|
run_function_entry:
|
||||||
auto basic_block = BasicBlock::Create(getGlobalContext(), "Entry", run_function);
|
run_function_re_entry:
|
||||||
|
auto block_address = GetBlockAddress(Read(PC))
|
||||||
|
if(index != nullptr)
|
||||||
|
{
|
||||||
|
block_present_basic_block:
|
||||||
|
goto block_address;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
block_not_present_basic_block:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
run_function_entry = BasicBlock::Create(getGlobalContext(), "Entry", run_function);
|
||||||
|
// run_function_re_entry is needed because it isn't possible to jump to the first block of a function
|
||||||
|
run_function_re_entry = BasicBlock::Create(getGlobalContext(), "ReEntry", run_function);
|
||||||
|
auto block_present_basic_block = BasicBlock::Create(getGlobalContext(), "BlockPresent", run_function);
|
||||||
|
auto block_not_present_basic_block = BasicBlock::Create(getGlobalContext(), "BlockNotPresent", run_function);
|
||||||
|
|
||||||
ir_builder->SetInsertPoint(basic_block);
|
ir_builder->SetInsertPoint(run_function_entry);
|
||||||
|
ir_builder->CreateBr(run_function_re_entry);
|
||||||
|
|
||||||
|
ir_builder->SetInsertPoint(run_function_re_entry);
|
||||||
|
auto block_address = ir_builder->CreateCall(get_block_address_function, ir_builder->CreateAlignedLoad(GetRegisterPtr(Register::PC), 4));
|
||||||
|
auto block_present_pred = ir_builder->CreateICmpNE(block_address, ConstantPointerNull::get(ir_builder->getInt8PtrTy()));
|
||||||
|
ir_builder->CreateCondBr(block_present_pred, block_present_basic_block, block_not_present_basic_block);
|
||||||
|
|
||||||
|
ir_builder->SetInsertPoint(block_present_basic_block);
|
||||||
|
auto indirect_br = ir_builder->CreateIndirectBr(block_address, instruction_blocks.size());
|
||||||
|
for (auto &block : instruction_blocks)
|
||||||
|
{
|
||||||
|
indirect_br->addDestination(block->GetEntryBasicBlock());
|
||||||
|
}
|
||||||
|
|
||||||
|
ir_builder->SetInsertPoint(block_not_present_basic_block);
|
||||||
ir_builder->CreateRetVoid();
|
ir_builder->CreateRetVoid();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModuleGen::GenerateBlocks()
|
void ModuleGen::DecodeInstructions()
|
||||||
{
|
{
|
||||||
for (auto i = Loader::ROMCodeStart; i <= Loader::ROMCodeStart + Loader::ROMCodeSize - 4; i += 4)
|
for (auto i = Loader::ROMCodeStart; i <= Loader::ROMCodeStart + Loader::ROMCodeSize - 4; i += 4)
|
||||||
{
|
{
|
||||||
auto instruction = Disassembler::Disassemble(Memory::Read32(i), i);
|
auto instruction = Disassembler::Disassemble(Memory::Read32(i), i);
|
||||||
if (instruction != nullptr)
|
if (instruction == nullptr) continue;
|
||||||
|
auto instruction_block = std::make_unique<InstructionBlock>(this, instruction.release());
|
||||||
|
instruction_blocks_by_pc[i] = instruction_block.get();
|
||||||
|
instruction_blocks.push_back(std::move(instruction_block));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModuleGen::GenerateInstructionsEntry()
|
||||||
|
{
|
||||||
|
for (auto &instruction : instruction_blocks)
|
||||||
{
|
{
|
||||||
LOG_DEBUG(BinaryTranslator, "Instruction at %08x", i);
|
instruction->GenerateEntryBlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModuleGen::GenerateInstructionsCode()
|
||||||
|
{
|
||||||
|
for (auto &instruction : instruction_blocks)
|
||||||
|
{
|
||||||
|
instruction->GenerateCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModuleGen::GenerateInstructionsTermination()
|
||||||
|
{
|
||||||
|
// Return to the switch
|
||||||
|
for (auto &block : instruction_blocks)
|
||||||
|
{
|
||||||
|
ir_builder->SetInsertPoint(block->GetExitBasicBlock());
|
||||||
|
ir_builder->CreateAlignedStore(ir_builder->getInt32(block->Address() + 4), GetRegisterPtr(Register::PC), 4);
|
||||||
|
ir_builder->CreateBr(run_function_re_entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModuleGen::AddInstructionsToRunFunction()
|
||||||
|
{
|
||||||
|
std::stack<BasicBlock *> basic_blocks_stack;
|
||||||
|
|
||||||
|
for (auto &block : instruction_blocks)
|
||||||
|
{
|
||||||
|
basic_blocks_stack.push(block->GetEntryBasicBlock());
|
||||||
|
|
||||||
|
while (basic_blocks_stack.size())
|
||||||
|
{
|
||||||
|
auto basic_block = basic_blocks_stack.top();
|
||||||
|
basic_blocks_stack.pop();
|
||||||
|
basic_block->insertInto(run_function);
|
||||||
|
auto terminator = basic_block->getTerminator();
|
||||||
|
for (auto i = 0; i < terminator->getNumSuccessors(); ++i)
|
||||||
|
{
|
||||||
|
auto new_basic_block = terminator->getSuccessor(i);
|
||||||
|
if (new_basic_block->getParent()) continue; // Already added to run
|
||||||
|
basic_blocks_stack.push(new_basic_block);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,10 @@
|
|||||||
#include <llvm/IR/IRBuilder.h>
|
#include <llvm/IR/IRBuilder.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <common/common_types.h>
|
||||||
|
|
||||||
|
enum class Register;
|
||||||
|
|
||||||
|
class InstructionBlock;
|
||||||
|
|
||||||
namespace llvm
|
namespace llvm
|
||||||
{
|
{
|
||||||
@ -12,11 +18,30 @@ public:
|
|||||||
~ModuleGen();
|
~ModuleGen();
|
||||||
|
|
||||||
void Run();
|
void Run();
|
||||||
|
|
||||||
|
// Returns the address of a register or a flag
|
||||||
|
llvm::Value *GetRegisterPtr(Register reg);
|
||||||
|
|
||||||
|
llvm::IRBuilder<> *IrBuilder() { return ir_builder.get(); }
|
||||||
|
llvm::Module *Module() { return module; }
|
||||||
|
private:
|
||||||
|
// Generates the declarations of all the globals of the module
|
||||||
void GenerateGlobals();
|
void GenerateGlobals();
|
||||||
|
void GenerateBlockAddressArray();
|
||||||
|
void GenerateGetBlockAddressFunction();
|
||||||
void GenerateCanRunFunction();
|
void GenerateCanRunFunction();
|
||||||
void GenerateRunFunction();
|
void GenerateRunFunction();
|
||||||
void GenerateBlocks();
|
// Creates InstructionBlock for each instruction
|
||||||
private:
|
void DecodeInstructions();
|
||||||
|
// Generates the entry basic blocks for each instruction
|
||||||
|
void GenerateInstructionsEntry();
|
||||||
|
// Generates the code of each instruction
|
||||||
|
void GenerateInstructionsCode();
|
||||||
|
// Terminates each block
|
||||||
|
void GenerateInstructionsTermination();
|
||||||
|
// Adds all the basic blocks of an instruction to the run function
|
||||||
|
void AddInstructionsToRunFunction();
|
||||||
|
|
||||||
std::unique_ptr<llvm::IRBuilder<>> ir_builder;
|
std::unique_ptr<llvm::IRBuilder<>> ir_builder;
|
||||||
llvm::Module *module;
|
llvm::Module *module;
|
||||||
|
|
||||||
@ -31,6 +56,21 @@ private:
|
|||||||
* Orderered N, Z, C, V
|
* Orderered N, Z, C, V
|
||||||
*/
|
*/
|
||||||
llvm::GlobalVariable *flags_global;
|
llvm::GlobalVariable *flags_global;
|
||||||
|
|
||||||
|
size_t block_address_array_base;
|
||||||
|
size_t block_address_array_size;
|
||||||
|
/*
|
||||||
|
* i8 **BlockAddressArray;
|
||||||
|
* The array at [i/4 - block_address_array_base] contains the block address for the instruction at i
|
||||||
|
* or nullptr if it is not decoded
|
||||||
|
*/
|
||||||
|
llvm::ArrayType *block_address_array_type;
|
||||||
|
llvm::GlobalVariable *block_address_array;
|
||||||
|
/*
|
||||||
|
* i8 *GetBlockAddress(u32 pc)
|
||||||
|
* Returns the address of the block for the instruction at pc
|
||||||
|
*/
|
||||||
|
llvm::Function *get_block_address_function;
|
||||||
/*
|
/*
|
||||||
* bool CanRun()
|
* bool CanRun()
|
||||||
* Returns whether there is a binary translation available for a PC
|
* Returns whether there is a binary translation available for a PC
|
||||||
@ -41,4 +81,12 @@ private:
|
|||||||
* Runs binary translated opcodes
|
* Runs binary translated opcodes
|
||||||
*/
|
*/
|
||||||
llvm::Function *run_function;
|
llvm::Function *run_function;
|
||||||
|
llvm::BasicBlock *run_function_entry;
|
||||||
|
llvm::BasicBlock *run_function_re_entry;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All the instruction blocks
|
||||||
|
*/
|
||||||
|
std::vector<std::unique_ptr<InstructionBlock>> instruction_blocks;
|
||||||
|
std::unordered_map<u32, InstructionBlock *> instruction_blocks_by_pc;
|
||||||
};
|
};
|
Loading…
Reference in New Issue
Block a user