diff --git a/TODO.md b/TODO.md index 63d7eaf4d..6da3e3464 100644 --- a/TODO.md +++ b/TODO.md @@ -1,24 +1,71 @@ +## Loader + +Set all function variable addresses to the thunks. Since we handle the thunks +specially the variables are just used as function pointer storage. + ## Kernel -NtAllocateVirtualMemory +Ordered: +``` +RtlInitializeCriticalSection/RtlInitializeCriticalSectionAndSpinCount +RtlEnterCriticalSection/RtlLeaveCriticalSection +XexCheckExecutablePrivilege +XGetAVPack +ExGetXConfigSetting +KeTlsAlloc +KeTlsSetValue +``` + +Others: +``` +NtQueryVirtualMemory + +KeTlsAlloc/KeTlsFree/KeTlsGetValue/KeTlsSetValue + +NtWaitForSingleObjectEx + +RtlInitUnicodeString/RtlFreeUnicodeString +RtlInitAnsiString/RtlFreeAnsiString +RtlUnicodeStringToAnsiString + +RtlCompareMemoryUlong +RtlNtStatusToDosError +RtlRaiseException + +NtCreateFile/NtOpenFile +NtReadFile/NtReadFileScatter +NtQueryFullAttributesFile +NtQueryInformationFile/NtSetInformationFile +NtQueryDirectoryFile/NtQueryVolumeInformationFile + +NtDuplicateObject + +KeBugCheck: +// VOID +// _In_ ULONG BugCheckCode +``` ## Instructions -### XER CA bit (carry) - -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. - ``` rlwimix rldiclx ``` +### XER CA bit (carry) + +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. + +### Overflow + Overflow bits can be set via the intrinsics: `llvm.sadd.with.overflow`/etc It'd be nice to avoid doing this unless absolutely required. The SDB could walk functions to see if they ever read or branch on the SO bit of things. +### Conditions + Condition bits are, after each function: ``` if (target_reg < 0) { CR0 = b100 | XER[SO] } @@ -31,9 +78,15 @@ For those, it would be nice to remove redundant sets. Maybe LLVM will do it automatically due to the local cr? May need to split that up into a few locals (one for each bit?) to ensure deduping. +### Branch Hinting + `@llvm.expect.i32`/`.i64` could be used with the BH bits in branches to indicate expected values. +### Data Caching + +dcbt and dcbtst could use LLVM intrinsic @llvm.prefetch. + ## Codegen ### Calling convention diff --git a/common.gypi b/common.gypi index 216b4dd41..f763641b4 100644 --- a/common.gypi +++ b/common.gypi @@ -12,7 +12,7 @@ # LLVM paths. # TODO(benvanik): switch based on configuration. - 'llvm_path': 'build/llvm/debug/', + 'llvm_path': 'build/llvm/release/', 'llvm_config': '<(llvm_path)bin/llvm-config', }, @@ -101,6 +101,7 @@ 'GCC_TREAT_WARNINGS_AS_ERRORS': 'YES', 'GCC_WARN_ABOUT_MISSING_NEWLINE': 'YES', 'WARNING_CFLAGS': ['-Wall', '-Wendif-labels'], + 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', }, }, } diff --git a/include/xenia/cpu/codegen/function_generator.h b/include/xenia/cpu/codegen/function_generator.h index 08eaeabdf..ca53a29cd 100644 --- a/include/xenia/cpu/codegen/function_generator.h +++ b/include/xenia/cpu/codegen/function_generator.h @@ -91,7 +91,7 @@ public: private: void GenerateSharedBlocks(); - void PrepareBasicBlock(sdb::FunctionBlock* block); + int PrepareBasicBlock(sdb::FunctionBlock* block); void GenerateBasicBlock(sdb::FunctionBlock* block); void SetupLocals(); diff --git a/private/runtest.sh b/private/runtest.sh index 5f6ab943d..af3e573ee 100755 --- a/private/runtest.sh +++ b/private/runtest.sh @@ -13,7 +13,7 @@ fi --memory_address_verification=true \ --trace_kernel_calls=true \ --trace_user_calls=true \ - --trace_instructions=true \ + --trace_instructions=false \ --abort_before_entry=true \ 1>build/run.txt #2>build/run.llvm.txt \ diff --git a/src/cpu/codegen/function_generator.cc b/src/cpu/codegen/function_generator.cc index b550a94d7..36a11dc99 100644 --- a/src/cpu/codegen/function_generator.cc +++ b/src/cpu/codegen/function_generator.cc @@ -152,7 +152,7 @@ void FunctionGenerator::GenerateBasicBlocks() { for (std::map::iterator it = fn_->blocks.begin(); it != fn_->blocks.end(); ++it) { FunctionBlock* block = it->second; - PrepareBasicBlock(block); + XEIGNORE(PrepareBasicBlock(block)); } // Setup all local variables now that we know what we need. @@ -217,7 +217,7 @@ void FunctionGenerator::GenerateSharedBlocks() { } } -void FunctionGenerator::PrepareBasicBlock(FunctionBlock* block) { +int FunctionGenerator::PrepareBasicBlock(FunctionBlock* block) { // Create the basic block that will end up getting filled during // generation. char name[32]; @@ -247,7 +247,11 @@ void FunctionGenerator::PrepareBasicBlock(FunctionBlock* block) { // and haven't implemented the disassemble method yet. ppc::InstrDisasm d; XEASSERTNOTNULL(i.type->disassemble); - XEASSERTZERO(i.type->disassemble(i, d)); + int result_code = i.type->disassemble(i, d); + XEASSERTZERO(result_code); + if (result_code) { + return result_code; + } // Accumulate access bits. access_bits.Extend(d.access_bits); @@ -255,6 +259,8 @@ void FunctionGenerator::PrepareBasicBlock(FunctionBlock* block) { // Add in access bits to function access bits. access_bits_.Extend(access_bits); + + return 0; } void FunctionGenerator::GenerateBasicBlock(FunctionBlock* block) { diff --git a/src/cpu/exec_module.cc b/src/cpu/exec_module.cc index 89e1d4651..cf07ac128 100644 --- a/src/cpu/exec_module.cc +++ b/src/cpu/exec_module.cc @@ -245,28 +245,46 @@ void XeIndirectBranch(xe_ppc_state_t* state, uint64_t target, uint64_t br_ia) { } void XeInvalidInstruction(xe_ppc_state_t* state, uint32_t cia, uint32_t data) { - // TODO(benvanik): handle better - XELOGCPU("INVALID INSTRUCTION %.8X %.8X", cia, 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("TRACE: %.8X -> k.%.8X (%s)", (uint32_t)call_ia - 4, (uint32_t)cia, + 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("TRACE: %.8X -> u.%.8X (%s)", (uint32_t)call_ia - 4, (uint32_t)cia, - fn->name); + 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("TRACE: %.8X %.8X %s %s", - cia, data, - type && type->emit ? " " : "X", - type ? type->name : ""); + XELOGCPU(XT("TRACE: %.8X %.8X %s %s"), + cia, data, + type && type->emit ? " " : "X", + type ? type->name : ""); // TODO(benvanik): better disassembly, printing of current register values/etc } diff --git a/xenia.gyp b/xenia.gyp index 56268de61..3a65a8e03 100644 --- a/xenia.gyp +++ b/xenia.gyp @@ -85,13 +85,12 @@ }], ['_type=="executable"', { 'libraries': [ - '