Cleaning up LLVM exports and adding an access violation trap.
This commit is contained in:
parent
23378443e8
commit
2ecacedaa6
|
@ -85,9 +85,11 @@ public:
|
|||
void update_gpr_value(uint32_t n, llvm::Value* value);
|
||||
|
||||
llvm::Value* GetMembase();
|
||||
llvm::Value* GetMemoryAddress(llvm::Value* addr);
|
||||
llvm::Value* ReadMemory(llvm::Value* addr, uint32_t size, bool extend);
|
||||
void WriteMemory(llvm::Value* addr, uint32_t size, llvm::Value* value);
|
||||
llvm::Value* GetMemoryAddress(uint32_t cia, llvm::Value* addr);
|
||||
llvm::Value* ReadMemory(
|
||||
uint32_t cia, llvm::Value* addr, uint32_t size, bool extend);
|
||||
void WriteMemory(
|
||||
uint32_t cia, llvm::Value* addr, uint32_t size, llvm::Value* value);
|
||||
|
||||
private:
|
||||
void GenerateSharedBlocks();
|
||||
|
|
|
@ -47,7 +47,7 @@ XEEMITTER(lbz, 0x88000000, D )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
if (i.D.RA) {
|
||||
ea = b.CreateAdd(g.gpr_value(i.D.RA), ea);
|
||||
}
|
||||
Value* v = g.ReadMemory(ea, 1, false);
|
||||
Value* v = g.ReadMemory(i.address, ea, 1, false);
|
||||
g.update_gpr_value(i.D.RT, v);
|
||||
|
||||
return 0;
|
||||
|
@ -66,7 +66,7 @@ XEEMITTER(lbzu, 0x8C000000, D )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
// RA <- EA
|
||||
|
||||
Value* ea = b.CreateAdd(g.gpr_value(i.D.RA), b.getInt64(XEEXTS16(i.D.DS)));
|
||||
Value* v = g.ReadMemory(ea, 1, false);
|
||||
Value* v = g.ReadMemory(i.address, ea, 1, false);
|
||||
g.update_gpr_value(i.D.RT, v);
|
||||
g.update_gpr_value(i.D.RA, ea);
|
||||
|
||||
|
@ -86,7 +86,7 @@ XEEMITTER(lbzux, 0x7C0000EE, X )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
// RA <- EA
|
||||
|
||||
Value* ea = b.CreateAdd(g.gpr_value(i.X.RA), g.gpr_value(i.X.RB));
|
||||
Value* v = g.ReadMemory(ea, 1, false);
|
||||
Value* v = g.ReadMemory(i.address, ea, 1, false);
|
||||
g.update_gpr_value(i.X.RT, v);
|
||||
g.update_gpr_value(i.X.RA, ea);
|
||||
|
||||
|
@ -116,7 +116,7 @@ XEEMITTER(lbzx, 0x7C0000AE, X )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
if (i.X.RA) {
|
||||
ea = b.CreateAdd(g.gpr_value(i.X.RA), ea);
|
||||
}
|
||||
Value* v = g.ReadMemory(ea, 1, false);
|
||||
Value* v = g.ReadMemory(i.address, ea, 1, false);
|
||||
g.update_gpr_value(i.X.RT, v);
|
||||
|
||||
return 0;
|
||||
|
@ -145,7 +145,7 @@ XEEMITTER(ld, 0xE8000000, DS )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
if (i.DS.RA) {
|
||||
ea = b.CreateAdd(g.gpr_value(i.DS.RA), ea);
|
||||
}
|
||||
Value* v = g.ReadMemory(ea, 8, false);
|
||||
Value* v = g.ReadMemory(i.address, ea, 8, false);
|
||||
g.update_gpr_value(i.DS.RT, v);
|
||||
|
||||
return 0;
|
||||
|
@ -165,7 +165,7 @@ XEEMITTER(ldu, 0xE8000001, DS )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
|
||||
Value* ea = b.CreateAdd(g.gpr_value(i.DS.RA),
|
||||
b.getInt64(XEEXTS16(i.DS.DS << 2)));
|
||||
Value* v = g.ReadMemory(ea, 8, false);
|
||||
Value* v = g.ReadMemory(i.address, ea, 8, false);
|
||||
g.update_gpr_value(i.DS.RT, v);
|
||||
g.update_gpr_value(i.DS.RA, ea);
|
||||
|
||||
|
@ -225,7 +225,7 @@ XEEMITTER(lhz, 0xA0000000, D )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
if (i.D.RA) {
|
||||
ea = b.CreateAdd(g.gpr_value(i.D.RA), ea);
|
||||
}
|
||||
Value* v = g.ReadMemory(ea, 2, false);
|
||||
Value* v = g.ReadMemory(i.address, ea, 2, false);
|
||||
g.update_gpr_value(i.D.RT, v);
|
||||
|
||||
return 0;
|
||||
|
@ -284,7 +284,7 @@ XEEMITTER(lwz, 0x80000000, D )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
if (i.D.RA) {
|
||||
ea = b.CreateAdd(g.gpr_value(i.D.RA), ea);
|
||||
}
|
||||
Value* v = g.ReadMemory(ea, 4, false);
|
||||
Value* v = g.ReadMemory(i.address, ea, 4, false);
|
||||
g.update_gpr_value(i.D.RT, v);
|
||||
|
||||
return 0;
|
||||
|
@ -303,7 +303,7 @@ XEEMITTER(lwzu, 0x84000000, D )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
// RA <- EA
|
||||
|
||||
Value* ea = b.CreateAdd(g.gpr_value(i.D.RA), b.getInt64(XEEXTS16(i.D.DS)));
|
||||
Value* v = g.ReadMemory(ea, 4, false);
|
||||
Value* v = g.ReadMemory(i.address, ea, 4, false);
|
||||
g.update_gpr_value(i.D.RT, v);
|
||||
g.update_gpr_value(i.D.RA, ea);
|
||||
|
||||
|
@ -338,7 +338,7 @@ XEEMITTER(lwzx, 0x7C00002E, X )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
if (i.X.RA) {
|
||||
ea = b.CreateAdd(g.gpr_value(i.X.RA), ea);
|
||||
}
|
||||
Value* v = g.ReadMemory(ea, 4, false);
|
||||
Value* v = g.ReadMemory(i.address, ea, 4, false);
|
||||
g.update_gpr_value(i.X.RT, v);
|
||||
|
||||
return 0;
|
||||
|
@ -371,7 +371,7 @@ XEEMITTER(stb, 0x98000000, D )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
ea = b.CreateAdd(g.gpr_value(i.D.RA), ea);
|
||||
}
|
||||
Value* v = g.gpr_value(i.D.RT);
|
||||
g.WriteMemory(ea, 1, v);
|
||||
g.WriteMemory(i.address, ea, 1, v);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -390,7 +390,7 @@ XEEMITTER(stbu, 0x9C000000, D )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
|
||||
Value* ea = b.CreateAdd(g.gpr_value(i.D.RA), b.getInt64(XEEXTS16(i.D.DS)));
|
||||
Value* v = g.gpr_value(i.D.RT);
|
||||
g.WriteMemory(ea, 1, v);
|
||||
g.WriteMemory(i.address, ea, 1, v);
|
||||
g.update_gpr_value(i.D.RA, ea);
|
||||
|
||||
return 0;
|
||||
|
@ -430,7 +430,7 @@ XEEMITTER(std, 0xF8000000, DS )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
ea = b.CreateAdd(g.gpr_value(i.DS.RA), ea);
|
||||
}
|
||||
Value* v = g.gpr_value(i.DS.RT);
|
||||
g.WriteMemory(ea, 8, v);
|
||||
g.WriteMemory(i.address, ea, 8, v);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -450,7 +450,7 @@ XEEMITTER(stdu, 0xF8000001, DS )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
Value* ea = b.CreateAdd(g.gpr_value(i.DS.RA),
|
||||
b.getInt64(XEEXTS16(i.DS.DS << 2)));
|
||||
Value* v = g.gpr_value(i.DS.RT);
|
||||
g.WriteMemory(ea, 8, v);
|
||||
g.WriteMemory(i.address, ea, 8, v);
|
||||
g.update_gpr_value(i.DS.RA, ea);
|
||||
|
||||
return 0;
|
||||
|
@ -490,7 +490,7 @@ XEEMITTER(sth, 0xB0000000, D )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
ea = b.CreateAdd(g.gpr_value(i.D.RA), ea);
|
||||
}
|
||||
Value* v = g.gpr_value(i.D.RT);
|
||||
g.WriteMemory(ea, 2, v);
|
||||
g.WriteMemory(i.address, ea, 2, v);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -510,7 +510,7 @@ XEEMITTER(sthu, 0xB4000000, D )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
Value* ea = b.CreateAdd(g.gpr_value(i.D.RA),
|
||||
b.getInt64(XEEXTS16(i.D.DS)));
|
||||
Value* v = g.gpr_value(i.D.RT);
|
||||
g.WriteMemory(ea, 2, v);
|
||||
g.WriteMemory(i.address, ea, 2, v);
|
||||
g.update_gpr_value(i.D.RA, ea);
|
||||
|
||||
return 0;
|
||||
|
@ -545,7 +545,7 @@ XEEMITTER(sthx, 0x7C00032E, X )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
ea = b.CreateAdd(g.gpr_value(i.X.RA), ea);
|
||||
}
|
||||
Value* v = g.gpr_value(i.X.RT);
|
||||
g.WriteMemory(ea, 2, v);
|
||||
g.WriteMemory(i.address, ea, 2, v);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -574,7 +574,7 @@ XEEMITTER(stw, 0x90000000, D )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
ea = b.CreateAdd(g.gpr_value(i.D.RA), ea);
|
||||
}
|
||||
Value* v = g.gpr_value(i.D.RT);
|
||||
g.WriteMemory(ea, 4, v);
|
||||
g.WriteMemory(i.address, ea, 4, v);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -594,7 +594,7 @@ XEEMITTER(stwu, 0x94000000, D )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
Value* ea = b.CreateAdd(g.gpr_value(i.D.RA),
|
||||
b.getInt64(XEEXTS16(i.D.DS)));
|
||||
Value* v = g.gpr_value(i.D.RT);
|
||||
g.WriteMemory(ea, 4, v);
|
||||
g.WriteMemory(i.address, ea, 4, v);
|
||||
g.update_gpr_value(i.D.RA, ea);
|
||||
|
||||
return 0;
|
||||
|
@ -629,7 +629,7 @@ XEEMITTER(stwx, 0x7C00012E, X )(FunctionGenerator& g, IRBuilder<>& b, I
|
|||
ea = b.CreateAdd(g.gpr_value(i.X.RA), ea);
|
||||
}
|
||||
Value* v = g.gpr_value(i.X.RT);
|
||||
g.WriteMemory(ea, 4, v);
|
||||
g.WriteMemory(i.address, ea, 4, v);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -874,7 +874,7 @@ Value* FunctionGenerator::GetMembase() {
|
|||
return builder_->CreateLoad(v);
|
||||
}
|
||||
|
||||
Value* FunctionGenerator::GetMemoryAddress(Value* addr) {
|
||||
Value* FunctionGenerator::GetMemoryAddress(uint32_t cia, Value* addr) {
|
||||
IRBuilder<>& b = *builder_;
|
||||
|
||||
// Input address is always in 32-bit space.
|
||||
|
@ -890,9 +890,12 @@ Value* FunctionGenerator::GetMemoryAddress(Value* addr) {
|
|||
b.CreateCondBr(gt, valid_bb, invalid_bb);
|
||||
|
||||
b.SetInsertPoint(invalid_bb);
|
||||
Function* debugtrap = Intrinsic::getDeclaration(
|
||||
gen_module_, Intrinsic::debugtrap);
|
||||
b.CreateCall(debugtrap);
|
||||
Value* access_violation = gen_module_->getFunction("XeAccessViolation");
|
||||
SpillRegisters();
|
||||
b.CreateCall3(access_violation,
|
||||
gen_fn_->arg_begin(),
|
||||
b.getInt32(cia),
|
||||
addr);
|
||||
b.CreateBr(valid_bb);
|
||||
|
||||
b.SetInsertPoint(valid_bb);
|
||||
|
@ -902,7 +905,8 @@ Value* FunctionGenerator::GetMemoryAddress(Value* addr) {
|
|||
return b.CreateInBoundsGEP(GetMembase(), addr);
|
||||
}
|
||||
|
||||
Value* FunctionGenerator::ReadMemory(Value* addr, uint32_t size, bool extend) {
|
||||
Value* FunctionGenerator::ReadMemory(
|
||||
uint32_t cia, Value* addr, uint32_t size, bool extend) {
|
||||
IRBuilder<>& b = *builder_;
|
||||
|
||||
Type* dataTy = NULL;
|
||||
|
@ -929,7 +933,7 @@ Value* FunctionGenerator::ReadMemory(Value* addr, uint32_t size, bool extend) {
|
|||
}
|
||||
PointerType* pointerTy = PointerType::getUnqual(dataTy);
|
||||
|
||||
Value* address = GetMemoryAddress(addr);
|
||||
Value* address = GetMemoryAddress(cia, addr);
|
||||
Value* ptr = b.CreatePointerCast(address, pointerTy);
|
||||
Value* value = b.CreateLoad(ptr);
|
||||
|
||||
|
@ -944,7 +948,8 @@ Value* FunctionGenerator::ReadMemory(Value* addr, uint32_t size, bool extend) {
|
|||
return value;
|
||||
}
|
||||
|
||||
void FunctionGenerator::WriteMemory(Value* addr, uint32_t size, Value* value) {
|
||||
void FunctionGenerator::WriteMemory(
|
||||
uint32_t cia, Value* addr, uint32_t size, Value* value) {
|
||||
IRBuilder<>& b = *builder_;
|
||||
|
||||
Type* dataTy = NULL;
|
||||
|
@ -971,7 +976,7 @@ void FunctionGenerator::WriteMemory(Value* addr, uint32_t size, Value* value) {
|
|||
}
|
||||
PointerType* pointerTy = PointerType::getUnqual(dataTy);
|
||||
|
||||
Value* address = GetMemoryAddress(addr);
|
||||
Value* address = GetMemoryAddress(cia, addr);
|
||||
Value* ptr = b.CreatePointerCast(address, pointerTy);
|
||||
|
||||
// Truncate, if required.
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <xenia/cpu/ppc/state.h>
|
||||
|
||||
#include "cpu/cpu-private.h"
|
||||
#include "cpu/llvm_exports.h"
|
||||
#include "cpu/xethunk/xethunk.h"
|
||||
|
||||
|
||||
|
@ -217,13 +218,13 @@ int ExecModule::Prepare() {
|
|||
XEEXPECTZERO(Init());
|
||||
|
||||
// Force JIT of all functions.
|
||||
for (Module::iterator it = gen_module_->begin(); it != gen_module_->end();
|
||||
++it) {
|
||||
Function* fn = it;
|
||||
if (!fn->isDeclaration()) {
|
||||
engine_->getPointerToFunction(fn);
|
||||
}
|
||||
}
|
||||
// for (Module::iterator it = gen_module_->begin(); it != gen_module_->end();
|
||||
// ++it) {
|
||||
// Function* fn = it;
|
||||
// if (!fn->isDeclaration()) {
|
||||
// engine_->getPointerToFunction(fn);
|
||||
// }
|
||||
// }
|
||||
|
||||
result_code = 0;
|
||||
XECLEANUP:
|
||||
|
@ -234,61 +235,6 @@ void ExecModule::AddFunctionsToMap(FunctionMap& map) {
|
|||
codegen_->AddFunctionsToMap(map);
|
||||
}
|
||||
|
||||
void XeTrap(xe_ppc_state_t* state, uint32_t cia) {
|
||||
printf("TRAP");
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void XeIndirectBranch(xe_ppc_state_t* state, uint64_t target, uint64_t br_ia) {
|
||||
printf("INDIRECT BRANCH %.8X -> %.8X\n", (uint32_t)br_ia, (uint32_t)target);
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void XeInvalidInstruction(xe_ppc_state_t* state, uint32_t cia, uint32_t data) {
|
||||
ppc::InstrData i;
|
||||
i.address = cia;
|
||||
i.code = data;
|
||||
i.type = ppc::GetInstrType(i.code);
|
||||
|
||||
if (!i.type) {
|
||||
XELOGCPU(XT("INVALID INSTRUCTION %.8X: %.8X ???"),
|
||||
i.address, i.code);
|
||||
} else if (i.type->disassemble) {
|
||||
ppc::InstrDisasm d;
|
||||
i.type->disassemble(i, d);
|
||||
std::string disasm;
|
||||
d.Dump(disasm);
|
||||
XELOGCPU(XT("INVALID INSTRUCTION %.8X: %.8X %s"),
|
||||
i.address, i.code, disasm.c_str());
|
||||
} else {
|
||||
XELOGCPU(XT("INVALID INSTRUCTION %.8X: %.8X %s"),
|
||||
i.address, i.code, i.type->name);
|
||||
}
|
||||
}
|
||||
|
||||
void XeTraceKernelCall(xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia,
|
||||
KernelExport* kernel_export) {
|
||||
XELOGCPU(XT("TRACE: %.8X -> k.%.8X (%s)"),
|
||||
(uint32_t)call_ia - 4, (uint32_t)cia,
|
||||
kernel_export ? kernel_export->name : "unknown");
|
||||
}
|
||||
|
||||
void XeTraceUserCall(xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia,
|
||||
FunctionSymbol* fn) {
|
||||
XELOGCPU(XT("TRACE: %.8X -> u.%.8X (%s)"),
|
||||
(uint32_t)call_ia - 4, (uint32_t)cia, fn->name);
|
||||
}
|
||||
|
||||
void XeTraceInstruction(xe_ppc_state_t* state, uint32_t cia, uint32_t data) {
|
||||
ppc::InstrType* type = ppc::GetInstrType(data);
|
||||
XELOGCPU(XT("TRACE: %.8X %.8X %s %s"),
|
||||
cia, data,
|
||||
type && type->emit ? " " : "X",
|
||||
type ? type->name : "<unknown>");
|
||||
|
||||
// TODO(benvanik): better disassembly, printing of current register values/etc
|
||||
}
|
||||
|
||||
int ExecModule::InjectGlobals() {
|
||||
LLVMContext& context = *context_.get();
|
||||
const DataLayout* dl = engine_->getDataLayout();
|
||||
|
@ -311,61 +257,7 @@ int ExecModule::InjectGlobals() {
|
|||
ConstantInt::get(intPtrTy, (uintptr_t)xe_memory_addr(memory_, 0)),
|
||||
int8PtrTy));
|
||||
|
||||
// Control methods:
|
||||
std::vector<Type*> trapArgs;
|
||||
trapArgs.push_back(int8PtrTy);
|
||||
trapArgs.push_back(Type::getInt32Ty(context));
|
||||
FunctionType* trapTy = FunctionType::get(
|
||||
Type::getVoidTy(context), trapArgs, false);
|
||||
engine_->addGlobalMapping(Function::Create(
|
||||
trapTy, Function::ExternalLinkage, "XeTrap",
|
||||
gen_module_.get()), (void*)&XeTrap);
|
||||
|
||||
std::vector<Type*> indirectBranchArgs;
|
||||
indirectBranchArgs.push_back(int8PtrTy);
|
||||
indirectBranchArgs.push_back(Type::getInt64Ty(context));
|
||||
indirectBranchArgs.push_back(Type::getInt64Ty(context));
|
||||
FunctionType* indirectBranchTy = FunctionType::get(
|
||||
Type::getVoidTy(context), indirectBranchArgs, false);
|
||||
engine_->addGlobalMapping(Function::Create(
|
||||
indirectBranchTy, Function::ExternalLinkage, "XeIndirectBranch",
|
||||
gen_module_.get()), (void*)&XeIndirectBranch);
|
||||
|
||||
// Debugging methods:
|
||||
std::vector<Type*> invalidInstructionArgs;
|
||||
invalidInstructionArgs.push_back(int8PtrTy);
|
||||
invalidInstructionArgs.push_back(Type::getInt32Ty(context));
|
||||
invalidInstructionArgs.push_back(Type::getInt32Ty(context));
|
||||
FunctionType* invalidInstructionTy = FunctionType::get(
|
||||
Type::getVoidTy(context), invalidInstructionArgs, false);
|
||||
engine_->addGlobalMapping(Function::Create(
|
||||
invalidInstructionTy, Function::ExternalLinkage, "XeInvalidInstruction",
|
||||
gen_module_.get()), (void*)&XeInvalidInstruction);
|
||||
|
||||
// Tracing methods:
|
||||
std::vector<Type*> traceCallArgs;
|
||||
traceCallArgs.push_back(int8PtrTy);
|
||||
traceCallArgs.push_back(Type::getInt64Ty(context));
|
||||
traceCallArgs.push_back(Type::getInt64Ty(context));
|
||||
traceCallArgs.push_back(Type::getInt64Ty(context));
|
||||
FunctionType* traceCallTy = FunctionType::get(
|
||||
Type::getVoidTy(context), traceCallArgs, false);
|
||||
std::vector<Type*> traceInstructionArgs;
|
||||
traceInstructionArgs.push_back(int8PtrTy);
|
||||
traceInstructionArgs.push_back(Type::getInt32Ty(context));
|
||||
traceInstructionArgs.push_back(Type::getInt32Ty(context));
|
||||
FunctionType* traceInstructionTy = FunctionType::get(
|
||||
Type::getVoidTy(context), traceInstructionArgs, false);
|
||||
|
||||
engine_->addGlobalMapping(Function::Create(
|
||||
traceCallTy, Function::ExternalLinkage, "XeTraceKernelCall",
|
||||
gen_module_.get()), (void*)&XeTraceKernelCall);
|
||||
engine_->addGlobalMapping(Function::Create(
|
||||
traceCallTy, Function::ExternalLinkage, "XeTraceUserCall",
|
||||
gen_module_.get()), (void*)&XeTraceUserCall);
|
||||
engine_->addGlobalMapping(Function::Create(
|
||||
traceInstructionTy, Function::ExternalLinkage, "XeTraceInstruction",
|
||||
gen_module_.get()), (void*)&XeTraceInstruction);
|
||||
SetupLlvmExports(gen_module_.get(), dl, engine_.get());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "cpu/llvm_exports.h"
|
||||
|
||||
#include <llvm/ExecutionEngine/ExecutionEngine.h>
|
||||
#include <llvm/IR/Constants.h>
|
||||
#include <llvm/IR/DataLayout.h>
|
||||
#include <llvm/IR/DerivedTypes.h>
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
|
||||
#include <xenia/cpu/sdb.h>
|
||||
#include <xenia/cpu/ppc/instr.h>
|
||||
#include <xenia/cpu/ppc/state.h>
|
||||
#include <xenia/kernel/export.h>
|
||||
|
||||
|
||||
using namespace llvm;
|
||||
using namespace xe;
|
||||
using namespace xe::cpu;
|
||||
using namespace xe::cpu::sdb;
|
||||
using namespace xe::kernel;
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
void XeTrap(xe_ppc_state_t* state, uint32_t cia) {
|
||||
XELOGE(XT("TRAP"));
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void XeIndirectBranch(xe_ppc_state_t* state, uint64_t target, uint64_t br_ia) {
|
||||
XELOGCPU(XT("INDIRECT BRANCH %.8X -> %.8X"),
|
||||
(uint32_t)br_ia, (uint32_t)target);
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void XeInvalidInstruction(xe_ppc_state_t* state, uint32_t cia, uint32_t data) {
|
||||
ppc::InstrData i;
|
||||
i.address = cia;
|
||||
i.code = data;
|
||||
i.type = ppc::GetInstrType(i.code);
|
||||
|
||||
if (!i.type) {
|
||||
XELOGCPU(XT("INVALID INSTRUCTION %.8X: %.8X ???"),
|
||||
i.address, i.code);
|
||||
} else if (i.type->disassemble) {
|
||||
ppc::InstrDisasm d;
|
||||
i.type->disassemble(i, d);
|
||||
std::string disasm;
|
||||
d.Dump(disasm);
|
||||
XELOGCPU(XT("INVALID INSTRUCTION %.8X: %.8X %s"),
|
||||
i.address, i.code, disasm.c_str());
|
||||
} else {
|
||||
XELOGCPU(XT("INVALID INSTRUCTION %.8X: %.8X %s"),
|
||||
i.address, i.code, i.type->name);
|
||||
}
|
||||
}
|
||||
|
||||
void XeAccessViolation(xe_ppc_state_t* state, uint32_t cia, uint64_t ea) {
|
||||
XELOGE(XT("INVALID ACCESS %.8X: tried to touch %.8X"),
|
||||
cia, (uint32_t)ea);
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
|
||||
void XeTraceKernelCall(xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia,
|
||||
KernelExport* kernel_export) {
|
||||
XELOGCPU(XT("TRACE: %.8X -> k.%.8X (%s)"),
|
||||
(uint32_t)call_ia - 4, (uint32_t)cia,
|
||||
kernel_export ? kernel_export->name : "unknown");
|
||||
}
|
||||
|
||||
void XeTraceUserCall(xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia,
|
||||
FunctionSymbol* fn) {
|
||||
XELOGCPU(XT("TRACE: %.8X -> u.%.8X (%s)"),
|
||||
(uint32_t)call_ia - 4, (uint32_t)cia, fn->name);
|
||||
}
|
||||
|
||||
void XeTraceInstruction(xe_ppc_state_t* state, uint32_t cia, uint32_t data) {
|
||||
ppc::InstrType* type = ppc::GetInstrType(data);
|
||||
XELOGCPU(XT("TRACE: %.8X %.8X %s %s"),
|
||||
cia, data,
|
||||
type && type->emit ? " " : "X",
|
||||
type ? type->name : "<unknown>");
|
||||
|
||||
// TODO(benvanik): better disassembly, printing of current register values/etc
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void xe::cpu::SetupLlvmExports(llvm::Module* module,
|
||||
const llvm::DataLayout* dl,
|
||||
llvm::ExecutionEngine* engine) {
|
||||
LLVMContext& context = module->getContext();
|
||||
Type* int8PtrTy = PointerType::getUnqual(Type::getInt8Ty(context));
|
||||
|
||||
// Control methods:
|
||||
std::vector<Type*> trapArgs;
|
||||
trapArgs.push_back(int8PtrTy);
|
||||
trapArgs.push_back(Type::getInt32Ty(context));
|
||||
FunctionType* trapTy = FunctionType::get(
|
||||
Type::getVoidTy(context), trapArgs, false);
|
||||
engine->addGlobalMapping(Function::Create(
|
||||
trapTy, Function::ExternalLinkage, "XeTrap",
|
||||
module), (void*)&XeTrap);
|
||||
|
||||
std::vector<Type*> indirectBranchArgs;
|
||||
indirectBranchArgs.push_back(int8PtrTy);
|
||||
indirectBranchArgs.push_back(Type::getInt64Ty(context));
|
||||
indirectBranchArgs.push_back(Type::getInt64Ty(context));
|
||||
FunctionType* indirectBranchTy = FunctionType::get(
|
||||
Type::getVoidTy(context), indirectBranchArgs, false);
|
||||
engine->addGlobalMapping(Function::Create(
|
||||
indirectBranchTy, Function::ExternalLinkage, "XeIndirectBranch",
|
||||
module), (void*)&XeIndirectBranch);
|
||||
|
||||
// Debugging methods:
|
||||
std::vector<Type*> invalidInstructionArgs;
|
||||
invalidInstructionArgs.push_back(int8PtrTy);
|
||||
invalidInstructionArgs.push_back(Type::getInt32Ty(context));
|
||||
invalidInstructionArgs.push_back(Type::getInt32Ty(context));
|
||||
FunctionType* invalidInstructionTy = FunctionType::get(
|
||||
Type::getVoidTy(context), invalidInstructionArgs, false);
|
||||
engine->addGlobalMapping(Function::Create(
|
||||
invalidInstructionTy, Function::ExternalLinkage, "XeInvalidInstruction",
|
||||
module), (void*)&XeInvalidInstruction);
|
||||
|
||||
std::vector<Type*> accessViolationArgs;
|
||||
accessViolationArgs.push_back(int8PtrTy);
|
||||
accessViolationArgs.push_back(Type::getInt32Ty(context));
|
||||
accessViolationArgs.push_back(Type::getInt64Ty(context));
|
||||
FunctionType* accessViolationTy = FunctionType::get(
|
||||
Type::getVoidTy(context), accessViolationArgs, false);
|
||||
engine->addGlobalMapping(Function::Create(
|
||||
accessViolationTy, Function::ExternalLinkage, "XeAccessViolation",
|
||||
module), (void*)&XeAccessViolation);
|
||||
|
||||
// Tracing methods:
|
||||
std::vector<Type*> traceCallArgs;
|
||||
traceCallArgs.push_back(int8PtrTy);
|
||||
traceCallArgs.push_back(Type::getInt64Ty(context));
|
||||
traceCallArgs.push_back(Type::getInt64Ty(context));
|
||||
traceCallArgs.push_back(Type::getInt64Ty(context));
|
||||
FunctionType* traceCallTy = FunctionType::get(
|
||||
Type::getVoidTy(context), traceCallArgs, false);
|
||||
std::vector<Type*> traceInstructionArgs;
|
||||
traceInstructionArgs.push_back(int8PtrTy);
|
||||
traceInstructionArgs.push_back(Type::getInt32Ty(context));
|
||||
traceInstructionArgs.push_back(Type::getInt32Ty(context));
|
||||
FunctionType* traceInstructionTy = FunctionType::get(
|
||||
Type::getVoidTy(context), traceInstructionArgs, false);
|
||||
|
||||
engine->addGlobalMapping(Function::Create(
|
||||
traceCallTy, Function::ExternalLinkage, "XeTraceKernelCall",
|
||||
module), (void*)&XeTraceKernelCall);
|
||||
engine->addGlobalMapping(Function::Create(
|
||||
traceCallTy, Function::ExternalLinkage, "XeTraceUserCall",
|
||||
module), (void*)&XeTraceUserCall);
|
||||
engine->addGlobalMapping(Function::Create(
|
||||
traceInstructionTy, Function::ExternalLinkage, "XeTraceInstruction",
|
||||
module), (void*)&XeTraceInstruction);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_CPU_LLVM_EXPORTS_H_
|
||||
#define XENIA_CPU_LLVM_EXPORTS_H_
|
||||
|
||||
#include <xenia/common.h>
|
||||
#include <xenia/core.h>
|
||||
|
||||
|
||||
namespace llvm {
|
||||
class ExecutionEngine;
|
||||
class LLVMContext;
|
||||
class Module;
|
||||
class DataLayout;
|
||||
}
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
|
||||
|
||||
void SetupLlvmExports(llvm::Module* module,
|
||||
const llvm::DataLayout* dl,
|
||||
llvm::ExecutionEngine* engine);
|
||||
|
||||
|
||||
} // cpu
|
||||
} // xe
|
||||
|
||||
|
||||
#endif // XENIA_CPU_LLVM_EXPORTS_H_
|
|
@ -3,6 +3,7 @@
|
|||
'sources': [
|
||||
'cpu.cc',
|
||||
'exec_module.cc',
|
||||
'llvm_exports.cc',
|
||||
'processor.cc',
|
||||
'sdb.cc',
|
||||
'thread_state.cc',
|
||||
|
|
Loading…
Reference in New Issue