Last stretch to get PPC native tests working
This commit is contained in:
parent
7eceb9db09
commit
737b78ad49
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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?
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue