mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-24 11:51:04 +00:00
Added LDR
This commit is contained in:
parent
f8ca04f93f
commit
2839139250
@ -13,6 +13,7 @@ set(SRCS
|
|||||||
Instructions/MovShift.cpp
|
Instructions/MovShift.cpp
|
||||||
Instructions/Branch.cpp
|
Instructions/Branch.cpp
|
||||||
Instructions/Arithmetic.cpp
|
Instructions/Arithmetic.cpp
|
||||||
|
Instructions/Ldr.cpp
|
||||||
)
|
)
|
||||||
set(HEADERS
|
set(HEADERS
|
||||||
CodeGen.h
|
CodeGen.h
|
||||||
@ -30,6 +31,7 @@ set(HEADERS
|
|||||||
Instructions/MovShift.h
|
Instructions/MovShift.h
|
||||||
Instructions/Branch.h
|
Instructions/Branch.h
|
||||||
Instructions/Arithmetic.h
|
Instructions/Arithmetic.h
|
||||||
|
Instructions/Ldr.h
|
||||||
)
|
)
|
||||||
|
|
||||||
create_directory_groups(${SRCS} ${HEADERS})
|
create_directory_groups(${SRCS} ${HEADERS})
|
||||||
|
@ -49,8 +49,7 @@ public:
|
|||||||
* Creates a basic block for use by instructions
|
* Creates a basic block for use by instructions
|
||||||
*/
|
*/
|
||||||
llvm::BasicBlock *CreateBasicBlock(const char *name);
|
llvm::BasicBlock *CreateBasicBlock(const char *name);
|
||||||
|
/*
|
||||||
/*
|
|
||||||
* Links two instructions, adding to prev and next lists
|
* Links two instructions, adding to prev and next lists
|
||||||
*/
|
*/
|
||||||
static void Link(InstructionBlock *prev, InstructionBlock *next);
|
static void Link(InstructionBlock *prev, InstructionBlock *next);
|
||||||
|
@ -107,5 +107,5 @@ Instruction::FieldDefObject Instruction::FieldDef(Type* field)
|
|||||||
template <typename Type>
|
template <typename Type>
|
||||||
void Instruction::WriteFunction(u32 value, void *field_address)
|
void Instruction::WriteFunction(u32 value, void *field_address)
|
||||||
{
|
{
|
||||||
*static_cast<Type *>(field_address) = static_cast<Type>(value);
|
*static_cast<Type *>(field_address) = Type(value);
|
||||||
}
|
}
|
107
src/binary_translation/Instructions/Ldr.cpp
Normal file
107
src/binary_translation/Instructions/Ldr.cpp
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
#include "Ldr.h"
|
||||||
|
#include "Disassembler.h"
|
||||||
|
#include "InstructionBlock.h"
|
||||||
|
#include <llvm/IR/Value.h>
|
||||||
|
#include <core/loader/loader.h>
|
||||||
|
#include <core/mem_map.h>
|
||||||
|
#include "MachineState.h"
|
||||||
|
|
||||||
|
static RegisterInstruction<Ldr> register_instruction;
|
||||||
|
|
||||||
|
bool Ldr::Decode()
|
||||||
|
{
|
||||||
|
if (ReadFields({ CondDef(), FieldDef<4>(5), FieldDef<1>(&U), FieldDef<7>(0x1f),
|
||||||
|
FieldDef<4>(&rt), FieldDef<12>(&imm12)}))
|
||||||
|
{
|
||||||
|
form = Form::PC;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (ReadFields({ CondDef(), FieldDef<3>(2), FieldDef<1>(&P), FieldDef<1>(&U), FieldDef<1>(0), FieldDef<1>(&W), FieldDef<1>(1), FieldDef<4>(&rn),
|
||||||
|
FieldDef<4>(&rt), FieldDef<12>(&imm12) }))
|
||||||
|
{
|
||||||
|
form = Form::Reg;
|
||||||
|
|
||||||
|
if (!P && W) return false; // SEE LDRT;
|
||||||
|
if (rn == Register::SP && !P && U && !W && imm12 == 4) return false; // SEE POP;
|
||||||
|
if ((!P || W) && rn == rt) return false; // UNPREDICTABLE;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (ReadFields({ CondDef(), FieldDef<6>(0x22), FieldDef<1>(&W), FieldDef<1>(1), FieldDef<4>(&rn),
|
||||||
|
FieldDef<16>(®ister_list) }))
|
||||||
|
{
|
||||||
|
form = Form::MultiReg;
|
||||||
|
|
||||||
|
if (W && rn == Register::SP && register_list.size() > 1) return false; // SEE POP (ARM);
|
||||||
|
if (rn == Register::PC || register_list.size() < 1) return false; // UNPREDICTABLE;
|
||||||
|
if (W && register_list[(u32)rn]) return false; // UNPREDICTABLE;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ldr::GenerateInstructionCode(InstructionBlock* instruction_block)
|
||||||
|
{
|
||||||
|
auto ir_builder = instruction_block->IrBuilder();
|
||||||
|
|
||||||
|
if (form != Form::MultiReg)
|
||||||
|
{
|
||||||
|
llvm::Value *address = nullptr;
|
||||||
|
llvm::Value *value = nullptr;
|
||||||
|
|
||||||
|
auto add = (bool)U;
|
||||||
|
|
||||||
|
if (form == Form::PC)
|
||||||
|
{
|
||||||
|
auto base = instruction_block->Address() + 8;
|
||||||
|
auto constAddress = add ? base + imm12 : base - imm12;
|
||||||
|
auto constAddressEnd = constAddress + 4;
|
||||||
|
// If the value is read only, inline it
|
||||||
|
if (constAddress >= Loader::ROMCodeStart && constAddressEnd <= (Loader::ROMCodeStart + Loader::ROMCodeSize) ||
|
||||||
|
constAddress >= Loader::ROMReadOnlyDataStart && constAddressEnd <= (Loader::ROMReadOnlyDataStart + Loader::ROMReadOnlyDataSize))
|
||||||
|
{
|
||||||
|
value = ir_builder->getInt32(Memory::Read32(constAddress));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
address = ir_builder->getInt32(constAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto index = (bool)P;
|
||||||
|
auto wback = !P || W;
|
||||||
|
auto source_register = instruction_block->Read(rn);
|
||||||
|
auto imm32 = ir_builder->getInt32(add ? imm12 : -imm12);
|
||||||
|
|
||||||
|
auto offset_address = ir_builder->CreateAdd(source_register, imm32);
|
||||||
|
address = index ? offset_address : source_register;
|
||||||
|
if (wback)
|
||||||
|
instruction_block->Write(rn, offset_address);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!value) value = instruction_block->Module()->Machine()->ReadMemory32(address);
|
||||||
|
instruction_block->Write(rt, value);
|
||||||
|
|
||||||
|
if (rt == Register::PC)
|
||||||
|
instruction_block->Module()->BranchReadPC();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto wback = (bool)W;
|
||||||
|
auto address = instruction_block->Read(rn);
|
||||||
|
for (auto i = 0; i < 16; ++i)
|
||||||
|
{
|
||||||
|
if (!register_list[i]) continue;
|
||||||
|
instruction_block->Write((Register)i, instruction_block->Module()->Machine()->ReadMemory32(address));
|
||||||
|
address = ir_builder->CreateAdd(address, ir_builder->getInt32(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wback)
|
||||||
|
instruction_block->Write(rn, address);
|
||||||
|
|
||||||
|
if (register_list[15])
|
||||||
|
instruction_block->Module()->BranchReadPC();
|
||||||
|
}
|
||||||
|
}
|
26
src/binary_translation/Instructions/Ldr.h
Normal file
26
src/binary_translation/Instructions/Ldr.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include "Instruction.h"
|
||||||
|
#include "Types.h"
|
||||||
|
#include <bitset>
|
||||||
|
|
||||||
|
class Ldr : public Instruction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class Form
|
||||||
|
{
|
||||||
|
PC, Reg, MultiReg
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool Decode() override;
|
||||||
|
void GenerateInstructionCode(InstructionBlock* instruction_block) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Form form;
|
||||||
|
bool U;
|
||||||
|
Register rt;
|
||||||
|
u32 imm12;
|
||||||
|
bool P;
|
||||||
|
bool W;
|
||||||
|
Register rn;
|
||||||
|
std::bitset<16> register_list;
|
||||||
|
};
|
@ -23,6 +23,12 @@ void MachineState::GenerateGlobals()
|
|||||||
auto flags_global_initializer = ConstantPointerNull::get(IntegerType::getInt1PtrTy(getGlobalContext()));
|
auto flags_global_initializer = ConstantPointerNull::get(IntegerType::getInt1PtrTy(getGlobalContext()));
|
||||||
flags_global = new GlobalVariable(*module->Module(), flags_global_initializer->getType(),
|
flags_global = new GlobalVariable(*module->Module(), flags_global_initializer->getType(),
|
||||||
false, GlobalValue::ExternalLinkage, flags_global_initializer, "Flags");
|
false, GlobalValue::ExternalLinkage, flags_global_initializer, "Flags");
|
||||||
|
|
||||||
|
auto memory_read_32_signature = FunctionType::get(IntegerType::getInt32Ty(getGlobalContext()), IntegerType::getInt32Ty(getGlobalContext()), false);
|
||||||
|
auto memory_read_32_ptr = PointerType::get(memory_read_32_signature, 0);
|
||||||
|
auto memory_read_32_initializer = ConstantPointerNull::get(memory_read_32_ptr);
|
||||||
|
memory_read_32_global = new GlobalVariable(*module->Module(), memory_read_32_ptr,
|
||||||
|
false, GlobalValue::ExternalLinkage, memory_read_32_initializer, "Memory::Read32");
|
||||||
}
|
}
|
||||||
|
|
||||||
Value *MachineState::GetRegisterPtr(Register reg)
|
Value *MachineState::GetRegisterPtr(Register reg)
|
||||||
@ -87,4 +93,17 @@ Value* MachineState::ConditionPassed(Condition cond)
|
|||||||
|
|
||||||
if (not) pred = ir_builder->CreateNot(pred);
|
if (not) pred = ir_builder->CreateNot(pred);
|
||||||
return pred;
|
return pred;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Value* MachineState::ReadMemory32(llvm::Value* address)
|
||||||
|
{
|
||||||
|
auto ir_builder = module->IrBuilder();
|
||||||
|
|
||||||
|
auto memory_read_32 = ir_builder->CreateLoad(memory_read_32_global);
|
||||||
|
module->GetTBAA()->TagConst(memory_read_32);
|
||||||
|
|
||||||
|
auto call = ir_builder->CreateCall(memory_read_32, address);
|
||||||
|
call->setOnlyReadsMemory();
|
||||||
|
module->GetTBAA()->TagMemory(call);
|
||||||
|
return call;
|
||||||
}
|
}
|
@ -23,6 +23,7 @@ public:
|
|||||||
llvm::Value *ReadRegiser(Register reg);
|
llvm::Value *ReadRegiser(Register reg);
|
||||||
llvm::Value *WriteRegiser(Register reg, llvm::Value *value);
|
llvm::Value *WriteRegiser(Register reg, llvm::Value *value);
|
||||||
llvm::Value* ConditionPassed(Condition cond);
|
llvm::Value* ConditionPassed(Condition cond);
|
||||||
|
llvm::Value* ReadMemory32(llvm::Value* address);
|
||||||
private:
|
private:
|
||||||
// Returns the address of a register or a flag
|
// Returns the address of a register or a flag
|
||||||
llvm::Value *GetRegisterPtr(Register reg);
|
llvm::Value *GetRegisterPtr(Register reg);
|
||||||
@ -40,4 +41,10 @@ private:
|
|||||||
* Orderered N, Z, C, V
|
* Orderered N, Z, C, V
|
||||||
*/
|
*/
|
||||||
llvm::GlobalVariable *flags_global;
|
llvm::GlobalVariable *flags_global;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* u32 (u32) Memory::Read
|
||||||
|
* Reads the memory at address
|
||||||
|
*/
|
||||||
|
llvm::GlobalVariable *memory_read_32_global;
|
||||||
};
|
};
|
@ -21,6 +21,7 @@ void TBAA::GenerateTags()
|
|||||||
}
|
}
|
||||||
const_node = md_builder.createTBAAScalarTypeNode("Readonly", tbaa_root);
|
const_node = md_builder.createTBAAScalarTypeNode("Readonly", tbaa_root);
|
||||||
instruction_count_node = md_builder.createTBAAScalarTypeNode("InstructionCount", tbaa_root);
|
instruction_count_node = md_builder.createTBAAScalarTypeNode("InstructionCount", tbaa_root);
|
||||||
|
memory_node = md_builder.createTBAAScalarTypeNode("Memory", tbaa_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TBAA::TagRegister(Instruction* instruction, Register reg)
|
void TBAA::TagRegister(Instruction* instruction, Register reg)
|
||||||
@ -36,4 +37,9 @@ void TBAA::TagConst(Instruction* instruction)
|
|||||||
void TBAA::TagInstructionCount(llvm::Instruction* instruction)
|
void TBAA::TagInstructionCount(llvm::Instruction* instruction)
|
||||||
{
|
{
|
||||||
instruction->setMetadata(LLVMContext::MD_tbaa, instruction_count_node);
|
instruction->setMetadata(LLVMContext::MD_tbaa, instruction_count_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TBAA::TagMemory(llvm::Instruction* instruction)
|
||||||
|
{
|
||||||
|
instruction->setMetadata(LLVMContext::MD_tbaa, memory_node);
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "Instructions/Types.h"
|
#include "Instructions/Types.h"
|
||||||
|
#include <llvm/IR/Instructions.h>
|
||||||
|
|
||||||
namespace llvm
|
namespace llvm
|
||||||
{
|
{
|
||||||
@ -22,10 +23,12 @@ public:
|
|||||||
void TagRegister(llvm::Instruction *instruction, Register reg);
|
void TagRegister(llvm::Instruction *instruction, Register reg);
|
||||||
void TagConst(llvm::Instruction *instruction);
|
void TagConst(llvm::Instruction *instruction);
|
||||||
void TagInstructionCount(llvm::Instruction *instruction);
|
void TagInstructionCount(llvm::Instruction *instruction);
|
||||||
|
void TagMemory(llvm::Instruction *instruction);
|
||||||
private:
|
private:
|
||||||
llvm::MDNode *register_nodes[RegisterCount];
|
llvm::MDNode *register_nodes[RegisterCount];
|
||||||
// Tag for everything that is never written.
|
// Tag for everything that is never written.
|
||||||
// Since it is never written, one tag works
|
// Since it is never written, one tag works
|
||||||
llvm::MDNode *const_node;
|
llvm::MDNode *const_node;
|
||||||
llvm::MDNode *instruction_count_node;
|
llvm::MDNode *instruction_count_node;
|
||||||
|
llvm::MDNode *memory_node;
|
||||||
};
|
};
|
@ -6,6 +6,7 @@
|
|||||||
#include <llvm/Object/ObjectFile.h>
|
#include <llvm/Object/ObjectFile.h>
|
||||||
#include <llvm/ExecutionEngine/RuntimeDyld.h>
|
#include <llvm/ExecutionEngine/RuntimeDyld.h>
|
||||||
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
|
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
|
||||||
|
#include <core/mem_map.h>
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
@ -120,14 +121,16 @@ void BinaryTranslationLoader::Load(FileUtil::IOFile& file)
|
|||||||
g_can_run_function = static_cast<decltype(g_can_run_function)>(g_dyld->getSymbolAddress("CanRun"));
|
g_can_run_function = static_cast<decltype(g_can_run_function)>(g_dyld->getSymbolAddress("CanRun"));
|
||||||
auto verify_ptr = static_cast<bool*>(g_dyld->getSymbolAddress("Verify"));
|
auto verify_ptr = static_cast<bool*>(g_dyld->getSymbolAddress("Verify"));
|
||||||
g_instruction_count = static_cast<uint32_t *>(g_dyld->getSymbolAddress("InstructionCount"));
|
g_instruction_count = static_cast<uint32_t *>(g_dyld->getSymbolAddress("InstructionCount"));
|
||||||
|
auto memory_read_32_ptr = static_cast<decltype(&Memory::Read32) *>(g_dyld->getSymbolAddress("Memory::Read32"));
|
||||||
|
|
||||||
if (!g_run_function || !g_can_run_function || !verify_ptr || !g_instruction_count)
|
if (!g_run_function || !g_can_run_function || !verify_ptr || !g_instruction_count || !memory_read_32_ptr)
|
||||||
{
|
{
|
||||||
LOG_WARNING(Loader, "Cannot load optimized file, missing critical function");
|
LOG_WARNING(Loader, "Cannot load optimized file, missing critical function");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_verify = *verify_ptr;
|
g_verify = *verify_ptr;
|
||||||
|
*memory_read_32_ptr = &Memory::Read32;
|
||||||
|
|
||||||
g_enabled = true;
|
g_enabled = true;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user