Executing a bunch of instructions!
Very hacky module startup code, but can now start XEXs! Time to start implementing kernel stuff.
This commit is contained in:
parent
92a3e19cd9
commit
46d5a0b51d
5
TODO.md
5
TODO.md
|
@ -6,14 +6,9 @@ Not sure the way I'm doing this is right. addic/subficx/etc set it to the value
|
||||||
of the overflow bit from the LLVM *_with_overflow intrinsic.
|
of the overflow bit from the LLVM *_with_overflow intrinsic.
|
||||||
|
|
||||||
```
|
```
|
||||||
MISDECODING: andix
|
|
||||||
|
|
||||||
rlwinmx
|
rlwinmx
|
||||||
rlwimix
|
rlwimix
|
||||||
rldiclx
|
rldiclx
|
||||||
|
|
||||||
slwx
|
|
||||||
srawix
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Overflow bits can be set via the intrinsics:
|
Overflow bits can be set via the intrinsics:
|
||||||
|
|
|
@ -9,7 +9,7 @@ fi
|
||||||
./build/xenia/release/xenia-run \
|
./build/xenia/release/xenia-run \
|
||||||
private/$1 \
|
private/$1 \
|
||||||
--optimize_ir_modules=true \
|
--optimize_ir_modules=true \
|
||||||
--optimize_ir_functions=false \
|
--optimize_ir_functions=true \
|
||||||
--trace_kernel_calls=true \
|
--trace_kernel_calls=true \
|
||||||
--trace_user_calls=false \
|
--trace_user_calls=false \
|
||||||
--trace_instructions=false \
|
--trace_instructions=false \
|
||||||
|
|
|
@ -539,7 +539,7 @@ XEEMITTER(andix, 0x70000000, D )(FunctionGenerator& g, IRBuilder<>& b, I
|
||||||
// With cr0 update.
|
// With cr0 update.
|
||||||
g.update_cr_with_cond(0, v, b.getInt64(0), true);
|
g.update_cr_with_cond(0, v, b.getInt64(0), true);
|
||||||
|
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
XEEMITTER(andisx, 0x74000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
|
XEEMITTER(andisx, 0x74000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
|
||||||
|
@ -805,7 +805,6 @@ XEEMITTER(rlwinmx, 0x54000000, M )(FunctionGenerator& g, IRBuilder<>& b, I
|
||||||
// g.update_cr_with_cond(0, v, b.getInt64(0), true);
|
// g.update_cr_with_cond(0, v, b.getInt64(0), true);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
printf("rlwinmx %d %d %d\n", i.M.SH, i.M.MB, i.M.ME);
|
|
||||||
XEINSTRNOTIMPLEMENTED();
|
XEINSTRNOTIMPLEMENTED();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,6 +173,7 @@ XEEMITTER(bcx, 0x40000000, B )(FunctionGenerator& g, IRBuilder<>& b, I
|
||||||
// Decrement counter.
|
// Decrement counter.
|
||||||
Value* ctr = g.ctr_value();
|
Value* ctr = g.ctr_value();
|
||||||
ctr = b.CreateSub(ctr, b.getInt64(1));
|
ctr = b.CreateSub(ctr, b.getInt64(1));
|
||||||
|
g.update_ctr_value(ctr);
|
||||||
|
|
||||||
// Ctr check.
|
// Ctr check.
|
||||||
if (XESELECTBITS(i.B.BO, 1, 1)) {
|
if (XESELECTBITS(i.B.BO, 1, 1)) {
|
||||||
|
@ -520,7 +521,7 @@ int XeEmitTrap(FunctionGenerator& g, IRBuilder<>& b, InstrData& i,
|
||||||
b.SetInsertPoint(trap_bb);
|
b.SetInsertPoint(trap_bb);
|
||||||
g.SpillRegisters();
|
g.SpillRegisters();
|
||||||
// TODO(benvanik): use @llvm.debugtrap? could make debugging better
|
// TODO(benvanik): use @llvm.debugtrap? could make debugging better
|
||||||
b.CreateCall2(g.gen_module()->getGlobalVariable("XeTrap"),
|
b.CreateCall2(g.gen_module()->getFunction("XeTrap"),
|
||||||
g.gen_fn()->arg_begin(),
|
g.gen_fn()->arg_begin(),
|
||||||
b.getInt32(i.address));
|
b.getInt32(i.address));
|
||||||
b.CreateBr(after_bb);
|
b.CreateBr(after_bb);
|
||||||
|
|
|
@ -117,7 +117,7 @@ void FunctionGenerator::GenerateBasicBlocks() {
|
||||||
|
|
||||||
if (FLAGS_trace_user_calls) {
|
if (FLAGS_trace_user_calls) {
|
||||||
SpillRegisters();
|
SpillRegisters();
|
||||||
Value* traceUserCall = gen_module_->getGlobalVariable("XeTraceUserCall");
|
Value* traceUserCall = gen_module_->getFunction("XeTraceUserCall");
|
||||||
builder_->CreateCall3(
|
builder_->CreateCall3(
|
||||||
traceUserCall,
|
traceUserCall,
|
||||||
gen_fn_->arg_begin(),
|
gen_fn_->arg_begin(),
|
||||||
|
@ -162,7 +162,7 @@ void FunctionGenerator::GenerateBasicBlocks() {
|
||||||
void FunctionGenerator::GenerateSharedBlocks() {
|
void FunctionGenerator::GenerateSharedBlocks() {
|
||||||
IRBuilder<>& b = *builder_;
|
IRBuilder<>& b = *builder_;
|
||||||
|
|
||||||
Value* indirect_branch = gen_module_->getGlobalVariable("XeIndirectBranch");
|
Value* indirect_branch = gen_module_->getFunction("XeIndirectBranch");
|
||||||
|
|
||||||
// Setup initial register fill in the entry block.
|
// Setup initial register fill in the entry block.
|
||||||
// We can only do this once all the locals have been created.
|
// We can only do this once all the locals have been created.
|
||||||
|
@ -218,9 +218,9 @@ void FunctionGenerator::GenerateBasicBlock(FunctionBlock* block,
|
||||||
//i->setMetadata("some.name", MDNode::get(context, MDString::get(context, pname)));
|
//i->setMetadata("some.name", MDNode::get(context, MDString::get(context, pname)));
|
||||||
|
|
||||||
Value* invalidInstruction =
|
Value* invalidInstruction =
|
||||||
gen_module_->getGlobalVariable("XeInvalidInstruction");
|
gen_module_->getFunction("XeInvalidInstruction");
|
||||||
Value* traceInstruction =
|
Value* traceInstruction =
|
||||||
gen_module_->getGlobalVariable("XeTraceInstruction");
|
gen_module_->getFunction("XeTraceInstruction");
|
||||||
|
|
||||||
// Walk instructions in block.
|
// Walk instructions in block.
|
||||||
uint8_t* p = xe_memory_addr(memory_, 0);
|
uint8_t* p = xe_memory_addr(memory_, 0);
|
||||||
|
@ -390,7 +390,7 @@ int FunctionGenerator::GenerateIndirectionBranch(uint32_t cia, Value* target,
|
||||||
SpillRegisters();
|
SpillRegisters();
|
||||||
|
|
||||||
// TODO(benvanik): keep function pointer lookup local.
|
// TODO(benvanik): keep function pointer lookup local.
|
||||||
Value* indirect_branch = gen_module_->getGlobalVariable("XeIndirectBranch");
|
Value* indirect_branch = gen_module_->getFunction("XeIndirectBranch");
|
||||||
b.CreateCall3(indirect_branch,
|
b.CreateCall3(indirect_branch,
|
||||||
gen_fn_->arg_begin(),
|
gen_fn_->arg_begin(),
|
||||||
target,
|
target,
|
||||||
|
@ -861,6 +861,9 @@ Value* FunctionGenerator::ReadMemory(Value* addr, uint32_t size, bool extend) {
|
||||||
}
|
}
|
||||||
PointerType* pointerTy = PointerType::getUnqual(dataTy);
|
PointerType* pointerTy = PointerType::getUnqual(dataTy);
|
||||||
|
|
||||||
|
// Input address is always in 32-bit space.
|
||||||
|
addr = b.CreateAnd(addr, UINT_MAX);
|
||||||
|
|
||||||
Value* offset_addr = b.CreateAdd(addr, b.getInt64(size));
|
Value* offset_addr = b.CreateAdd(addr, b.getInt64(size));
|
||||||
Value* address = b.CreateInBoundsGEP(GetMembase(), offset_addr);
|
Value* address = b.CreateInBoundsGEP(GetMembase(), offset_addr);
|
||||||
Value* ptr = b.CreatePointerCast(address, pointerTy);
|
Value* ptr = b.CreatePointerCast(address, pointerTy);
|
||||||
|
@ -890,6 +893,9 @@ void FunctionGenerator::WriteMemory(Value* addr, uint32_t size, Value* value) {
|
||||||
}
|
}
|
||||||
PointerType* pointerTy = PointerType::getUnqual(dataTy);
|
PointerType* pointerTy = PointerType::getUnqual(dataTy);
|
||||||
|
|
||||||
|
// Input address is always in 32-bit space.
|
||||||
|
addr = b.CreateAnd(addr, UINT_MAX);
|
||||||
|
|
||||||
Value* offset_addr = b.CreateAdd(addr, b.getInt64(size));
|
Value* offset_addr = b.CreateAdd(addr, b.getInt64(size));
|
||||||
Value* address = b.CreateInBoundsGEP(GetMembase(), offset_addr);
|
Value* address = b.CreateInBoundsGEP(GetMembase(), offset_addr);
|
||||||
Value* ptr = b.CreatePointerCast(address, pointerTy);
|
Value* ptr = b.CreatePointerCast(address, pointerTy);
|
||||||
|
|
|
@ -77,7 +77,7 @@ int ModuleGenerator::Generate() {
|
||||||
}
|
}
|
||||||
di_builder_ = new DIBuilder(*gen_module_);
|
di_builder_ = new DIBuilder(*gen_module_);
|
||||||
di_builder_->createCompileUnit(
|
di_builder_->createCompileUnit(
|
||||||
0,
|
dwarf::DW_LANG_C99, //0x8010,
|
||||||
StringRef(module_name_),
|
StringRef(module_name_),
|
||||||
StringRef(dir),
|
StringRef(dir),
|
||||||
StringRef("xenia"),
|
StringRef("xenia"),
|
||||||
|
@ -196,7 +196,7 @@ void ModuleGenerator::AddMissingImport(FunctionSymbol* fn) {
|
||||||
IRBuilder<> builder(block);
|
IRBuilder<> builder(block);
|
||||||
|
|
||||||
if (FLAGS_trace_kernel_calls) {
|
if (FLAGS_trace_kernel_calls) {
|
||||||
Value* traceKernelCall = m->getGlobalVariable("XeTraceKernelCall");
|
Value* traceKernelCall = m->getFunction("XeTraceKernelCall");
|
||||||
builder.CreateCall3(
|
builder.CreateCall3(
|
||||||
traceKernelCall,
|
traceKernelCall,
|
||||||
f->arg_begin(),
|
f->arg_begin(),
|
||||||
|
|
|
@ -240,12 +240,12 @@ void XeInvalidInstruction(xe_ppc_state_t* state, uint32_t cia, uint32_t data) {
|
||||||
|
|
||||||
void XeTraceKernelCall(xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia) {
|
void XeTraceKernelCall(xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia) {
|
||||||
// TODO(benvanik): get names
|
// TODO(benvanik): get names
|
||||||
XELOGCPU("TRACE: %.8X -> k.%.8X", (uint32_t)call_ia, (uint32_t)cia);
|
XELOGCPU("TRACE: %.8X -> k.%.8X", (uint32_t)call_ia - 4, (uint32_t)cia);
|
||||||
}
|
}
|
||||||
|
|
||||||
void XeTraceUserCall(xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia) {
|
void XeTraceUserCall(xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia) {
|
||||||
// TODO(benvanik): get names
|
// TODO(benvanik): get names
|
||||||
XELOGCPU("TRACE: %.8X -> u.%.8X", (uint32_t)call_ia, (uint32_t)cia);
|
XELOGCPU("TRACE: %.8X -> u.%.8X", (uint32_t)call_ia - 4, (uint32_t)cia);
|
||||||
}
|
}
|
||||||
|
|
||||||
void XeTraceInstruction(xe_ppc_state_t* state, uint32_t cia, uint32_t data) {
|
void XeTraceInstruction(xe_ppc_state_t* state, uint32_t cia, uint32_t data) {
|
||||||
|
@ -286,10 +286,9 @@ int ExecModule::InjectGlobals() {
|
||||||
trapArgs.push_back(Type::getInt32Ty(context));
|
trapArgs.push_back(Type::getInt32Ty(context));
|
||||||
FunctionType* trapTy = FunctionType::get(
|
FunctionType* trapTy = FunctionType::get(
|
||||||
Type::getVoidTy(context), trapArgs, false);
|
Type::getVoidTy(context), trapArgs, false);
|
||||||
gv = new GlobalVariable(*gen_module_, trapTy, true,
|
engine_->addGlobalMapping(Function::Create(
|
||||||
GlobalVariable::ExternalLinkage, 0,
|
trapTy, Function::ExternalLinkage, "XeTrap",
|
||||||
"XeTrap");
|
gen_module_.get()), (void*)&XeTrap);
|
||||||
engine_->addGlobalMapping(gv, (void*)&XeTrap);
|
|
||||||
|
|
||||||
std::vector<Type*> indirectBranchArgs;
|
std::vector<Type*> indirectBranchArgs;
|
||||||
indirectBranchArgs.push_back(int8PtrTy);
|
indirectBranchArgs.push_back(int8PtrTy);
|
||||||
|
@ -297,10 +296,9 @@ int ExecModule::InjectGlobals() {
|
||||||
indirectBranchArgs.push_back(Type::getInt64Ty(context));
|
indirectBranchArgs.push_back(Type::getInt64Ty(context));
|
||||||
FunctionType* indirectBranchTy = FunctionType::get(
|
FunctionType* indirectBranchTy = FunctionType::get(
|
||||||
Type::getVoidTy(context), indirectBranchArgs, false);
|
Type::getVoidTy(context), indirectBranchArgs, false);
|
||||||
gv = new GlobalVariable(*gen_module_, indirectBranchTy, true,
|
engine_->addGlobalMapping(Function::Create(
|
||||||
GlobalVariable::ExternalLinkage, 0,
|
indirectBranchTy, Function::ExternalLinkage, "XeIndirectBranch",
|
||||||
"XeIndirectBranch");
|
gen_module_.get()), (void*)&XeIndirectBranch);
|
||||||
engine_->addGlobalMapping(gv, (void*)&XeIndirectBranch);
|
|
||||||
|
|
||||||
// Debugging methods:
|
// Debugging methods:
|
||||||
std::vector<Type*> invalidInstructionArgs;
|
std::vector<Type*> invalidInstructionArgs;
|
||||||
|
@ -309,10 +307,9 @@ int ExecModule::InjectGlobals() {
|
||||||
invalidInstructionArgs.push_back(Type::getInt32Ty(context));
|
invalidInstructionArgs.push_back(Type::getInt32Ty(context));
|
||||||
FunctionType* invalidInstructionTy = FunctionType::get(
|
FunctionType* invalidInstructionTy = FunctionType::get(
|
||||||
Type::getVoidTy(context), invalidInstructionArgs, false);
|
Type::getVoidTy(context), invalidInstructionArgs, false);
|
||||||
gv = new GlobalVariable(*gen_module_, invalidInstructionTy, true,
|
engine_->addGlobalMapping(Function::Create(
|
||||||
GlobalVariable::ExternalLinkage, 0,
|
invalidInstructionTy, Function::ExternalLinkage, "XeInvalidInstruction",
|
||||||
"XeInvalidInstruction");
|
gen_module_.get()), (void*)&XeInvalidInstruction);
|
||||||
engine_->addGlobalMapping(gv, (void*)&XeInvalidInstruction);
|
|
||||||
|
|
||||||
// Tracing methods:
|
// Tracing methods:
|
||||||
std::vector<Type*> traceCallArgs;
|
std::vector<Type*> traceCallArgs;
|
||||||
|
@ -328,18 +325,15 @@ int ExecModule::InjectGlobals() {
|
||||||
FunctionType* traceInstructionTy = FunctionType::get(
|
FunctionType* traceInstructionTy = FunctionType::get(
|
||||||
Type::getVoidTy(context), traceInstructionArgs, false);
|
Type::getVoidTy(context), traceInstructionArgs, false);
|
||||||
|
|
||||||
gv = new GlobalVariable(*gen_module_, traceCallTy, true,
|
engine_->addGlobalMapping(Function::Create(
|
||||||
GlobalValue::ExternalLinkage, 0,
|
traceCallTy, Function::ExternalLinkage, "XeTraceKernelCall",
|
||||||
"XeTraceKernelCall");
|
gen_module_.get()), (void*)&XeTraceKernelCall);
|
||||||
engine_->addGlobalMapping(gv, (void*)&XeTraceKernelCall);
|
engine_->addGlobalMapping(Function::Create(
|
||||||
gv = new GlobalVariable(*gen_module_, traceCallTy, true,
|
traceCallTy, Function::ExternalLinkage, "XeTraceUserCall",
|
||||||
GlobalValue::ExternalLinkage, 0,
|
gen_module_.get()), (void*)&XeTraceUserCall);
|
||||||
"XeTraceUserCall");
|
engine_->addGlobalMapping(Function::Create(
|
||||||
engine_->addGlobalMapping(gv, (void*)&XeTraceUserCall);
|
traceInstructionTy, Function::ExternalLinkage, "XeTraceInstruction",
|
||||||
gv = new GlobalVariable(*gen_module_, traceInstructionTy, true,
|
gen_module_.get()), (void*)&XeTraceInstruction);
|
||||||
GlobalValue::ExternalLinkage, 0,
|
|
||||||
"XeTraceInstruction");
|
|
||||||
engine_->addGlobalMapping(gv, (void*)&XeTraceInstruction);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ int Processor::Setup() {
|
||||||
std::string error_message;
|
std::string error_message;
|
||||||
engine_ = shared_ptr<ExecutionEngine>(
|
engine_ = shared_ptr<ExecutionEngine>(
|
||||||
ExecutionEngine::create(dummy_module, false, &error_message,
|
ExecutionEngine::create(dummy_module, false, &error_message,
|
||||||
CodeGenOpt::Aggressive));
|
CodeGenOpt::Aggressive, false));
|
||||||
if (!engine_) {
|
if (!engine_) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
|
|
||||||
using namespace xe;
|
using namespace xe;
|
||||||
|
using namespace xe::cpu;
|
||||||
using namespace xe::kernel;
|
using namespace xe::kernel;
|
||||||
|
|
||||||
|
|
||||||
|
@ -131,13 +132,11 @@ XECLEANUP:
|
||||||
}
|
}
|
||||||
|
|
||||||
void Runtime::LaunchModule(UserModule* user_module) {
|
void Runtime::LaunchModule(UserModule* user_module) {
|
||||||
//const xe_xex2_header_t *xex_header = xe_module_get_xex_header(module);
|
const xe_xex2_header_t *xex_header = user_module->xex_header();
|
||||||
|
|
||||||
// TODO(benvanik): set as main module/etc
|
// TODO(benvanik): set as main module/etc
|
||||||
// xekXexExecutableModuleHandle = xe_module_get_handle(module);
|
// xekXexExecutableModuleHandle = xe_module_get_handle(module);
|
||||||
|
|
||||||
// XEEXPECTTRUE(XECPUPrepareModule(XEGetCPU(), module->xex, module->pe, module->address_space, module->address_space_size));
|
|
||||||
|
|
||||||
// Setup the heap (and TLS?).
|
// Setup the heap (and TLS?).
|
||||||
// xex_header->exe_heap_size;
|
// xex_header->exe_heap_size;
|
||||||
|
|
||||||
|
@ -149,6 +148,19 @@ void Runtime::LaunchModule(UserModule* user_module) {
|
||||||
// Wait until thread completes.
|
// Wait until thread completes.
|
||||||
// XLARGE_INTEGER timeout = XINFINITE;
|
// XLARGE_INTEGER timeout = XINFINITE;
|
||||||
// xekNtWaitForSingleObjectEx(thread_handle, TRUE, &timeout);
|
// xekNtWaitForSingleObjectEx(thread_handle, TRUE, &timeout);
|
||||||
|
|
||||||
|
// Simulate a thread.
|
||||||
|
uint32_t stack_size = xex_header->exe_stack_size;
|
||||||
|
if (stack_size < 16 * 1024 * 1024) {
|
||||||
|
stack_size = 16 * 1024 * 1024;
|
||||||
|
}
|
||||||
|
ThreadState* thread_state = processor_->AllocThread(
|
||||||
|
0x80000000, stack_size);
|
||||||
|
|
||||||
|
// Execute test.
|
||||||
|
processor_->Execute(thread_state, xex_header->exe_entry_point);
|
||||||
|
|
||||||
|
processor_->DeallocThread(thread_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
UserModule* Runtime::GetModule(const xechar_t* path) {
|
UserModule* Runtime::GetModule(const xechar_t* path) {
|
||||||
|
|
Loading…
Reference in New Issue