Last stretch to get PPC native tests working

This commit is contained in:
Dr. Chat 2017-05-11 15:09:43 -05:00
parent 7eceb9db09
commit 737b78ad49
8 changed files with 131 additions and 52 deletions

View File

@ -15,7 +15,6 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <cstring>
namespace xe { namespace xe {
namespace filesystem { namespace filesystem {
@ -44,7 +43,6 @@ std::vector<FileInfo> ListFiles(const std::wstring& path) {
while (auto ent = readdir(dir)) { while (auto ent = readdir(dir)) {
FileInfo info; FileInfo info;
std::memset(&info, 0, sizeof(info));
if (ent->d_type == DT_DIR) { if (ent->d_type == DT_DIR) {
info.type = FileInfo::Type::kDirectory; info.type = FileInfo::Type::kDirectory;
info.total_size = 0; info.total_size = 0;
@ -53,6 +51,9 @@ std::vector<FileInfo> ListFiles(const std::wstring& path) {
info.total_size = 0; // TODO(DrChat): Find a way to get this info.total_size = 0; // TODO(DrChat): Find a way to get this
} }
info.create_timestamp = 0;
info.access_timestamp = 0;
info.write_timestamp = 0;
info.name = xe::to_wstring(ent->d_name); info.name = xe::to_wstring(ent->d_name);
result.push_back(info); result.push_back(info);
} }

View File

@ -36,7 +36,8 @@ void set_name(std::thread::native_handle_type handle, const std::string& name) {
} }
void Sleep(std::chrono::microseconds duration) { void Sleep(std::chrono::microseconds duration) {
timespec rqtp = {duration.count() / 1000000, duration.count() % 1000}; timespec rqtp = {time_t(duration.count() / 1000000),
time_t(duration.count() % 1000)};
nanosleep(&rqtp, nullptr); nanosleep(&rqtp, nullptr);
// TODO(benvanik): spin while rmtp >0? // TODO(benvanik): spin while rmtp >0?
} }

View File

@ -16,7 +16,6 @@
#include "xenia/base/memory.h" #include "xenia/base/memory.h"
#include "xenia/base/platform.h" #include "xenia/base/platform.h"
#include "xenia/base/string_util.h" #include "xenia/base/string_util.h"
#include "xenia/cpu/ppc/ppc_context.h"
#if XE_COMPILER_MSVC #if XE_COMPILER_MSVC
#include "xenia/base/platform_win.h" #include "xenia/base/platform_win.h"
@ -34,10 +33,10 @@ namespace cpu {
namespace test { namespace test {
struct Context { struct Context {
uint64_t r[32]; uint64_t r[32]; // 0x000
double f[32]; double f[32]; // 0x100
vec128_t v[32]; // For now, only support 32 vector registers. vec128_t v[32]; // 0x200 For now, only support 32 vector registers.
uint32_t cr; // Condition register uint32_t cr; // 0x400 Condition register
}; };
typedef std::vector<std::pair<std::string, std::string>> AnnotationList; typedef std::vector<std::pair<std::string, std::string>> AnnotationList;
@ -184,6 +183,7 @@ class TestRunner {
memory::PageAccess::kExecuteReadWrite); memory::PageAccess::kExecuteReadWrite);
context_ = memory::AlignedAlloc<Context>(32); context_ = memory::AlignedAlloc<Context>(32);
std::memset(context_, 0, sizeof(Context));
} }
~TestRunner() { ~TestRunner() {
@ -240,7 +240,6 @@ class TestRunner {
std::snprintf(out_value, out_value_size, "%016" PRIX64, ctx->r[n]); std::snprintf(out_value, out_value_size, "%016" PRIX64, ctx->r[n]);
return false; return false;
} }
return true;
} else if (sscanf(name, "f%d", &n) == 1) { } else if (sscanf(name, "f%d", &n) == 1) {
if (std::strstr(value, "0x")) { if (std::strstr(value, "0x")) {
// Special case: Treat float as integer. // Special case: Treat float as integer.
@ -265,7 +264,6 @@ class TestRunner {
return false; return false;
} }
} }
return true;
} else if (sscanf(name, "v%d", &n) == 1) { } else if (sscanf(name, "v%d", &n) == 1) {
vec128_t expected = string_util::from_string<vec128_t>(value); vec128_t expected = string_util::from_string<vec128_t>(value);
if (ctx->v[n] != expected) { if (ctx->v[n] != expected) {
@ -274,22 +272,19 @@ class TestRunner {
ctx->v[n].i32[3]); ctx->v[n].i32[3]);
return false; return false;
} }
return true;
} else if (std::strcmp(name, "cr") == 0) { } else if (std::strcmp(name, "cr") == 0) {
// TODO(DrChat) uint64_t actual = ctx->cr;
/*
uint64_t actual = ctx->cr();
uint64_t expected = string_util::from_string<uint64_t>(value); uint64_t expected = string_util::from_string<uint64_t>(value);
if (actual != expected) { if (actual != expected) {
std::snprintf(out_value, out_value_size, "%016" PRIX64, actual); std::snprintf(out_value, out_value_size, "%016" PRIX64, actual);
return false; return false;
} }
*/
return false; // true;
} else { } else {
assert_always("Unrecognized register name: %s\n", name); assert_always("Unrecognized register name: %s\n", name);
return false; return false;
} }
return true;
} }
bool SetRegFromString(const char* name, const char* value, Context* ctx) { bool SetRegFromString(const char* name, const char* value, Context* ctx) {
@ -301,10 +296,13 @@ class TestRunner {
} else if (sscanf(name, "v%d", &n) == 1) { } else if (sscanf(name, "v%d", &n) == 1) {
ctx->v[n] = string_util::from_string<vec128_t>(value); ctx->v[n] = string_util::from_string<vec128_t>(value);
} else if (std::strcmp(name, "cr") == 0) { } else if (std::strcmp(name, "cr") == 0) {
// this->set_cr(string_util::from_string<uint64_t>(value)); ctx->cr = uint32_t(string_util::from_string<uint64_t>(value));
} else { } else {
printf("Unrecognized register name: %s\n", name); printf("Unrecognized register name: %s\n", name);
return false;
} }
return true;
} }
bool SetupTestState(TestCase& test_case) { bool SetupTestState(TestCase& test_case) {
@ -480,9 +478,8 @@ bool RunTests(const std::wstring& test_name) {
} }
test_suites.push_back(std::move(test_suite)); test_suites.push_back(std::move(test_suite));
} }
if (load_failed) {
return false; XELOGI("%d tests loaded successfully.", (int)test_suites.size());
}
TestRunner runner; TestRunner runner;
for (auto& test_suite : test_suites) { for (auto& test_suite : test_suites) {

View File

@ -7,14 +7,20 @@
****************************************************************************** ******************************************************************************
*/ */
// r3 = context # r3 = context
// this does not touch r1, r3, r4, r13 # this does not touch r1, r3, r4, r13
.load_registers_ctx: .load_registers_ctx:
lwz r2, 0x400(r3) # CR
mtcrf 0xFF, r2
li r2, 0
mtxer r2
ld r0, 0x00(r3) ld r0, 0x00(r3)
// r1 cannot be used # r1 cannot be used
ld r2, 0x10(r3) ld r2, 0x10(r3)
// r3 will be loaded before the call # r3 will be loaded before the call
// r4 will be loaded before the call # r4 will be loaded before the call
ld r5, 0x28(r3) ld r5, 0x28(r3)
ld r6, 0x30(r3) ld r6, 0x30(r3)
ld r7, 0x38(r3) ld r7, 0x38(r3)
@ -23,7 +29,7 @@
ld r10, 0x50(r3) ld r10, 0x50(r3)
ld r11, 0x58(r3) ld r11, 0x58(r3)
ld r12, 0x60(r3) ld r12, 0x60(r3)
// r13 cannot be used (OS use only) # r13 cannot be used (OS use only)
ld r14, 0x70(r3) ld r14, 0x70(r3)
ld r15, 0x78(r3) ld r15, 0x78(r3)
ld r16, 0x80(r3) ld r16, 0x80(r3)
@ -42,15 +48,48 @@
ld r29, 0xE8(r3) ld r29, 0xE8(r3)
ld r30, 0xF0(r3) ld r30, 0xF0(r3)
ld r31, 0xF8(r3) ld r31, 0xF8(r3)
lfd f0, 0x100(r3)
lfd f1, 0x108(r3)
lfd f2, 0x110(r3)
lfd f3, 0x118(r3)
lfd f4, 0x120(r3)
lfd f5, 0x128(r3)
lfd f6, 0x130(r3)
lfd f7, 0x138(r3)
lfd f8, 0x140(r3)
lfd f9, 0x148(r3)
lfd f10, 0x150(r3)
lfd f11, 0x158(r3)
lfd f12, 0x160(r3)
lfd f13, 0x168(r3)
lfd f14, 0x170(r3)
lfd f15, 0x178(r3)
lfd f16, 0x180(r3)
lfd f17, 0x188(r3)
lfd f18, 0x190(r3)
lfd f19, 0x198(r3)
lfd f20, 0x1A0(r3)
lfd f21, 0x1A8(r3)
lfd f22, 0x1B0(r3)
lfd f23, 0x1B8(r3)
lfd f24, 0x1C0(r3)
lfd f25, 0x1C8(r3)
lfd f26, 0x1D0(r3)
lfd f27, 0x1D8(r3)
lfd f28, 0x1E0(r3)
lfd f29, 0x1E8(r3)
lfd f30, 0x1F0(r3)
lfd f31, 0x1F8(r3)
blr blr
// r3 = context # r3 = context
// this does not save r1, r3, r13 # this does not save r1, r3, r13
.save_registers_ctx: .save_registers_ctx:
std r0, 0x00(r3) std r0, 0x00(r3)
// r1 cannot be used # r1 cannot be used
std r2, 0x10(r3) std r2, 0x10(r3)
// r3 will be saved later # r3 will be saved later
std r4, 0x20(r3) std r4, 0x20(r3)
std r5, 0x28(r3) std r5, 0x28(r3)
std r6, 0x30(r3) std r6, 0x30(r3)
@ -60,7 +99,7 @@
std r10, 0x50(r3) std r10, 0x50(r3)
std r11, 0x58(r3) std r11, 0x58(r3)
std r12, 0x60(r3) std r12, 0x60(r3)
// r13 cannot be used (OS use only) # r13 cannot be used (OS use only)
std r14, 0x70(r3) std r14, 0x70(r3)
std r15, 0x78(r3) std r15, 0x78(r3)
std r16, 0x80(r3) std r16, 0x80(r3)
@ -79,18 +118,54 @@
std r29, 0xE8(r3) std r29, 0xE8(r3)
std r30, 0xF0(r3) std r30, 0xF0(r3)
std r31, 0xF8(r3) std r31, 0xF8(r3)
stfd f0, 0x100(r3)
stfd f1, 0x108(r3)
stfd f2, 0x110(r3)
stfd f3, 0x118(r3)
stfd f4, 0x120(r3)
stfd f5, 0x128(r3)
stfd f6, 0x130(r3)
stfd f7, 0x138(r3)
stfd f8, 0x140(r3)
stfd f9, 0x148(r3)
stfd f10, 0x150(r3)
stfd f11, 0x158(r3)
stfd f12, 0x160(r3)
stfd f13, 0x168(r3)
stfd f14, 0x170(r3)
stfd f15, 0x178(r3)
stfd f16, 0x180(r3)
stfd f17, 0x188(r3)
stfd f18, 0x190(r3)
stfd f19, 0x198(r3)
stfd f20, 0x1A0(r3)
stfd f21, 0x1A8(r3)
stfd f22, 0x1B0(r3)
stfd f23, 0x1B8(r3)
stfd f24, 0x1C0(r3)
stfd f25, 0x1C8(r3)
stfd f26, 0x1D0(r3)
stfd f27, 0x1D8(r3)
stfd f28, 0x1E0(r3)
stfd f29, 0x1E8(r3)
stfd f30, 0x1F0(r3)
stfd f31, 0x1F8(r3)
mfcr r2 # CR
stw r2, 0x400(r3)
blr blr
// void xe_call_native(Context* ctx, void* func) # void xe_call_native(Context* ctx, void* func)
.globl xe_call_native .globl xe_call_native
xe_call_native: xe_call_native:
mflr r12 mflr r12
stw r12, -0x8(r1) stw r12, -0x8(r1)
stwu r1, -0x380(r1) // 0x200(gpr + fp) + 0x200(vr) stwu r1, -0x380(r1) # 0x200(gpr + fp) + 0x200(vr)
// Save nonvolatile registers on the stack. # Save nonvolatile registers on the stack.
std r2, 0x110(r1) std r2, 0x110(r1)
std r3, 0x118(r1) // Store the context, this will be needed later. std r3, 0x118(r1) # Store the context, this will be needed later.
std r14, 0x170(r1) std r14, 0x170(r1)
std r15, 0x178(r1) std r15, 0x178(r1)
std r16, 0x180(r1) std r16, 0x180(r1)
@ -129,27 +204,27 @@ xe_call_native:
stfd f30, 0x2F0(r1) stfd f30, 0x2F0(r1)
stfd f31, 0x2F8(r1) stfd f31, 0x2F8(r1)
// Load registers from context # Load registers from context (except r3/r4)
bl load_registers_ctx bl .load_registers_ctx
// Call the test routine # Call the test routine
mtctr r4 mtctr r4
ld r4, 0x28(r3) ld r4, 0x20(r3)
ld r3, 0x20(r3) ld r3, 0x18(r3)
bctrl bctrl
// Temporarily store r3 into the stack (in the place of r0) # Temporarily store r3 into the stack (in the place of r0)
std r3, 0x100(r1) std r3, 0x100(r1)
// Store registers into context # Store registers into context (except r3)
ld r3, 0x118(r1) ld r3, 0x118(r1)
bl save_registers_ctx bl .save_registers_ctx
// Now store r3 # Now store r3
ld r4, 0x100(r1) ld r4, 0x100(r1)
std r4, 0x20(r3) std r4, 0x18(r3)
// Restore nonvolatile registers from the stack # Restore nonvolatile registers from the stack
ld r2, 0x110(r1) ld r2, 0x110(r1)
ld r14, 0x170(r1) ld r14, 0x170(r1)
ld r15, 0x178(r1) ld r15, 0x178(r1)
@ -192,4 +267,4 @@ xe_call_native:
addi r1, r1, 0x380 addi r1, r1, 0x380
lwz r12, -0x8(r1) lwz r12, -0x8(r1)
mtlr r12 mtlr r12
blr blr

View File

@ -52,14 +52,18 @@ project("xenia-cpu-ppc-nativetests")
"../../../base/main_"..platform_suffix..".cc", "../../../base/main_"..platform_suffix..".cc",
}) })
files({ files({
"*.s", "instr_*.s",
"seq_*.s",
}) })
filter("files:instr_*.s", "files:seq_*.s")
flags({"ExcludeFromBuild"})
filter({})
includedirs({ includedirs({
project_root.."/third_party/gflags/src", project_root.."/third_party/gflags/src",
}) })
filter("files:*.s") buildoptions({
flags({"ExcludeFromBuild"}) "-Wa,-mregnames", -- Tell GAS to accept register names.
filter({}) })
files({ files({
"ppc_testing_native_thunks.s", "ppc_testing_native_thunks.s",

View File

@ -850,7 +850,8 @@ class GenTestsCommand(Command):
src_files = [os.path.join(root, name) src_files = [os.path.join(root, name)
for root, dirs, files in os.walk('src') for root, dirs, files in os.walk('src')
for name in files for name in files
if name.endswith(('.s'))] if (name.startswith('instr_') or name.startswith('seq_'))
and name.endswith(('.s'))]
def make_unix_path(p): def make_unix_path(p):
"""Forces a unix path separator style, as required by binutils. """Forces a unix path separator style, as required by binutils.