mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-24 12:01:04 +00:00
New class for machine state
This commit is contained in:
parent
49483c67ca
commit
3864675b6d
@ -4,6 +4,7 @@ set(SRCS
|
|||||||
ModuleGen.cpp
|
ModuleGen.cpp
|
||||||
Disassembler.cpp
|
Disassembler.cpp
|
||||||
InstructionBlock.cpp
|
InstructionBlock.cpp
|
||||||
|
MachineState.cpp
|
||||||
|
|
||||||
Instructions/Instruction.cpp
|
Instructions/Instruction.cpp
|
||||||
Instructions/DataProcessing.cpp
|
Instructions/DataProcessing.cpp
|
||||||
@ -13,6 +14,7 @@ set(HEADERS
|
|||||||
ModuleGen.h
|
ModuleGen.h
|
||||||
Disassembler.h
|
Disassembler.h
|
||||||
InstructionBlock.h
|
InstructionBlock.h
|
||||||
|
MachineState.h
|
||||||
|
|
||||||
Instructions/Types.h
|
Instructions/Types.h
|
||||||
Instructions/Instruction.h
|
Instructions/Instruction.h
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "Instructions/Instruction.h"
|
#include "Instructions/Instruction.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#include "MachineState.h"
|
||||||
|
|
||||||
InstructionBlock::InstructionBlock(ModuleGen* module, Instruction* instruction)
|
InstructionBlock::InstructionBlock(ModuleGen* module, Instruction* instruction)
|
||||||
: module(module),
|
: module(module),
|
||||||
@ -33,14 +34,12 @@ void InstructionBlock::GenerateCode()
|
|||||||
|
|
||||||
llvm::Value *InstructionBlock::Read(Register reg)
|
llvm::Value *InstructionBlock::Read(Register reg)
|
||||||
{
|
{
|
||||||
auto ib = module->IrBuilder();
|
return module->Machine()->ReadRegiser(reg);
|
||||||
return ib->CreateAlignedLoad(module->GetRegisterPtr(reg), 4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Value *InstructionBlock::Write(Register reg, llvm::Value *value)
|
llvm::Value *InstructionBlock::Write(Register reg, llvm::Value *value)
|
||||||
{
|
{
|
||||||
auto ib = module->IrBuilder();
|
return module->Machine()->WriteRegiser(reg, value);
|
||||||
return ib->CreateAlignedStore(value, module->GetRegisterPtr(reg), 4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t InstructionBlock::Address()
|
size_t InstructionBlock::Address()
|
||||||
|
55
src/binary_translation/MachineState.cpp
Normal file
55
src/binary_translation/MachineState.cpp
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#include "MachineState.h"
|
||||||
|
#include "ModuleGen.h"
|
||||||
|
#include "Instructions/Types.h"
|
||||||
|
#include <llvm/IR/GlobalValue.h>
|
||||||
|
#include <llvm/IR/Constants.h>
|
||||||
|
#include <llvm/IR/LLVMContext.h>
|
||||||
|
#include <llvm/IR/GlobalVariable.h>
|
||||||
|
|
||||||
|
using namespace llvm;
|
||||||
|
|
||||||
|
MachineState::MachineState(ModuleGen *module) : module(module)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void MachineState::GenerateGlobals()
|
||||||
|
{
|
||||||
|
auto registers_global_initializer = ConstantPointerNull::get(IntegerType::getInt32PtrTy(getGlobalContext()));
|
||||||
|
registers_global = new GlobalVariable(*module->Module(), registers_global_initializer->getType(),
|
||||||
|
false, GlobalValue::ExternalLinkage, registers_global_initializer, "Registers");
|
||||||
|
|
||||||
|
// Flags is stored internally as i1* indexed in multiples of 4
|
||||||
|
auto flags_global_initializer = ConstantPointerNull::get(IntegerType::getInt1PtrTy(getGlobalContext()));
|
||||||
|
flags_global = new GlobalVariable(*module->Module(), flags_global_initializer->getType(),
|
||||||
|
false, GlobalValue::ExternalLinkage, flags_global_initializer, "Flags");
|
||||||
|
}
|
||||||
|
|
||||||
|
Value* MachineState::ReadRegiser(Register reg)
|
||||||
|
{
|
||||||
|
auto load = module->IrBuilder()->CreateLoad(GetRegisterPtr(reg));
|
||||||
|
return load;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value* MachineState::WriteRegiser(Register reg, Value *value)
|
||||||
|
{
|
||||||
|
auto store = module->IrBuilder()->CreateAlignedStore(value, GetRegisterPtr(reg), 4);
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value *MachineState::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 = module->IrBuilder()->CreateAlignedLoad(global, 4);
|
||||||
|
return module->IrBuilder()->CreateConstInBoundsGEP1_32(base, index);
|
||||||
|
}
|
41
src/binary_translation/MachineState.h
Normal file
41
src/binary_translation/MachineState.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
|
||||||
|
enum class Register;
|
||||||
|
class ModuleGen;
|
||||||
|
|
||||||
|
namespace llvm
|
||||||
|
{
|
||||||
|
class Value;
|
||||||
|
class GlobalVariable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Contains all the machine state:
|
||||||
|
Registers, Flags, Memory
|
||||||
|
*/
|
||||||
|
class MachineState
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MachineState(ModuleGen *module);
|
||||||
|
|
||||||
|
void GenerateGlobals();
|
||||||
|
llvm::Value *ReadRegiser(Register reg);
|
||||||
|
llvm::Value *WriteRegiser(Register reg, llvm::Value *value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Returns the address of a register or a flag
|
||||||
|
llvm::Value *GetRegisterPtr(Register reg);
|
||||||
|
|
||||||
|
ModuleGen *module;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* u32 *Registers;
|
||||||
|
* The registers of the cpu
|
||||||
|
*/
|
||||||
|
llvm::GlobalVariable *registers_global;
|
||||||
|
/*
|
||||||
|
* u32 *Flags;
|
||||||
|
* The flags of the cpu
|
||||||
|
* Orderered N, Z, C, V
|
||||||
|
*/
|
||||||
|
llvm::GlobalVariable *flags_global;
|
||||||
|
};
|
@ -8,6 +8,7 @@
|
|||||||
#include <llvm/IR/Function.h>
|
#include <llvm/IR/Function.h>
|
||||||
#include <llvm/IR/GlobalVariable.h>
|
#include <llvm/IR/GlobalVariable.h>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
#include "MachineState.h"
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
@ -15,6 +16,7 @@ ModuleGen::ModuleGen(llvm::Module* module)
|
|||||||
: module(module)
|
: module(module)
|
||||||
{
|
{
|
||||||
ir_builder = make_unique<IRBuilder<>>(getGlobalContext());
|
ir_builder = make_unique<IRBuilder<>>(getGlobalContext());
|
||||||
|
machine = make_unique<MachineState>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
ModuleGen::~ModuleGen()
|
ModuleGen::~ModuleGen()
|
||||||
@ -39,32 +41,9 @@ void ModuleGen::Run()
|
|||||||
GenerateBlockAddressArray();
|
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()
|
||||||
{
|
{
|
||||||
auto registers_global_initializer = ConstantPointerNull::get(IntegerType::getInt32PtrTy(getGlobalContext()));
|
machine->GenerateGlobals();
|
||||||
registers_global = new GlobalVariable(*module, registers_global_initializer->getType(), false, GlobalValue::ExternalLinkage, registers_global_initializer, "Registers");
|
|
||||||
|
|
||||||
// Flags is stored internally as i1* indexed in multiples of 4
|
|
||||||
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");
|
|
||||||
|
|
||||||
auto get_block_address_function_type = FunctionType::get(ir_builder->getInt8PtrTy(), ir_builder->getInt32Ty(), false);
|
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);
|
get_block_address_function = Function::Create(get_block_address_function_type, GlobalValue::PrivateLinkage, "GetBlockAddress", module);
|
||||||
@ -146,7 +125,7 @@ void ModuleGen::GenerateCanRunFunction()
|
|||||||
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);
|
||||||
auto block_address = ir_builder->CreateCall(get_block_address_function, ir_builder->CreateAlignedLoad(GetRegisterPtr(Register::PC), 4));
|
auto block_address = ir_builder->CreateCall(get_block_address_function, machine->ReadRegiser(Register::PC));
|
||||||
ir_builder->CreateRet(ir_builder->CreateICmpNE(block_address, ConstantPointerNull::get(ir_builder->getInt8PtrTy())));
|
ir_builder->CreateRet(ir_builder->CreateICmpNE(block_address, ConstantPointerNull::get(ir_builder->getInt8PtrTy())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +157,7 @@ void ModuleGen::GenerateRunFunction()
|
|||||||
ir_builder->CreateBr(run_function_re_entry);
|
ir_builder->CreateBr(run_function_re_entry);
|
||||||
|
|
||||||
ir_builder->SetInsertPoint(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_address = ir_builder->CreateCall(get_block_address_function, Machine()->ReadRegiser(Register::PC));
|
||||||
auto block_present_pred = ir_builder->CreateICmpNE(block_address, ConstantPointerNull::get(ir_builder->getInt8PtrTy()));
|
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->CreateCondBr(block_present_pred, block_present_basic_block, block_not_present_basic_block);
|
||||||
|
|
||||||
@ -227,7 +206,7 @@ void ModuleGen::GenerateInstructionsTermination()
|
|||||||
for (auto &block : instruction_blocks)
|
for (auto &block : instruction_blocks)
|
||||||
{
|
{
|
||||||
ir_builder->SetInsertPoint(block->GetExitBasicBlock());
|
ir_builder->SetInsertPoint(block->GetExitBasicBlock());
|
||||||
ir_builder->CreateAlignedStore(ir_builder->getInt32(block->Address() + 4), GetRegisterPtr(Register::PC), 4);
|
Machine()->WriteRegiser(Register::PC, ir_builder->getInt32(block->Address() + 4));
|
||||||
ir_builder->CreateBr(run_function_re_entry);
|
ir_builder->CreateBr(run_function_re_entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
enum class Register;
|
enum class Register;
|
||||||
|
|
||||||
class InstructionBlock;
|
class InstructionBlock;
|
||||||
|
class MachineState;
|
||||||
|
|
||||||
namespace llvm
|
namespace llvm
|
||||||
{
|
{
|
||||||
@ -19,11 +20,10 @@ public:
|
|||||||
|
|
||||||
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::IRBuilder<> *IrBuilder() { return ir_builder.get(); }
|
||||||
llvm::Module *Module() { return module; }
|
llvm::Module *Module() { return module; }
|
||||||
|
MachineState *Machine() { return machine.get(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Generates the declarations of all the globals of the module
|
// Generates the declarations of all the globals of the module
|
||||||
void GenerateGlobals();
|
void GenerateGlobals();
|
||||||
@ -42,21 +42,11 @@ private:
|
|||||||
// Adds all the basic blocks of an instruction to the run function
|
// Adds all the basic blocks of an instruction to the run function
|
||||||
void AddInstructionsToRunFunction();
|
void AddInstructionsToRunFunction();
|
||||||
|
|
||||||
|
std::unique_ptr<MachineState> machine;
|
||||||
|
|
||||||
std::unique_ptr<llvm::IRBuilder<>> ir_builder;
|
std::unique_ptr<llvm::IRBuilder<>> ir_builder;
|
||||||
llvm::Module *module;
|
llvm::Module *module;
|
||||||
|
|
||||||
/*
|
|
||||||
* u32 *Registers;
|
|
||||||
* The registers of the cpu
|
|
||||||
*/
|
|
||||||
llvm::GlobalVariable *registers_global;
|
|
||||||
/*
|
|
||||||
* u32 *Flags;
|
|
||||||
* The flags of the cpu
|
|
||||||
* Orderered N, Z, C, V
|
|
||||||
*/
|
|
||||||
llvm::GlobalVariable *flags_global;
|
|
||||||
|
|
||||||
size_t block_address_array_base;
|
size_t block_address_array_base;
|
||||||
size_t block_address_array_size;
|
size_t block_address_array_size;
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user