From 8e92a4b55b0ca092aec860b9cca4f3913b63353f Mon Sep 17 00:00:00 2001 From: uytvbn Date: Tue, 24 Oct 2017 22:00:39 +0200 Subject: [PATCH 01/17] [Linux] Fix binutils path for gentests --- xenia-build | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xenia-build b/xenia-build index 1cf41601b..0d8f92d82 100755 --- a/xenia-build +++ b/xenia-build @@ -938,7 +938,10 @@ class GenTestsCommand(Command): print('Generating test binaries...') print('') - binutils_path = os.path.join('third_party', 'binutils-ppc-cygwin') + if sys.platform == 'win32': + binutils_path = os.path.join('third_party', 'binutils-ppc-cygwin') + else: + binutils_path = os.path.join('third_party', 'binutils', 'bin') ppc_as = os.path.join(binutils_path, 'powerpc-none-elf-as') ppc_ld = os.path.join(binutils_path, 'powerpc-none-elf-ld') ppc_objdump = os.path.join(binutils_path, 'powerpc-none-elf-objdump') From 7186af388ace3b6b204d0486bcdec1ca75fb170c Mon Sep 17 00:00:00 2001 From: uytvbn Date: Tue, 24 Oct 2017 22:01:35 +0200 Subject: [PATCH 02/17] [Linux] Implement exception handler --- src/xenia/base/exception_handler_posix.cc | 133 +++++++++++++++++++++- 1 file changed, 129 insertions(+), 4 deletions(-) diff --git a/src/xenia/base/exception_handler_posix.cc b/src/xenia/base/exception_handler_posix.cc index 5c3aa81f0..49c556ee5 100644 --- a/src/xenia/base/exception_handler_posix.cc +++ b/src/xenia/base/exception_handler_posix.cc @@ -9,10 +9,135 @@ #include "xenia/base/exception_handler.h" +#include +#include + namespace xe { -// TODO(DrChat): Exception handling on linux. -void ExceptionHandler::Install(Handler fn, void* data) {} -void ExceptionHandler::Uninstall(Handler fn, void* data) {} +bool signal_handlers_installed_ = false; +struct sigaction original_sigill_handler_; +struct sigaction original_sigsegv_handler_; -} // namespace xe \ No newline at end of file +// This can be as large as needed, but isn't often needed. +// As we will be sometimes firing many exceptions we want to avoid having to +// scan the table too much or invoke many custom handlers. +constexpr size_t kMaxHandlerCount = 8; + +// All custom handlers, left-aligned and null terminated. +// Executed in order. +std::pair handlers_[kMaxHandlerCount]; + +void ExceptionHandlerCallback(int signum, siginfo_t* siginfo, void* sigctx) { + ucontext_t* ctx = static_cast(sigctx); + + X64Context thread_context; + + thread_context.rip = ctx->uc_mcontext.gregs[REG_RIP]; + thread_context.eflags = ctx->uc_mcontext.gregs[REG_EFL]; + thread_context.rax = ctx->uc_mcontext.gregs[REG_RAX]; + thread_context.rcx = ctx->uc_mcontext.gregs[REG_RCX]; + thread_context.rdx = ctx->uc_mcontext.gregs[REG_RDX]; + thread_context.rbx = ctx->uc_mcontext.gregs[REG_RBX]; + thread_context.rsp = ctx->uc_mcontext.gregs[REG_RSP]; + thread_context.rbp = ctx->uc_mcontext.gregs[REG_RBP]; + thread_context.rsi = ctx->uc_mcontext.gregs[REG_RSI]; + thread_context.rdi = ctx->uc_mcontext.gregs[REG_RDI]; + thread_context.r8 = ctx->uc_mcontext.gregs[REG_R8]; + thread_context.r9 = ctx->uc_mcontext.gregs[REG_R9]; + thread_context.r10 = ctx->uc_mcontext.gregs[REG_R10]; + thread_context.r11 = ctx->uc_mcontext.gregs[REG_R11]; + thread_context.r12 = ctx->uc_mcontext.gregs[REG_R12]; + thread_context.r13 = ctx->uc_mcontext.gregs[REG_R13]; + thread_context.r14 = ctx->uc_mcontext.gregs[REG_R14]; + thread_context.r15 = ctx->uc_mcontext.gregs[REG_R15]; + std::memcpy(thread_context.xmm_registers, ctx->uc_mcontext.fpregs->_xmm, + sizeof(thread_context.xmm_registers)); + + Exception ex; + switch (signum) { + case SIGILL: + ex.InitializeIllegalInstruction(&thread_context); + break; + case SIGSEGV: { + Exception::AccessViolationOperation access_violation_operation = + ((ucontext_t*)sigctx)->uc_mcontext.gregs[REG_ERR] & 0x2 + ? Exception::AccessViolationOperation::kRead + : Exception::AccessViolationOperation::kWrite; + ex.InitializeAccessViolation(&thread_context, + reinterpret_cast(siginfo->si_addr), + access_violation_operation); + } break; + default: + assert_always("Unhandled signum"); + } + + for (size_t i = 0; i < xe::countof(handlers_) && handlers_[i].first; ++i) { + if (handlers_[i].first(&ex, handlers_[i].second)) { + // Exception handled. + return; + } + } + + assert_always("Unhandled exception"); +} + +void ExceptionHandler::Install(Handler fn, void* data) { + if (!signal_handlers_installed_) { + struct sigaction signal_handler; + + std::memset(&signal_handler, 0, sizeof(signal_handler)); + signal_handler.sa_sigaction = ExceptionHandlerCallback; + signal_handler.sa_flags = SA_SIGINFO; + + if (sigaction(SIGILL, &signal_handler, &original_sigill_handler_) != 0) { + assert_always("Failed to install new SIGILL handler"); + } + if (sigaction(SIGSEGV, &signal_handler, &original_sigsegv_handler_) != 0) { + assert_always("Failed to install new SIGSEGV handler"); + } + signal_handlers_installed_ = true; + } + + for (size_t i = 0; i < xe::countof(handlers_); ++i) { + if (!handlers_[i].first) { + handlers_[i].first = fn; + handlers_[i].second = data; + return; + } + } + assert_always("Too many exception handlers installed"); +} + +void ExceptionHandler::Uninstall(Handler fn, void* data) { + for (size_t i = 0; i < xe::countof(handlers_); ++i) { + if (handlers_[i].first == fn && handlers_[i].second == data) { + for (; i < xe::countof(handlers_) - 1; ++i) { + handlers_[i] = handlers_[i + 1]; + } + handlers_[i].first = nullptr; + handlers_[i].second = nullptr; + break; + } + } + + bool has_any = false; + for (size_t i = 0; i < xe::countof(handlers_); ++i) { + if (handlers_[i].first) { + has_any = true; + break; + } + } + if (!has_any) { + if (signal_handlers_installed_) { + if (sigaction(SIGILL, &original_sigill_handler_, NULL) != 0) { + assert_always("Failed to restore original SIGILL handler"); + } + if (sigaction(SIGSEGV, &original_sigsegv_handler_, NULL) != 0) { + assert_always("Failed to restore original SIGSEGV handler"); + } + signal_handlers_installed_ = false; + } + } +} + +} // namespace xe From 60fea32f52bce7e42ce3cbf99fd3083271e38b15 Mon Sep 17 00:00:00 2001 From: uytvbn Date: Tue, 24 Oct 2017 22:04:56 +0200 Subject: [PATCH 03/17] [Linux] Fix off-by-one error in bit_scan_forward --- src/xenia/base/math.h | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/xenia/base/math.h b/src/xenia/base/math.h index 8852636d2..050a624ab 100644 --- a/src/xenia/base/math.h +++ b/src/xenia/base/math.h @@ -204,13 +204,21 @@ inline bool bit_scan_forward(uint64_t v, uint32_t* out_first_set_index) { #else inline bool bit_scan_forward(uint32_t v, uint32_t* out_first_set_index) { int i = ffs(v); - *out_first_set_index = i; - return i != 0; + if (i == 0) { + return false; + } else { + *out_first_set_index = i - 1; + return true; + } } inline bool bit_scan_forward(uint64_t v, uint32_t* out_first_set_index) { int i = ffsll(v); - *out_first_set_index = i; - return i != 0; + if (i == 0) { + return false; + } else { + *out_first_set_index = i - 1; + return true; + } } #endif // XE_PLATFORM_WIN32 inline bool bit_scan_forward(int32_t v, uint32_t* out_first_set_index) { From 6c58b3b13dbbf8413dc421a84e9187e799dca9e6 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Sun, 20 Jan 2019 21:28:17 -0500 Subject: [PATCH 04/17] [string] Add base string tests --- src/xenia/base/testing/string_test.cc | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/xenia/base/testing/string_test.cc diff --git a/src/xenia/base/testing/string_test.cc b/src/xenia/base/testing/string_test.cc new file mode 100644 index 000000000..1f287d933 --- /dev/null +++ b/src/xenia/base/testing/string_test.cc @@ -0,0 +1,25 @@ +/** +****************************************************************************** +* Xenia : Xbox 360 Emulator Research Project * +****************************************************************************** +* Copyright 2019 Ben Vanik. All rights reserved. * +* Released under the BSD license - see LICENSE in the root for more details. * +****************************************************************************** +*/ + +#include "xenia/base/string.h" + +#include "third_party/catch/include/catch.hpp" + +namespace xe { +namespace base { +namespace test { + +TEST_CASE("StringBuffer") { + // TODO(bwrsandman): + REQUIRE(false); +} + +} // namespace test +} // namespace base +} // namespace xe From c97c4dbeacec95ee6799126cb8cca721b71b7e8f Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Sun, 27 Jan 2019 10:10:04 -0500 Subject: [PATCH 05/17] [string] Remove reuse of va_list in AppendVarargs va_list are not guarenteed to maintain their values after being used. With clang on Linux, args is undefined after fetching length and will print "(null)". Copy args into another va_list before getting length to prevent this. Add tests. --- src/xenia/base/string_buffer.cc | 5 ++++- src/xenia/base/testing/string_test.cc | 13 +++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/xenia/base/string_buffer.cc b/src/xenia/base/string_buffer.cc index f7b4c8889..ac8a924d6 100644 --- a/src/xenia/base/string_buffer.cc +++ b/src/xenia/base/string_buffer.cc @@ -64,7 +64,10 @@ void StringBuffer::AppendFormat(const char* format, ...) { } void StringBuffer::AppendVarargs(const char* format, va_list args) { - int length = vsnprintf(nullptr, 0, format, args); + va_list size_args; + va_copy(size_args, args); // arg is indeterminate after the return so copy it + int length = vsnprintf(nullptr, 0, format, size_args); + va_end(size_args); Grow(length + 1); vsnprintf(buffer_ + buffer_offset_, buffer_capacity_, format, args); buffer_offset_ += length; diff --git a/src/xenia/base/testing/string_test.cc b/src/xenia/base/testing/string_test.cc index 1f287d933..946ed59b2 100644 --- a/src/xenia/base/testing/string_test.cc +++ b/src/xenia/base/testing/string_test.cc @@ -8,6 +8,7 @@ */ #include "xenia/base/string.h" +#include "xenia/base/string_buffer.h" #include "third_party/catch/include/catch.hpp" @@ -16,8 +17,16 @@ namespace base { namespace test { TEST_CASE("StringBuffer") { - // TODO(bwrsandman): - REQUIRE(false); + StringBuffer sb; + uint32_t module_flags = 0x1000000; + + std::string path_(R"(\Device\Cdrom0\default.xex)"); + sb.AppendFormat("Module %s:\n", path_.c_str()); + REQUIRE(sb.to_string() == "Module \\Device\\Cdrom0\\default.xex:\n"); + sb.AppendFormat(" Module Flags: %.8X\n", module_flags); + REQUIRE( + sb.to_string() == + "Module \\Device\\Cdrom0\\default.xex:\n Module Flags: 01000000\n"); } } // namespace test From 41b0aa9ffd202c804d244c66122d6a95e0814e2b Mon Sep 17 00:00:00 2001 From: uytvbn Date: Tue, 24 Oct 2017 22:32:39 +0200 Subject: [PATCH 06/17] [Linux] Implement thunk generation --- src/xenia/cpu/backend/x64/x64_backend.cc | 83 ++++++++++++++++++++---- src/xenia/cpu/backend/x64/x64_emitter.cc | 30 ++++++--- 2 files changed, 93 insertions(+), 20 deletions(-) diff --git a/src/xenia/cpu/backend/x64/x64_backend.cc b/src/xenia/cpu/backend/x64/x64_backend.cc index 8d3d48cee..f379fcbff 100644 --- a/src/xenia/cpu/backend/x64/x64_backend.cc +++ b/src/xenia/cpu/backend/x64/x64_backend.cc @@ -403,9 +403,9 @@ X64ThunkEmitter::X64ThunkEmitter(X64Backend* backend, XbyakAllocator* allocator) X64ThunkEmitter::~X64ThunkEmitter() {} HostToGuestThunk X64ThunkEmitter::EmitHostToGuestThunk() { - // rcx = target - // rdx = arg0 (context) - // r8 = arg1 (guest return address) + // rcx (win), rdi (linux) = target + // rdx (win), rsi (linux) = arg0 (context) + // r8 (win), rdx (linux) = arg1 (guest return address) struct _code_offsets { size_t prolog; @@ -420,9 +420,15 @@ HostToGuestThunk X64ThunkEmitter::EmitHostToGuestThunk() { code_offsets.prolog = getSize(); // rsp + 0 = return address +#if XE_PLATFORM_LINUX + mov(qword[rsp + 8 * 3], rdx); + mov(qword[rsp + 8 * 2], rsi); + mov(qword[rsp + 8 * 1], rdi); +#else mov(qword[rsp + 8 * 3], r8); mov(qword[rsp + 8 * 2], rdx); mov(qword[rsp + 8 * 1], rcx); +#endif sub(rsp, stack_size); code_offsets.prolog_stack_alloc = getSize(); @@ -431,9 +437,15 @@ HostToGuestThunk X64ThunkEmitter::EmitHostToGuestThunk() { // Save nonvolatile registers. EmitSaveNonvolatileRegs(); +#ifdef XE_PLATFORM_LINUX + mov(rax, rdi); + // context already in rsi + mov(rcx, rdx); // return address +#else mov(rax, rcx); mov(rsi, rdx); // context mov(rcx, r8); // return address +#endif call(rax); EmitLoadNonvolatileRegs(); @@ -441,9 +453,15 @@ HostToGuestThunk X64ThunkEmitter::EmitHostToGuestThunk() { code_offsets.epilog = getSize(); add(rsp, stack_size); +#if XE_PLATFORM_LINUX + mov(rdi, qword[rsp + 8 * 1]); + mov(rsi, qword[rsp + 8 * 2]); + mov(rdx, qword[rsp + 8 * 3]); +#else mov(rcx, qword[rsp + 8 * 1]); mov(rdx, qword[rsp + 8 * 2]); mov(r8, qword[rsp + 8 * 3]); +#endif ret(); code_offsets.tail = getSize(); @@ -464,10 +482,12 @@ HostToGuestThunk X64ThunkEmitter::EmitHostToGuestThunk() { } GuestToHostThunk X64ThunkEmitter::EmitGuestToHostThunk() { - // rcx = target function - // rdx = arg0 - // r8 = arg1 - // r9 = arg2 + // rcx (windows), rdi (linux) = target function + // rdx (windows), rsi (linux) = arg0 + // r8 (windows), rdx (linux) = arg1 + // r9 (windows), rcx (linux) = arg2 + // --- (windows), r8 (linux) = arg3 + // --- (windows), r9 (linux) = arg4 struct _code_offsets { size_t prolog; @@ -490,8 +510,13 @@ GuestToHostThunk X64ThunkEmitter::EmitGuestToHostThunk() { // Save off volatile registers. EmitSaveVolatileRegs(); - mov(rax, rcx); // function + mov(rax, rcx); // function +#if XE_PLATFORM_LINUX + mov(rdi, GetContextReg()); // context + mov(rsi, rbx); +#else mov(rcx, GetContextReg()); // context +#endif call(rax); EmitLoadVolatileRegs(); @@ -546,8 +571,13 @@ ResolveFunctionThunk X64ThunkEmitter::EmitResolveFunctionThunk() { // Save volatile registers EmitSaveVolatileRegs(); - mov(rcx, rsi); // context +#if XE_PLATFORM_LINUX + mov(rdi, rsi); // context + mov(rsi, rbx); +#else + mov(rcx, rsi); // context mov(rdx, rbx); +#endif mov(rax, uint64_t(&ResolveFunction)); call(rax); @@ -578,6 +608,12 @@ ResolveFunctionThunk X64ThunkEmitter::EmitResolveFunctionThunk() { void X64ThunkEmitter::EmitSaveVolatileRegs() { // Save off volatile registers. // mov(qword[rsp + offsetof(StackLayout::Thunk, r[0])], rax); +#if XE_PLATFORM_LINUX + mov(qword[rsp + offsetof(StackLayout::Thunk, r[1])], rdi); + mov(qword[rsp + offsetof(StackLayout::Thunk, r[2])], rsi); + mov(qword[rsp + offsetof(StackLayout::Thunk, r[3])], rcx); + mov(qword[rsp + offsetof(StackLayout::Thunk, r[4])], rdx); +#else mov(qword[rsp + offsetof(StackLayout::Thunk, r[1])], rcx); mov(qword[rsp + offsetof(StackLayout::Thunk, r[2])], rdx); mov(qword[rsp + offsetof(StackLayout::Thunk, r[3])], r8); @@ -591,10 +627,17 @@ void X64ThunkEmitter::EmitSaveVolatileRegs() { vmovaps(qword[rsp + offsetof(StackLayout::Thunk, xmm[3])], xmm3); vmovaps(qword[rsp + offsetof(StackLayout::Thunk, xmm[4])], xmm4); vmovaps(qword[rsp + offsetof(StackLayout::Thunk, xmm[5])], xmm5); +#endif } void X64ThunkEmitter::EmitLoadVolatileRegs() { - // Load volatile registers from our stack frame. +#if XE_PLATFORM_LINUX + // mov(rax, qword[rsp + offsetof(StackLayout::Thunk, r[0])]); + mov(rdi, qword[rsp + offsetof(StackLayout::Thunk, r[1])]); + mov(rsi, qword[rsp + offsetof(StackLayout::Thunk, r[2])]); + mov(rcx, qword[rsp + offsetof(StackLayout::Thunk, r[3])]); + mov(rdx, qword[rsp + offsetof(StackLayout::Thunk, r[4])]); +#else // vmovaps(xmm0, qword[rsp + offsetof(StackLayout::Thunk, xmm[0])]); vmovaps(xmm1, qword[rsp + offsetof(StackLayout::Thunk, xmm[1])]); vmovaps(xmm2, qword[rsp + offsetof(StackLayout::Thunk, xmm[2])]); @@ -609,10 +652,18 @@ void X64ThunkEmitter::EmitLoadVolatileRegs() { mov(r9, qword[rsp + offsetof(StackLayout::Thunk, r[4])]); mov(r10, qword[rsp + offsetof(StackLayout::Thunk, r[5])]); mov(r11, qword[rsp + offsetof(StackLayout::Thunk, r[6])]); +#endif } void X64ThunkEmitter::EmitSaveNonvolatileRegs() { - // Preserve nonvolatile registers. +#if XE_PLATFORM_LINUX + mov(qword[rsp + offsetof(StackLayout::Thunk, r[0])], rbx); + mov(qword[rsp + offsetof(StackLayout::Thunk, r[1])], rbp); + mov(qword[rsp + offsetof(StackLayout::Thunk, r[2])], r12); + mov(qword[rsp + offsetof(StackLayout::Thunk, r[3])], r13); + mov(qword[rsp + offsetof(StackLayout::Thunk, r[4])], r14); + mov(qword[rsp + offsetof(StackLayout::Thunk, r[5])], r15); +#else mov(qword[rsp + offsetof(StackLayout::Thunk, r[0])], rbx); mov(qword[rsp + offsetof(StackLayout::Thunk, r[1])], rcx); mov(qword[rsp + offsetof(StackLayout::Thunk, r[2])], rbp); @@ -633,9 +684,18 @@ void X64ThunkEmitter::EmitSaveNonvolatileRegs() { vmovaps(qword[rsp + offsetof(StackLayout::Thunk, xmm[7])], xmm13); vmovaps(qword[rsp + offsetof(StackLayout::Thunk, xmm[8])], xmm14); vmovaps(qword[rsp + offsetof(StackLayout::Thunk, xmm[9])], xmm15); +#endif } void X64ThunkEmitter::EmitLoadNonvolatileRegs() { +#ifdef XE_PLATFORM_LINUX + mov(rbx, qword[rsp + offsetof(StackLayout::Thunk, r[0])]); + mov(rbp, qword[rsp + offsetof(StackLayout::Thunk, r[1])]); + mov(r12, qword[rsp + offsetof(StackLayout::Thunk, r[2])]); + mov(r13, qword[rsp + offsetof(StackLayout::Thunk, r[3])]); + mov(r14, qword[rsp + offsetof(StackLayout::Thunk, r[4])]); + mov(r15, qword[rsp + offsetof(StackLayout::Thunk, r[5])]); +#else vmovaps(xmm6, qword[rsp + offsetof(StackLayout::Thunk, xmm[0])]); vmovaps(xmm7, qword[rsp + offsetof(StackLayout::Thunk, xmm[1])]); vmovaps(xmm8, qword[rsp + offsetof(StackLayout::Thunk, xmm[2])]); @@ -656,6 +716,7 @@ void X64ThunkEmitter::EmitLoadNonvolatileRegs() { mov(r13, qword[rsp + offsetof(StackLayout::Thunk, r[6])]); mov(r14, qword[rsp + offsetof(StackLayout::Thunk, r[7])]); mov(r15, qword[rsp + offsetof(StackLayout::Thunk, r[8])]); +#endif } } // namespace x64 diff --git a/src/xenia/cpu/backend/x64/x64_emitter.cc b/src/xenia/cpu/backend/x64/x64_emitter.cc index 216efd9bc..a57cada36 100644 --- a/src/xenia/cpu/backend/x64/x64_emitter.cc +++ b/src/xenia/cpu/backend/x64/x64_emitter.cc @@ -491,9 +491,9 @@ void X64Emitter::CallExtern(const hir::Instr* instr, const Function* function) { if (builtin_function->handler()) { undefined = false; // rcx = target function - // rdx = arg0 - // r8 = arg1 - // r9 = arg2 + // rdx (windows), r8 (linux) = arg0 + // r8 (windows), rdx (linux) = arg1 + // r9 (windows), rcx (linux) = arg2 auto thunk = backend()->guest_to_host_thunk(); mov(rax, reinterpret_cast(thunk)); mov(rcx, reinterpret_cast(builtin_function->handler())); @@ -507,9 +507,9 @@ void X64Emitter::CallExtern(const hir::Instr* instr, const Function* function) { if (extern_function->extern_handler()) { undefined = false; // rcx = target function - // rdx = arg0 - // r8 = arg1 - // r9 = arg2 + // rdx (windows), r8 (linux) = arg0 + // r8 (windows), rdx (linux) = arg1 + // r9 (windows), rcx (linux) = arg2 auto thunk = backend()->guest_to_host_thunk(); mov(rax, reinterpret_cast(thunk)); mov(rcx, reinterpret_cast(extern_function->extern_handler())); @@ -542,9 +542,9 @@ void X64Emitter::CallNative(uint64_t (*fn)(void* raw_context, uint64_t arg0), void X64Emitter::CallNativeSafe(void* fn) { // rcx = target function - // rdx = arg0 - // r8 = arg1 - // r9 = arg2 + // rdx (windows), r8 (linux) = arg0 + // r8 (windows), rdx (linux) = arg1 + // r9 (windows), rcx (linux) = arg2 auto thunk = backend()->guest_to_host_thunk(); mov(rax, reinterpret_cast(thunk)); mov(rcx, reinterpret_cast(fn)); @@ -558,6 +558,17 @@ void X64Emitter::SetReturnAddress(uint64_t value) { } Xbyak::Reg64 X64Emitter::GetNativeParam(uint32_t param) { +#if XE_PLATFORM_LINUX + if (param == 0) + return rbx; + else if (param == 1) + return rdx; + else if (param == 2) + return rcx; + + assert_always(); + return rcx; +#else if (param == 0) return rdx; else if (param == 1) @@ -567,6 +578,7 @@ Xbyak::Reg64 X64Emitter::GetNativeParam(uint32_t param) { assert_always(); return r9; +#endif } // Important: If you change these, you must update the thunks in x64_backend.cc! From c804b0dff9b71cda47f4b7cf0320423cc9772eaf Mon Sep 17 00:00:00 2001 From: uytvbn Date: Tue, 24 Oct 2017 22:49:31 +0200 Subject: [PATCH 07/17] [Linux] Force passing XMM values by pointer --- src/xenia/cpu/backend/x64/x64_seq_vector.cc | 24 ++++++++++----------- src/xenia/cpu/backend/x64/x64_sequences.cc | 16 +++++++------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/xenia/cpu/backend/x64/x64_seq_vector.cc b/src/xenia/cpu/backend/x64/x64_seq_vector.cc index dc9aa7186..b5f648989 100644 --- a/src/xenia/cpu/backend/x64/x64_seq_vector.cc +++ b/src/xenia/cpu/backend/x64/x64_seq_vector.cc @@ -671,7 +671,7 @@ EMITTER_OPCODE_TABLE(OPCODE_VECTOR_SUB, VECTOR_SUB); // OPCODE_VECTOR_SHL // ============================================================================ template ::value, int> = 0> -static __m128i EmulateVectorShl(void*, __m128i src1, __m128i src2) { +static __m128i EmulateVectorShl(void*, __m128i& src1, __m128i& src2) { alignas(16) T value[16 / sizeof(T)]; alignas(16) T shamt[16 / sizeof(T)]; @@ -863,7 +863,7 @@ EMITTER_OPCODE_TABLE(OPCODE_VECTOR_SHL, VECTOR_SHL_V128); // OPCODE_VECTOR_SHR // ============================================================================ template ::value, int> = 0> -static __m128i EmulateVectorShr(void*, __m128i src1, __m128i src2) { +static __m128i EmulateVectorShr(void*, __m128i& src1, __m128i& src2) { alignas(16) T value[16 / sizeof(T)]; alignas(16) T shamt[16 / sizeof(T)]; @@ -1199,7 +1199,7 @@ EMITTER_OPCODE_TABLE(OPCODE_VECTOR_SHA, VECTOR_SHA_V128); // OPCODE_VECTOR_ROTATE_LEFT // ============================================================================ template ::value, int> = 0> -static __m128i EmulateVectorRotateLeft(void*, __m128i src1, __m128i src2) { +static __m128i EmulateVectorRotateLeft(void*, __m128i& src1, __m128i& src2) { alignas(16) T value[16 / sizeof(T)]; alignas(16) T shamt[16 / sizeof(T)]; @@ -1289,7 +1289,7 @@ EMITTER_OPCODE_TABLE(OPCODE_VECTOR_ROTATE_LEFT, VECTOR_ROTATE_LEFT_V128); // OPCODE_VECTOR_AVERAGE // ============================================================================ template ::value, int> = 0> -static __m128i EmulateVectorAverage(void*, __m128i src1, __m128i src2) { +static __m128i EmulateVectorAverage(void*, __m128i& src1, __m128i& src2) { alignas(16) T src1v[16 / sizeof(T)]; alignas(16) T src2v[16 / sizeof(T)]; alignas(16) T value[16 / sizeof(T)]; @@ -1857,7 +1857,7 @@ struct PACK : Sequence> { // ((src1.uy & 0xFF) << 8) | (src1.uz & 0xFF) e.vpshufb(i.dest, i.dest, e.GetXmmConstPtr(XMMPackD3DCOLOR)); } - static __m128i EmulateFLOAT16_2(void*, __m128 src1) { + static __m128i EmulateFLOAT16_2(void*, __m128& src1) { alignas(16) float a[4]; alignas(16) uint16_t b[8]; _mm_store_ps(a, src1); @@ -1898,7 +1898,7 @@ struct PACK : Sequence> { e.vmovaps(i.dest, e.xmm0); } } - static __m128i EmulateFLOAT16_4(void*, __m128 src1) { + static __m128i EmulateFLOAT16_4(void*, __m128& src1) { alignas(16) float a[4]; alignas(16) uint16_t b[8]; _mm_store_ps(a, src1); @@ -2031,8 +2031,8 @@ struct PACK : Sequence> { // Merge XZ and YW. e.vorps(i.dest, e.xmm0); } - static __m128i EmulatePack8_IN_16_UN_UN_SAT(void*, __m128i src1, - __m128i src2) { + static __m128i EmulatePack8_IN_16_UN_UN_SAT(void*, __m128i& src1, + __m128i& src2) { alignas(16) uint16_t a[8]; alignas(16) uint16_t b[8]; alignas(16) uint8_t c[16]; @@ -2044,7 +2044,7 @@ struct PACK : Sequence> { } return _mm_load_si128(reinterpret_cast<__m128i*>(c)); } - static __m128i EmulatePack8_IN_16_UN_UN(void*, __m128i src1, __m128i src2) { + static __m128i EmulatePack8_IN_16_UN_UN(void*, __m128i& src1, __m128i& src2) { alignas(16) uint8_t a[16]; alignas(16) uint8_t b[16]; alignas(16) uint8_t c[16]; @@ -2277,7 +2277,7 @@ struct UNPACK : Sequence> { e.vpor(i.dest, e.GetXmmConstPtr(XMMOne)); // To convert to 0 to 1, games multiply by 0x47008081 and add 0xC7008081. } - static __m128 EmulateFLOAT16_2(void*, __m128i src1) { + static __m128 EmulateFLOAT16_2(void*, __m128i& src1) { alignas(16) uint16_t a[8]; alignas(16) float b[4]; _mm_store_si128(reinterpret_cast<__m128i*>(a), src1); @@ -2336,7 +2336,7 @@ struct UNPACK : Sequence> { e.vmovaps(i.dest, e.xmm0); } } - static __m128 EmulateFLOAT16_4(void*, __m128i src1) { + static __m128 EmulateFLOAT16_4(void*, __m128i& src1) { alignas(16) uint16_t a[8]; alignas(16) float b[4]; _mm_store_si128(reinterpret_cast<__m128i*>(a), src1); @@ -2616,4 +2616,4 @@ EMITTER_OPCODE_TABLE(OPCODE_UNPACK, UNPACK); } // namespace x64 } // namespace backend } // namespace cpu -} // namespace xe \ No newline at end of file +} // namespace xe diff --git a/src/xenia/cpu/backend/x64/x64_sequences.cc b/src/xenia/cpu/backend/x64/x64_sequences.cc index 7d18cb4d0..1e4d193ad 100644 --- a/src/xenia/cpu/backend/x64/x64_sequences.cc +++ b/src/xenia/cpu/backend/x64/x64_sequences.cc @@ -2352,7 +2352,7 @@ EMITTER_OPCODE_TABLE(OPCODE_RECIP, RECIP_F32, RECIP_F64, RECIP_V128); // TODO(benvanik): use approx here: // https://jrfonseca.blogspot.com/2008/09/fast-sse2-pow-tables-or-polynomials.html struct POW2_F32 : Sequence> { - static __m128 EmulatePow2(void*, __m128 src) { + static __m128 EmulatePow2(void*, __m128& src) { float src_value; _mm_store_ss(&src_value, src); float result = std::exp2(src_value); @@ -2366,7 +2366,7 @@ struct POW2_F32 : Sequence> { } }; struct POW2_F64 : Sequence> { - static __m128d EmulatePow2(void*, __m128d src) { + static __m128d EmulatePow2(void*, __m128d& src) { double src_value; _mm_store_sd(&src_value, src); double result = std::exp2(src_value); @@ -2380,7 +2380,7 @@ struct POW2_F64 : Sequence> { } }; struct POW2_V128 : Sequence> { - static __m128 EmulatePow2(void*, __m128 src) { + static __m128 EmulatePow2(void*, __m128& src) { alignas(16) float values[4]; _mm_store_ps(values, src); for (size_t i = 0; i < 4; ++i) { @@ -2403,7 +2403,7 @@ EMITTER_OPCODE_TABLE(OPCODE_POW2, POW2_F32, POW2_F64, POW2_V128); // https://jrfonseca.blogspot.com/2008/09/fast-sse2-pow-tables-or-polynomials.html // TODO(benvanik): this emulated fn destroys all xmm registers! don't do it! struct LOG2_F32 : Sequence> { - static __m128 EmulateLog2(void*, __m128 src) { + static __m128 EmulateLog2(void*, __m128& src) { float src_value; _mm_store_ss(&src_value, src); float result = std::log2(src_value); @@ -2417,7 +2417,7 @@ struct LOG2_F32 : Sequence> { } }; struct LOG2_F64 : Sequence> { - static __m128d EmulateLog2(void*, __m128d src) { + static __m128d EmulateLog2(void*, __m128d& src) { double src_value; _mm_store_sd(&src_value, src); double result = std::log2(src_value); @@ -2431,7 +2431,7 @@ struct LOG2_F64 : Sequence> { } }; struct LOG2_V128 : Sequence> { - static __m128 EmulateLog2(void*, __m128 src) { + static __m128 EmulateLog2(void*, __m128& src) { alignas(16) float values[4]; _mm_store_ps(values, src); for (size_t i = 0; i < 4; ++i) { @@ -2713,7 +2713,7 @@ struct SHL_V128 : Sequence> { e.CallNativeSafe(reinterpret_cast(EmulateShlV128)); e.vmovaps(i.dest, e.xmm0); } - static __m128i EmulateShlV128(void*, __m128i src1, uint8_t src2) { + static __m128i EmulateShlV128(void*, __m128i& src1, uint8_t src2) { // Almost all instances are shamt = 1, but non-constant. // shamt is [0,7] uint8_t shamt = src2 & 0x7; @@ -2790,7 +2790,7 @@ struct SHR_V128 : Sequence> { e.CallNativeSafe(reinterpret_cast(EmulateShrV128)); e.vmovaps(i.dest, e.xmm0); } - static __m128i EmulateShrV128(void*, __m128i src1, uint8_t src2) { + static __m128i EmulateShrV128(void*, __m128i& src1, uint8_t src2) { // Almost all instances are shamt = 1, but non-constant. // shamt is [0,7] uint8_t shamt = src2 & 0x7; From 8817975912ad2304f50f1210ad1045be49c8d8b9 Mon Sep 17 00:00:00 2001 From: uytvbn Date: Tue, 24 Oct 2017 22:57:10 +0200 Subject: [PATCH 08/17] [Linux] Fix Value::MulHi --- src/xenia/cpu/hir/value.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/xenia/cpu/hir/value.cc b/src/xenia/cpu/hir/value.cc index 666648b03..ed7bfc440 100644 --- a/src/xenia/cpu/hir/value.cc +++ b/src/xenia/cpu/hir/value.cc @@ -440,12 +440,14 @@ void Value::MulHi(Value* other, bool is_unsigned) { #else if (is_unsigned) { constant.i64 = static_cast( - static_cast(constant.i64) * - static_cast(other->constant.i64)); + (static_cast(constant.u64) * + static_cast(other->constant.u64)) >> + 64); } else { - constant.i64 = - static_cast(static_cast<__int128>(constant.i64) * - static_cast<__int128>(other->constant.i64)); + constant.i64 = static_cast( + (static_cast<__int128>(constant.i64) * + static_cast<__int128>(other->constant.i64)) >> + 64); } #endif // XE_COMPILER_MSVC break; From ee7f68a85f0ca62ddbf85846788c838c9f1241a0 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Sat, 9 Mar 2019 22:01:01 -0500 Subject: [PATCH 09/17] [Linux] Fix Value::set_zero() on release Disable optimization on set zero to prevent clang from vectorizing the assigment to zero which would use different registers than expected. With -O0: RAX. With -O1: RDI. --- src/xenia/cpu/hir/value.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/xenia/cpu/hir/value.h b/src/xenia/cpu/hir/value.h index dcc95ca8c..bcfee604a 100644 --- a/src/xenia/cpu/hir/value.h +++ b/src/xenia/cpu/hir/value.h @@ -16,6 +16,12 @@ #include "xenia/cpu/backend/machine_info.h" #include "xenia/cpu/hir/opcodes.h" +#if XE_PLATFORM_LINUX +#define OPTNONE __attribute__((optnone)) +#else +#define OPTNONE +#endif // XE_PLATFORM_LINUX + namespace xe { namespace cpu { namespace hir { @@ -109,7 +115,9 @@ class Value { Use* AddUse(Arena* arena, Instr* instr); void RemoveUse(Use* use); - void set_zero(TypeName new_type) { + // Set optnone to prevent clang from vectorizing the assignment to 0 which + // would happen on different registers. + void set_zero(TypeName new_type) OPTNONE { type = new_type; flags |= VALUE_IS_CONSTANT; constant.v128.low = constant.v128.high = 0; From 85f407f317d8b33961db7a91b94abb722351f6b6 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Sun, 10 Mar 2019 16:15:24 -0400 Subject: [PATCH 10/17] [Linux] Fix Value::Not on release Disable optimization on set zero to prevent clang from vectorizing the assigment to zero which would use different registers than expected. --- src/xenia/cpu/hir/value.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/xenia/cpu/hir/value.cc b/src/xenia/cpu/hir/value.cc index ed7bfc440..69a8f783a 100644 --- a/src/xenia/cpu/hir/value.cc +++ b/src/xenia/cpu/hir/value.cc @@ -16,6 +16,12 @@ #include "xenia/base/byte_order.h" #include "xenia/base/math.h" +#if XE_PLATFORM_LINUX +#define OPTNONE __attribute__((optnone)) +#else +#define OPTNONE +#endif // XE_PLATFORM_LINUX + namespace xe { namespace cpu { namespace hir { @@ -757,8 +763,8 @@ void Value::Xor(Value* other) { break; } } - -void Value::Not() { +// Set optnone to prevent clang 6 from optimizing and causing issues +void Value::Not() OPTNONE { switch (type) { case INT8_TYPE: constant.i8 = ~constant.i8; From 23353173fe12d66e58ca89cfa88c8933841591bc Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Sun, 10 Mar 2019 14:24:49 -0400 Subject: [PATCH 11/17] [Linux] Fix Processor::backend() on release Disable inlining on backend() which causes ppc issues on clang 7 in release builds. --- src/xenia/cpu/processor.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/xenia/cpu/processor.h b/src/xenia/cpu/processor.h index bb8709a72..c319f2259 100644 --- a/src/xenia/cpu/processor.h +++ b/src/xenia/cpu/processor.h @@ -29,6 +29,12 @@ #include "xenia/cpu/thread_state.h" #include "xenia/memory.h" +#if XE_PLATFORM_LINUX +#define NOINLINE __attribute__((noinline)) +#else +#define NOINLINE +#endif // XE_PLATFORM_LINUX + DECLARE_bool(debug); namespace xe { @@ -67,7 +73,9 @@ class Processor { Memory* memory() const { return memory_; } StackWalker* stack_walker() const { return stack_walker_.get(); } ppc::PPCFrontend* frontend() const { return frontend_.get(); } - backend::Backend* backend() const { return backend_.get(); } + // Clang 6 on release has issues with ppc instructions when this function is + // inlined + backend::Backend* backend() const NOINLINE { return backend_.get(); } ExportResolver* export_resolver() const { return export_resolver_; } bool Setup(std::unique_ptr backend); From 02dd9254b1d3aa1d0b084aa8bea510905f6de00a Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Thu, 21 Feb 2019 18:06:51 -0500 Subject: [PATCH 12/17] [travis] Enable ppc gentest and tests --- .travis.yml | 4 +++- third_party/binutils/build.sh | 0 2 files changed, 3 insertions(+), 1 deletion(-) mode change 100644 => 100755 third_party/binutils/build.sh diff --git a/.travis.yml b/.travis.yml index 40056746a..2075010ff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,6 +50,7 @@ before_script: - if [[ $BUILD == true ]]; then sudo dpkg -i libvulkan1_$LIBVULKAN_VERSION+dfsg1-1_amd64.deb libvulkan-dev_$LIBVULKAN_VERSION+dfsg1-1_amd64.deb; fi # Prepare environment (pull dependencies, build tools). - travis_retry ./xenia-build setup + - if [[ $BUILD == true ]]; then ./third_party/binutils/build.sh; fi script: # Run linter. @@ -59,8 +60,9 @@ script: - if [[ $BUILD == true ]]; then ./xenia-build build --config=$CONFIG --target=xenia-base-tests; fi - if [[ $BUILD == true ]]; then ./build/bin/Linux/$CONFIG/xenia-base-tests; fi # Build and run ppc tests. + - if [[ $BUILD == true ]]; then ./xenia-build gentests; fi - if [[ $BUILD == true ]]; then ./xenia-build build --config=$CONFIG --target=xenia-cpu-ppc-tests; fi - # - if [[ $BUILD == true ]]; then ./build/bin/Linux/$CONFIG/xenia-cpu-ppc-tests --log_file=stdout; fi + - if [[ $BUILD == true ]]; then ./build/bin/Linux/$CONFIG/xenia-cpu-ppc-tests --log_file=stdout; fi # Build all of xenia. - if [[ $BUILD == true ]]; then ./xenia-build build --config=$CONFIG; fi diff --git a/third_party/binutils/build.sh b/third_party/binutils/build.sh old mode 100644 new mode 100755 From 0cf34743ccc3ea895b000da1bf582c8e56466185 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Wed, 10 Jul 2019 14:55:30 -0400 Subject: [PATCH 13/17] ppc linux: add comment about xmm registers --- src/xenia/cpu/backend/x64/x64_backend.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xenia/cpu/backend/x64/x64_backend.cc b/src/xenia/cpu/backend/x64/x64_backend.cc index f379fcbff..d847d746a 100644 --- a/src/xenia/cpu/backend/x64/x64_backend.cc +++ b/src/xenia/cpu/backend/x64/x64_backend.cc @@ -657,6 +657,7 @@ void X64ThunkEmitter::EmitLoadVolatileRegs() { void X64ThunkEmitter::EmitSaveNonvolatileRegs() { #if XE_PLATFORM_LINUX + // SysV does not have nonvolatile XMM registers. mov(qword[rsp + offsetof(StackLayout::Thunk, r[0])], rbx); mov(qword[rsp + offsetof(StackLayout::Thunk, r[1])], rbp); mov(qword[rsp + offsetof(StackLayout::Thunk, r[2])], r12); From 74d30f8348e9fae0d2c7b1257b796c05e9fb8f4d Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Sat, 13 Jul 2019 14:10:22 -0400 Subject: [PATCH 14/17] [cpu] Use dynamic cast for downcasting pointers --- src/xenia/cpu/module.cc | 2 +- src/xenia/cpu/processor.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xenia/cpu/module.cc b/src/xenia/cpu/module.cc index 4c582763f..d9277c0f4 100644 --- a/src/xenia/cpu/module.cc +++ b/src/xenia/cpu/module.cc @@ -106,7 +106,7 @@ Symbol::Status Module::DeclareFunction(uint32_t address, Symbol* symbol; Symbol::Status status = DeclareSymbol(Symbol::Type::kFunction, address, &symbol); - *out_function = static_cast(symbol); + *out_function = dynamic_cast(symbol); return status; } diff --git a/src/xenia/cpu/processor.cc b/src/xenia/cpu/processor.cc index 278c60de8..49b396655 100644 --- a/src/xenia/cpu/processor.cc +++ b/src/xenia/cpu/processor.cc @@ -197,7 +197,7 @@ Function* Processor::DefineBuiltin(const std::string& name, function->set_end_address(address + 4); function->set_name(name); - auto builtin_function = static_cast(function); + auto builtin_function = dynamic_cast(function); builtin_function->SetupBuiltin(handler, arg0, arg1); function->set_status(Symbol::Status::kDeclared); From b3f5b6ecf05855efa64e6414133d9a0b6b290c49 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Sat, 13 Jul 2019 14:11:25 -0400 Subject: [PATCH 15/17] [cpu] Add linux registers to CallExtern --- src/xenia/cpu/backend/x64/x64_emitter.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/xenia/cpu/backend/x64/x64_emitter.cc b/src/xenia/cpu/backend/x64/x64_emitter.cc index a57cada36..6dc7fa2f6 100644 --- a/src/xenia/cpu/backend/x64/x64_emitter.cc +++ b/src/xenia/cpu/backend/x64/x64_emitter.cc @@ -497,8 +497,13 @@ void X64Emitter::CallExtern(const hir::Instr* instr, const Function* function) { auto thunk = backend()->guest_to_host_thunk(); mov(rax, reinterpret_cast(thunk)); mov(rcx, reinterpret_cast(builtin_function->handler())); +#if XE_PLATFORM_LINUX + mov(rbx, reinterpret_cast(builtin_function->arg0())); + mov(rdx, reinterpret_cast(builtin_function->arg1())); +#else mov(rdx, reinterpret_cast(builtin_function->arg0())); mov(r8, reinterpret_cast(builtin_function->arg1())); +#endif call(rax); // rax = host return } From 0e54381d4c71119ce906fd020444c7ef07c19b6d Mon Sep 17 00:00:00 2001 From: uytvbn Date: Tue, 24 Oct 2017 23:12:33 +0200 Subject: [PATCH 16/17] [Linux] Implement virtual memory allocation --- src/xenia/base/memory_posix.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/xenia/base/memory_posix.cc b/src/xenia/base/memory_posix.cc index 68fdcd61b..1e55f99d9 100644 --- a/src/xenia/base/memory_posix.cc +++ b/src/xenia/base/memory_posix.cc @@ -40,7 +40,13 @@ void* AllocFixed(void* base_address, size_t length, AllocationType allocation_type, PageAccess access) { // mmap does not support reserve / commit, so ignore allocation_type. uint32_t prot = ToPosixProtectFlags(access); - return mmap(base_address, length, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + void* result = mmap(base_address, length, prot, + MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0); + if (result == MAP_FAILED) { + return nullptr; + } else { + return result; + } } bool DeallocFixed(void* base_address, size_t length, @@ -90,7 +96,7 @@ FileMappingHandle CreateFileMappingHandle(std::wstring path, size_t length, } void CloseFileMappingHandle(FileMappingHandle handle) { - close((intptr_t)handle); + close(static_cast(reinterpret_cast(handle))); } void* MapFileView(FileMappingHandle handle, void* base_address, size_t length, From 1c10e7654f2b4cdaf8c24b8c6a29f62a80bbd5b3 Mon Sep 17 00:00:00 2001 From: Sandy Carter Date: Mon, 15 Jul 2019 16:52:04 -0400 Subject: [PATCH 17/17] [cpu] Test cpu-test on travis --- .travis.yml | 3 +++ src/xenia/cpu/testing/add_test.cc | 2 +- src/xenia/cpu/testing/pack_test.cc | 7 ++++--- src/xenia/cpu/testing/unpack_test.cc | 2 +- src/xenia/cpu/testing/util.h | 1 - 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2075010ff..7cc71f9e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -59,6 +59,9 @@ script: # Build and run base tests. - if [[ $BUILD == true ]]; then ./xenia-build build --config=$CONFIG --target=xenia-base-tests; fi - if [[ $BUILD == true ]]; then ./build/bin/Linux/$CONFIG/xenia-base-tests; fi + # Build and run cpu tests. + - if [[ $BUILD == true ]]; then ./xenia-build build --config=$CONFIG --target=xenia-cpu-tests; fi + - if [[ $BUILD == true ]]; then ./build/bin/Linux/$CONFIG/xenia-cpu-tests; fi # Build and run ppc tests. - if [[ $BUILD == true ]]; then ./xenia-build gentests; fi - if [[ $BUILD == true ]]; then ./xenia-build build --config=$CONFIG --target=xenia-cpu-ppc-tests; fi diff --git a/src/xenia/cpu/testing/add_test.cc b/src/xenia/cpu/testing/add_test.cc index 8b0a9db54..c1b1b243a 100644 --- a/src/xenia/cpu/testing/add_test.cc +++ b/src/xenia/cpu/testing/add_test.cc @@ -265,7 +265,7 @@ TEST_CASE("ADD_I64", "[instr]") { }, [](PPCContext* ctx) { auto result = ctx->r[3]; - REQUIRE(result == -15); + REQUIRE(result == static_cast(-15)); }); test.Run( [](PPCContext* ctx) { diff --git a/src/xenia/cpu/testing/pack_test.cc b/src/xenia/cpu/testing/pack_test.cc index 915272128..dfac068d6 100644 --- a/src/xenia/cpu/testing/pack_test.cc +++ b/src/xenia/cpu/testing/pack_test.cc @@ -51,7 +51,7 @@ TEST_CASE("PACK_FLOAT16_2", "[instr]") { }, [](PPCContext* ctx) { auto result = ctx->v[3]; - REQUIRE(result == vec128i(0, 0, 0, 0x7FFFFFFF)); + REQUIRE(result == vec128i(0, 0, 0, 0x7BFFFBFF)); }); test.Run( [](PPCContext* ctx) { @@ -80,7 +80,7 @@ TEST_CASE("PACK_FLOAT16_4", "[instr]") { [](PPCContext* ctx) { auto result = ctx->v[3]; REQUIRE(result == - vec128i(0x00000000, 0x00000000, 0x64D26D8C, 0x48824491)); + vec128i(0x00000000, 0x00000000, 0x64D26D8B, 0x48814491)); }); } @@ -92,7 +92,8 @@ TEST_CASE("PACK_SHORT_2", "[instr]") { test.Run([](PPCContext* ctx) { ctx->v[4] = vec128i(0); }, [](PPCContext* ctx) { auto result = ctx->v[3]; - REQUIRE(result == vec128i(0)); + REQUIRE(result == + vec128i(0x00000000, 0x00000000, 0x00000000, 0x80018001)); }); test.Run( [](PPCContext* ctx) { diff --git a/src/xenia/cpu/testing/unpack_test.cc b/src/xenia/cpu/testing/unpack_test.cc index 284d7e76c..04aad1a75 100644 --- a/src/xenia/cpu/testing/unpack_test.cc +++ b/src/xenia/cpu/testing/unpack_test.cc @@ -55,7 +55,7 @@ TEST_CASE("UNPACK_FLOAT16_2", "[instr]") { [](PPCContext* ctx) { auto result = ctx->v[3]; REQUIRE(result == - vec128i(0x47FFE000, 0xC7FFE000, 0x00000000, 0x3F800000)); + vec128i(0x7FFFE000, 0xFFFFE000, 0x00000000, 0x3F800000)); }); test.Run([](PPCContext* ctx) { ctx->v[4] = vec128i(0, 0, 0, 0x55556666); }, [](PPCContext* ctx) { diff --git a/src/xenia/cpu/testing/util.h b/src/xenia/cpu/testing/util.h index 075903455..1e9a956fa 100644 --- a/src/xenia/cpu/testing/util.h +++ b/src/xenia/cpu/testing/util.h @@ -73,7 +73,6 @@ class TestFunction { uint32_t stack_address = memory_size - stack_size; uint32_t thread_state_address = stack_address - 0x1000; auto thread_state = std::make_unique(processor.get(), 0x100); - assert_always(); // TODO: Allocate a thread stack!!! auto ctx = thread_state->context(); ctx->lr = 0xBCBCBCBC;