Merge branch 'master' into d3d12
This commit is contained in:
commit
fac37e7c50
|
@ -41,7 +41,7 @@ legally purchased devices and games and information made public on the internet
|
||||||
|
|
||||||
## Quickstart
|
## Quickstart
|
||||||
|
|
||||||
Windows 8.1+ with Python 3.4 and [Visual Studio 2017](https://www.visualstudio.com/downloads/) and the Windows SDKs installed:
|
With Windows 8+, Python 3.4+, and [Visual Studio 2017 or 2019](https://www.visualstudio.com/downloads/) and the Windows SDKs installed:
|
||||||
|
|
||||||
> git clone https://github.com/xenia-project/xenia.git
|
> git clone https://github.com/xenia-project/xenia.git
|
||||||
> cd xenia
|
> cd xenia
|
||||||
|
@ -82,7 +82,7 @@ is wide open greenfield fun.
|
||||||
Fixes and optimizations are always welcome (please!), but in addition to
|
Fixes and optimizations are always welcome (please!), but in addition to
|
||||||
that there are some major work areas still untouched:
|
that there are some major work areas still untouched:
|
||||||
|
|
||||||
* Help work through missing functionality/bugs in game [compat](https://github.com/xenia-project/xenia/issues?labels=compat)
|
* Help work through [missing functionality/bugs in games](https://github.com/xenia-project/xenia/labels/compat)
|
||||||
* Add input drivers for [PS4 controllers](https://github.com/xenia-project/xenia/issues/60) (or anything else)
|
* Add input drivers for [PS4 controllers](https://github.com/xenia-project/xenia/issues/60) (or anything else)
|
||||||
* Skilled with Linux? A strong contributor is needed to [help with porting](https://github.com/xenia-project/xenia/labels/cross%20platform)
|
* Skilled with Linux? A strong contributor is needed to [help with porting](https://github.com/xenia-project/xenia/labels/cross%20platform)
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,9 @@ video drivers for your card.
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
* Windows 8 or later
|
* Windows 8 or later
|
||||||
* Visual Studio 2017
|
* [Visual Studio 2017 or Visual Studio 2019](https://www.visualstudio.com/downloads/)
|
||||||
* Windows Universal CRT SDK
|
|
||||||
* [Python 3.4+](https://www.python.org/downloads/)
|
* [Python 3.4+](https://www.python.org/downloads/)
|
||||||
* You will also need the [Windows 8.1 SDK](https://msdn.microsoft.com/en-us/windows/desktop/bg162891)
|
* You may also need the [Windows 8.1 SDK](https://msdn.microsoft.com/en-us/windows/desktop/bg162891)
|
||||||
* (for VS2017 just click the Windows 8.1 SDK option in the Individual Components section in the Visual Studio Installer)
|
* (for VS2017 just click the Windows 8.1 SDK option in the Individual Components section in the Visual Studio Installer)
|
||||||
|
|
||||||
Ensure Python is in your PATH.
|
Ensure Python is in your PATH.
|
||||||
|
|
|
@ -176,11 +176,16 @@ bool EmulatorWindow::Initialize() {
|
||||||
auto file_menu = MenuItem::Create(MenuItem::Type::kPopup, L"&File");
|
auto file_menu = MenuItem::Create(MenuItem::Type::kPopup, L"&File");
|
||||||
{
|
{
|
||||||
file_menu->AddChild(
|
file_menu->AddChild(
|
||||||
MenuItem::Create(MenuItem::Type::kString, L"&Open", L"Ctrl+O",
|
MenuItem::Create(MenuItem::Type::kString, L"&Open...", L"Ctrl+O",
|
||||||
std::bind(&EmulatorWindow::FileOpen, this)));
|
std::bind(&EmulatorWindow::FileOpen, this)));
|
||||||
file_menu->AddChild(
|
file_menu->AddChild(
|
||||||
MenuItem::Create(MenuItem::Type::kString, L"Close",
|
MenuItem::Create(MenuItem::Type::kString, L"Close",
|
||||||
std::bind(&EmulatorWindow::FileClose, this)));
|
std::bind(&EmulatorWindow::FileClose, this)));
|
||||||
|
file_menu->AddChild(MenuItem::Create(MenuItem::Type::kSeparator));
|
||||||
|
file_menu->AddChild(MenuItem::Create(
|
||||||
|
MenuItem::Type::kString, L"Show content directory...",
|
||||||
|
std::bind(&EmulatorWindow::ShowContentDirectory, this)));
|
||||||
|
file_menu->AddChild(MenuItem::Create(MenuItem::Type::kSeparator));
|
||||||
file_menu->AddChild(MenuItem::Create(MenuItem::Type::kString, L"E&xit",
|
file_menu->AddChild(MenuItem::Create(MenuItem::Type::kString, L"E&xit",
|
||||||
L"Alt+F4",
|
L"Alt+F4",
|
||||||
[this]() { window_->Close(); }));
|
[this]() { window_->Close(); }));
|
||||||
|
@ -251,16 +256,17 @@ bool EmulatorWindow::Initialize() {
|
||||||
{
|
{
|
||||||
help_menu->AddChild(MenuItem::Create(
|
help_menu->AddChild(MenuItem::Create(
|
||||||
MenuItem::Type::kString, L"Build commit on GitHub...", [this]() {
|
MenuItem::Type::kString, L"Build commit on GitHub...", [this]() {
|
||||||
std::string url =
|
std::wstring url =
|
||||||
std::string("https://github.com/benvanik/xenia/tree/") +
|
std::wstring(L"https://github.com/xenia-project/xenia/tree/") +
|
||||||
XE_BUILD_COMMIT + "/";
|
xe::to_wstring(XE_BUILD_COMMIT) + L"/";
|
||||||
LaunchBrowser(url.c_str());
|
LaunchBrowser(url.c_str());
|
||||||
}));
|
}));
|
||||||
help_menu->AddChild(MenuItem::Create(
|
help_menu->AddChild(MenuItem::Create(
|
||||||
MenuItem::Type::kString, L"Recent changes on GitHub...", [this]() {
|
MenuItem::Type::kString, L"Recent changes on GitHub...", [this]() {
|
||||||
std::string url =
|
std::wstring url =
|
||||||
std::string("https://github.com/benvanik/xenia/compare/") +
|
std::wstring(L"https://github.com/xenia-project/xenia/compare/") +
|
||||||
XE_BUILD_COMMIT + "..." + XE_BUILD_BRANCH;
|
xe::to_wstring(XE_BUILD_COMMIT) + L"..." +
|
||||||
|
xe::to_wstring(XE_BUILD_BRANCH);
|
||||||
LaunchBrowser(url.c_str());
|
LaunchBrowser(url.c_str());
|
||||||
}));
|
}));
|
||||||
help_menu->AddChild(MenuItem::Create(MenuItem::Type::kSeparator));
|
help_menu->AddChild(MenuItem::Create(MenuItem::Type::kSeparator));
|
||||||
|
@ -269,7 +275,7 @@ bool EmulatorWindow::Initialize() {
|
||||||
std::bind(&EmulatorWindow::ShowHelpWebsite, this)));
|
std::bind(&EmulatorWindow::ShowHelpWebsite, this)));
|
||||||
help_menu->AddChild(MenuItem::Create(
|
help_menu->AddChild(MenuItem::Create(
|
||||||
MenuItem::Type::kString, L"&About...",
|
MenuItem::Type::kString, L"&About...",
|
||||||
[this]() { LaunchBrowser("https://xenia.jp/about/"); }));
|
[this]() { LaunchBrowser(L"https://xenia.jp/about/"); }));
|
||||||
}
|
}
|
||||||
main_menu->AddChild(std::move(help_menu));
|
main_menu->AddChild(std::move(help_menu));
|
||||||
|
|
||||||
|
@ -331,6 +337,27 @@ void EmulatorWindow::FileClose() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmulatorWindow::ShowContentDirectory() {
|
||||||
|
std::wstring target_path;
|
||||||
|
|
||||||
|
auto content_root = emulator_->content_root();
|
||||||
|
if (!emulator_->is_title_open() || !emulator_->kernel_state()) {
|
||||||
|
target_path = content_root;
|
||||||
|
} else {
|
||||||
|
// TODO(gibbed): expose this via ContentManager?
|
||||||
|
wchar_t title_id[9] = L"00000000";
|
||||||
|
std::swprintf(title_id, 9, L"%.8X", emulator_->kernel_state()->title_id());
|
||||||
|
auto package_root = xe::join_paths(content_root, title_id);
|
||||||
|
target_path = package_root;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!xe::filesystem::PathExists(target_path)) {
|
||||||
|
xe::filesystem::CreateFolder(target_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchBrowser(target_path.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
void EmulatorWindow::CheckHideCursor() {
|
void EmulatorWindow::CheckHideCursor() {
|
||||||
if (!window_->is_fullscreen()) {
|
if (!window_->is_fullscreen()) {
|
||||||
// Only hide when fullscreen.
|
// Only hide when fullscreen.
|
||||||
|
@ -395,7 +422,7 @@ void EmulatorWindow::ToggleFullscreen() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmulatorWindow::ShowHelpWebsite() { LaunchBrowser("https://xenia.jp"); }
|
void EmulatorWindow::ShowHelpWebsite() { LaunchBrowser(L"https://xenia.jp"); }
|
||||||
|
|
||||||
void EmulatorWindow::UpdateTitle() {
|
void EmulatorWindow::UpdateTitle() {
|
||||||
std::wstring title(base_title_);
|
std::wstring title(base_title_);
|
||||||
|
|
|
@ -46,6 +46,7 @@ class EmulatorWindow {
|
||||||
void FileDrop(wchar_t* filename);
|
void FileDrop(wchar_t* filename);
|
||||||
void FileOpen();
|
void FileOpen();
|
||||||
void FileClose();
|
void FileClose();
|
||||||
|
void ShowContentDirectory();
|
||||||
void CheckHideCursor();
|
void CheckHideCursor();
|
||||||
void CpuTimeScalarReset();
|
void CpuTimeScalarReset();
|
||||||
void CpuTimeScalarSetHalf();
|
void CpuTimeScalarSetHalf();
|
||||||
|
|
|
@ -69,23 +69,23 @@ void av_log_callback(void* avcl, int level, const char* fmt, va_list va) {
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case AV_LOG_ERROR:
|
case AV_LOG_ERROR:
|
||||||
level_char = '!';
|
level_char = '!';
|
||||||
log_level = xe::LogLevel::LOG_LEVEL_ERROR;
|
log_level = xe::LogLevel::Error;
|
||||||
break;
|
break;
|
||||||
case AV_LOG_WARNING:
|
case AV_LOG_WARNING:
|
||||||
level_char = 'w';
|
level_char = 'w';
|
||||||
log_level = xe::LogLevel::LOG_LEVEL_WARNING;
|
log_level = xe::LogLevel::Warning;
|
||||||
break;
|
break;
|
||||||
case AV_LOG_INFO:
|
case AV_LOG_INFO:
|
||||||
level_char = 'i';
|
level_char = 'i';
|
||||||
log_level = xe::LogLevel::LOG_LEVEL_INFO;
|
log_level = xe::LogLevel::Info;
|
||||||
break;
|
break;
|
||||||
case AV_LOG_VERBOSE:
|
case AV_LOG_VERBOSE:
|
||||||
level_char = 'v';
|
level_char = 'v';
|
||||||
log_level = xe::LogLevel::LOG_LEVEL_DEBUG;
|
log_level = xe::LogLevel::Debug;
|
||||||
break;
|
break;
|
||||||
case AV_LOG_DEBUG:
|
case AV_LOG_DEBUG:
|
||||||
level_char = 'd';
|
level_char = 'd';
|
||||||
log_level = xe::LogLevel::LOG_LEVEL_DEBUG;
|
log_level = xe::LogLevel::Debug;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,18 +109,18 @@ X_STATUS XmaDecoder::Setup(kernel::KernelState* kernel_state) {
|
||||||
sizeof(XMA_CONTEXT_DATA) * kContextCount, 256, kSystemHeapPhysical);
|
sizeof(XMA_CONTEXT_DATA) * kContextCount, 256, kSystemHeapPhysical);
|
||||||
context_data_last_ptr_ =
|
context_data_last_ptr_ =
|
||||||
context_data_first_ptr_ + (sizeof(XMA_CONTEXT_DATA) * kContextCount - 1);
|
context_data_first_ptr_ + (sizeof(XMA_CONTEXT_DATA) * kContextCount - 1);
|
||||||
registers_.context_array_ptr = context_data_first_ptr_;
|
register_file_[XE_XMA_REG_CONTEXT_ARRAY_ADDRESS].u32 =
|
||||||
|
context_data_first_ptr_;
|
||||||
|
|
||||||
// Setup XMA contexts.
|
// Setup XMA contexts.
|
||||||
for (int i = 0; i < kContextCount; ++i) {
|
for (int i = 0; i < kContextCount; ++i) {
|
||||||
uint32_t guest_ptr =
|
uint32_t guest_ptr = context_data_first_ptr_ + i * sizeof(XMA_CONTEXT_DATA);
|
||||||
registers_.context_array_ptr + i * sizeof(XMA_CONTEXT_DATA);
|
|
||||||
XmaContext& context = contexts_[i];
|
XmaContext& context = contexts_[i];
|
||||||
if (context.Setup(i, memory(), guest_ptr)) {
|
if (context.Setup(i, memory(), guest_ptr)) {
|
||||||
assert_always();
|
assert_always();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
registers_.next_context = 1;
|
register_file_[XE_XMA_REG_NEXT_CONTEXT_INDEX].u32 = 1;
|
||||||
context_bitmap_.Resize(kContextCount);
|
context_bitmap_.Resize(kContextCount);
|
||||||
|
|
||||||
worker_running_ = true;
|
worker_running_ = true;
|
||||||
|
@ -185,11 +185,16 @@ void XmaDecoder::Shutdown() {
|
||||||
xe::threading::Wait(worker_thread_->thread(), false);
|
xe::threading::Wait(worker_thread_->thread(), false);
|
||||||
worker_thread_.reset();
|
worker_thread_.reset();
|
||||||
|
|
||||||
memory()->SystemHeapFree(registers_.context_array_ptr);
|
if (context_data_first_ptr_) {
|
||||||
|
memory()->SystemHeapFree(context_data_first_ptr_);
|
||||||
|
}
|
||||||
|
|
||||||
|
context_data_first_ptr_ = 0;
|
||||||
|
context_data_last_ptr_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int XmaDecoder::GetContextId(uint32_t guest_ptr) {
|
int XmaDecoder::GetContextId(uint32_t guest_ptr) {
|
||||||
static_assert(sizeof(XMA_CONTEXT_DATA) == 64, "FIXME");
|
static_assert_size(XMA_CONTEXT_DATA, 64);
|
||||||
if (guest_ptr < context_data_first_ptr_ ||
|
if (guest_ptr < context_data_first_ptr_ ||
|
||||||
guest_ptr > context_data_last_ptr_) {
|
guest_ptr > context_data_last_ptr_) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -229,51 +234,70 @@ bool XmaDecoder::BlockOnContext(uint32_t guest_ptr, bool poll) {
|
||||||
return context.Block(poll);
|
return context.Block(poll);
|
||||||
}
|
}
|
||||||
|
|
||||||
// free60 may be useful here, however it looks like it's using a different
|
|
||||||
// piece of hardware:
|
|
||||||
// https://github.com/Free60Project/libxenon/blob/master/libxenon/drivers/xenon_sound/sound.c
|
|
||||||
|
|
||||||
uint32_t XmaDecoder::ReadRegister(uint32_t addr) {
|
uint32_t XmaDecoder::ReadRegister(uint32_t addr) {
|
||||||
uint32_t r = addr & 0xFFFF;
|
uint32_t r = (addr & 0xFFFF) / 4;
|
||||||
// 1800h is read on startup and stored -- context? buffers?
|
|
||||||
// 1818h is read during a lock?
|
|
||||||
|
|
||||||
assert_true(r % 4 == 0);
|
switch (r) {
|
||||||
uint32_t value = register_file_[r / 4];
|
default: {
|
||||||
|
if (!register_file_.GetRegisterInfo(r)) {
|
||||||
// 1818 is rotating context processing # set to hardware ID of context being
|
XELOGE("XMA: Read from unknown register (%.4X)", r);
|
||||||
// processed.
|
}
|
||||||
// If bit 200h is set, the locking code will possibly collide on hardware IDs
|
}
|
||||||
// and error out, so we should never set it (I think?).
|
#pragma warning(suppress : 4065)
|
||||||
if (r == 0x1818) {
|
|
||||||
// To prevent games from seeing a stuck XMA context, return a rotating
|
|
||||||
// number
|
|
||||||
registers_.current_context = registers_.next_context;
|
|
||||||
registers_.next_context = (registers_.next_context + 1) % kContextCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
value = xe::byte_swap(value);
|
assert_true(r < XmaRegisterFile::kRegisterCount);
|
||||||
return value;
|
|
||||||
|
// 0606h (1818h) is rotating context processing # set to hardware ID of
|
||||||
|
// context being processed.
|
||||||
|
// If bit 200h is set, the locking code will possibly collide on hardware IDs
|
||||||
|
// and error out, so we should never set it (I think?).
|
||||||
|
if (r == XE_XMA_REG_CURRENT_CONTEXT_INDEX) {
|
||||||
|
// To prevent games from seeing a stuck XMA context, return a rotating
|
||||||
|
// number
|
||||||
|
uint32_t next_context_index =
|
||||||
|
register_file_[XE_XMA_REG_NEXT_CONTEXT_INDEX].u32;
|
||||||
|
register_file_[XE_XMA_REG_CURRENT_CONTEXT_INDEX].u32 = next_context_index;
|
||||||
|
register_file_[XE_XMA_REG_NEXT_CONTEXT_INDEX].u32 =
|
||||||
|
(next_context_index + 1) % kContextCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return xe::byte_swap(register_file_.values[r].u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
void XmaDecoder::WriteRegister(uint32_t addr, uint32_t value) {
|
void XmaDecoder::WriteRegister(uint32_t addr, uint32_t value) {
|
||||||
SCOPE_profile_cpu_f("apu");
|
SCOPE_profile_cpu_f("apu");
|
||||||
|
|
||||||
uint32_t r = addr & 0xFFFF;
|
uint32_t r = (addr & 0xFFFF) / 4;
|
||||||
value = xe::byte_swap(value);
|
value = xe::byte_swap(value);
|
||||||
// 1804h is written to with 0x02000000 and 0x03000000 around a lock operation
|
|
||||||
|
|
||||||
assert_true(r % 4 == 0);
|
if ((r >= XE_XMA_REG_CONTEXT_KICK_0 && r <= XE_XMA_REG_CONTEXT_KICK_9) ||
|
||||||
register_file_[r / 4] = uint32_t(value);
|
(r >= XE_XMA_REG_CONTEXT_LOCK_0 && r <= XE_XMA_REG_CONTEXT_LOCK_9) ||
|
||||||
|
(r >= XE_XMA_REG_CONTEXT_CLEAR_0 && r <= XE_XMA_REG_CONTEXT_CLEAR_9)) {
|
||||||
|
} else {
|
||||||
|
switch (r) {
|
||||||
|
default: {
|
||||||
|
XELOGE("XMA: Write to unhandled register (%.4X): %.8X", r, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#pragma warning(suppress : 4065)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (r >= 0x1940 && r <= 0x1940 + 9 * 4) {
|
// 0601h (1804h) is written to with 0x02000000 and 0x03000000 around a lock
|
||||||
|
// operation
|
||||||
|
|
||||||
|
assert_true(r < XmaRegisterFile::kRegisterCount);
|
||||||
|
register_file_.values[r].u32 = value;
|
||||||
|
|
||||||
|
if (r >= XE_XMA_REG_CONTEXT_KICK_0 && r <= XE_XMA_REG_CONTEXT_KICK_9) {
|
||||||
// Context kick command.
|
// Context kick command.
|
||||||
// This will kick off the given hardware contexts.
|
// This will kick off the given hardware contexts.
|
||||||
// Basically, this kicks the SPU and says "hey, decode that audio!"
|
// Basically, this kicks the SPU and says "hey, decode that audio!"
|
||||||
// XMAEnableContext
|
// XMAEnableContext
|
||||||
|
|
||||||
// The context ID is a bit in the range of the entire context array.
|
// The context ID is a bit in the range of the entire context array.
|
||||||
uint32_t base_context_id = (r - 0x1940) / 4 * 32;
|
uint32_t base_context_id = (r - XE_XMA_REG_CONTEXT_KICK_0) * 32;
|
||||||
for (int i = 0; value && i < 32; ++i, value >>= 1) {
|
for (int i = 0; value && i < 32; ++i, value >>= 1) {
|
||||||
if (value & 1) {
|
if (value & 1) {
|
||||||
uint32_t context_id = base_context_id + i;
|
uint32_t context_id = base_context_id + i;
|
||||||
|
@ -284,11 +308,11 @@ void XmaDecoder::WriteRegister(uint32_t addr, uint32_t value) {
|
||||||
|
|
||||||
// Signal the decoder thread to start processing.
|
// Signal the decoder thread to start processing.
|
||||||
work_event_->Set();
|
work_event_->Set();
|
||||||
} else if (r >= 0x1A40 && r <= 0x1A40 + 9 * 4) {
|
} else if (r >= XE_XMA_REG_CONTEXT_LOCK_0 && r <= XE_XMA_REG_CONTEXT_LOCK_9) {
|
||||||
// Context lock command.
|
// Context lock command.
|
||||||
// This requests a lock by flagging the context.
|
// This requests a lock by flagging the context.
|
||||||
// XMADisableContext
|
// XMADisableContext
|
||||||
uint32_t base_context_id = (r - 0x1A40) / 4 * 32;
|
uint32_t base_context_id = (r - XE_XMA_REG_CONTEXT_LOCK_0) * 32;
|
||||||
for (int i = 0; value && i < 32; ++i, value >>= 1) {
|
for (int i = 0; value && i < 32; ++i, value >>= 1) {
|
||||||
if (value & 1) {
|
if (value & 1) {
|
||||||
uint32_t context_id = base_context_id + i;
|
uint32_t context_id = base_context_id + i;
|
||||||
|
@ -299,10 +323,11 @@ void XmaDecoder::WriteRegister(uint32_t addr, uint32_t value) {
|
||||||
|
|
||||||
// Signal the decoder thread to start processing.
|
// Signal the decoder thread to start processing.
|
||||||
work_event_->Set();
|
work_event_->Set();
|
||||||
} else if (r >= 0x1A80 && r <= 0x1A80 + 9 * 4) {
|
} else if (r >= XE_XMA_REG_CONTEXT_CLEAR_0 &&
|
||||||
|
r <= XE_XMA_REG_CONTEXT_CLEAR_9) {
|
||||||
// Context clear command.
|
// Context clear command.
|
||||||
// This will reset the given hardware contexts.
|
// This will reset the given hardware contexts.
|
||||||
uint32_t base_context_id = (r - 0x1A80) / 4 * 32;
|
uint32_t base_context_id = (r - XE_XMA_REG_CONTEXT_CLEAR_0) * 32;
|
||||||
for (int i = 0; value && i < 32; ++i, value >>= 1) {
|
for (int i = 0; value && i < 32; ++i, value >>= 1) {
|
||||||
if (value & 1) {
|
if (value & 1) {
|
||||||
uint32_t context_id = base_context_id + i;
|
uint32_t context_id = base_context_id + i;
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
#include "xenia/apu/xma_context.h"
|
#include "xenia/apu/xma_context.h"
|
||||||
|
#include "xenia/apu/xma_register_file.h"
|
||||||
#include "xenia/base/bit_map.h"
|
#include "xenia/base/bit_map.h"
|
||||||
#include "xenia/kernel/xthread.h"
|
#include "xenia/kernel/xthread.h"
|
||||||
#include "xenia/xbox.h"
|
#include "xenia/xbox.h"
|
||||||
|
@ -35,7 +36,9 @@ class XmaDecoder {
|
||||||
X_STATUS Setup(kernel::KernelState* kernel_state);
|
X_STATUS Setup(kernel::KernelState* kernel_state);
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
uint32_t context_array_ptr() const { return registers_.context_array_ptr; }
|
uint32_t context_array_ptr() const {
|
||||||
|
return register_file_.values[XE_XMA_REG_CONTEXT_ARRAY_ADDRESS].u32;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t AllocateContext();
|
uint32_t AllocateContext();
|
||||||
void ReleaseContext(uint32_t guest_ptr);
|
void ReleaseContext(uint32_t guest_ptr);
|
||||||
|
@ -75,26 +78,7 @@ class XmaDecoder {
|
||||||
xe::threading::Fence pause_fence_; // Signaled when worker paused.
|
xe::threading::Fence pause_fence_; // Signaled when worker paused.
|
||||||
xe::threading::Fence resume_fence_; // Signaled when resume requested.
|
xe::threading::Fence resume_fence_; // Signaled when resume requested.
|
||||||
|
|
||||||
// Stored little endian, accessed through 0x7FEA....
|
XmaRegisterFile register_file_;
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
uint8_t ignored0[0x1800];
|
|
||||||
// 1800h; points to guest-space physical block of 320 contexts.
|
|
||||||
uint32_t context_array_ptr;
|
|
||||||
};
|
|
||||||
struct {
|
|
||||||
uint8_t ignored1[0x1818];
|
|
||||||
// 1818h; current context ID.
|
|
||||||
uint32_t current_context;
|
|
||||||
// 181Ch; next context ID to process.
|
|
||||||
uint32_t next_context;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
} registers_;
|
|
||||||
uint32_t register_file_[0xFFFF / 4];
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint32_t kContextCount = 320;
|
static const uint32_t kContextCount = 320;
|
||||||
XmaContext contexts_[kContextCount];
|
XmaContext contexts_[kContextCount];
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xenia/apu/xma_register_file.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "xenia/base/math.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace apu {
|
||||||
|
|
||||||
|
XmaRegisterFile::XmaRegisterFile() { std::memset(values, 0, sizeof(values)); }
|
||||||
|
|
||||||
|
const XmaRegisterInfo* XmaRegisterFile::GetRegisterInfo(uint32_t index) {
|
||||||
|
switch (index) {
|
||||||
|
#define XE_XMA_REGISTER(index, type, name) \
|
||||||
|
case index: { \
|
||||||
|
static const XmaRegisterInfo reg_info = { \
|
||||||
|
XmaRegisterInfo::Type::type, \
|
||||||
|
#name, \
|
||||||
|
}; \
|
||||||
|
return ®_info; \
|
||||||
|
}
|
||||||
|
#include "xenia/apu/xma_register_table.inc"
|
||||||
|
#undef XE_XMA_REGISTER
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace apu
|
||||||
|
} // namespace xe
|
|
@ -0,0 +1,54 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XENIA_APU_XMA_REGISTER_FILE_H_
|
||||||
|
#define XENIA_APU_XMA_REGISTER_FILE_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace apu {
|
||||||
|
|
||||||
|
enum XmaRegister {
|
||||||
|
#define XE_XMA_REGISTER(index, type, name) XE_XMA_REG_##name = index,
|
||||||
|
#include "xenia/apu/xma_register_table.inc"
|
||||||
|
#undef XE_XMA_REGISTER
|
||||||
|
};
|
||||||
|
|
||||||
|
struct XmaRegisterInfo {
|
||||||
|
enum class Type {
|
||||||
|
kDword,
|
||||||
|
kFloat,
|
||||||
|
};
|
||||||
|
Type type;
|
||||||
|
const char* name;
|
||||||
|
};
|
||||||
|
|
||||||
|
class XmaRegisterFile {
|
||||||
|
public:
|
||||||
|
XmaRegisterFile();
|
||||||
|
|
||||||
|
static const XmaRegisterInfo* GetRegisterInfo(uint32_t index);
|
||||||
|
|
||||||
|
static const size_t kRegisterCount = (0xFFFF + 1) / 4;
|
||||||
|
union RegisterValue {
|
||||||
|
uint32_t u32;
|
||||||
|
float f32;
|
||||||
|
};
|
||||||
|
RegisterValue values[kRegisterCount];
|
||||||
|
|
||||||
|
RegisterValue& operator[](int reg) { return values[reg]; }
|
||||||
|
RegisterValue& operator[](XmaRegister reg) { return values[reg]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace apu
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
#endif // XENIA_APU_XMA_REGISTER_FILE_H_
|
|
@ -0,0 +1,51 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
// This is a partial file designed to be included by other files when
|
||||||
|
// constructing various tables.
|
||||||
|
|
||||||
|
//#define XE_XMA_REGISTER(index, type, name)
|
||||||
|
|
||||||
|
XE_XMA_REGISTER(0x0600, kDword, CONTEXT_ARRAY_ADDRESS)
|
||||||
|
|
||||||
|
XE_XMA_REGISTER(0x0606, kDword, CURRENT_CONTEXT_INDEX)
|
||||||
|
XE_XMA_REGISTER(0x0607, kDword, NEXT_CONTEXT_INDEX)
|
||||||
|
|
||||||
|
XE_XMA_REGISTER(0x0650, kDword, CONTEXT_KICK_0)
|
||||||
|
XE_XMA_REGISTER(0x0651, kDword, CONTEXT_KICK_1)
|
||||||
|
XE_XMA_REGISTER(0x0652, kDword, CONTEXT_KICK_2)
|
||||||
|
XE_XMA_REGISTER(0x0653, kDword, CONTEXT_KICK_3)
|
||||||
|
XE_XMA_REGISTER(0x0654, kDword, CONTEXT_KICK_4)
|
||||||
|
XE_XMA_REGISTER(0x0655, kDword, CONTEXT_KICK_5)
|
||||||
|
XE_XMA_REGISTER(0x0656, kDword, CONTEXT_KICK_6)
|
||||||
|
XE_XMA_REGISTER(0x0657, kDword, CONTEXT_KICK_7)
|
||||||
|
XE_XMA_REGISTER(0x0658, kDword, CONTEXT_KICK_8)
|
||||||
|
XE_XMA_REGISTER(0x0659, kDword, CONTEXT_KICK_9)
|
||||||
|
|
||||||
|
XE_XMA_REGISTER(0x0690, kDword, CONTEXT_LOCK_0)
|
||||||
|
XE_XMA_REGISTER(0x0691, kDword, CONTEXT_LOCK_1)
|
||||||
|
XE_XMA_REGISTER(0x0692, kDword, CONTEXT_LOCK_2)
|
||||||
|
XE_XMA_REGISTER(0x0693, kDword, CONTEXT_LOCK_3)
|
||||||
|
XE_XMA_REGISTER(0x0694, kDword, CONTEXT_LOCK_4)
|
||||||
|
XE_XMA_REGISTER(0x0695, kDword, CONTEXT_LOCK_5)
|
||||||
|
XE_XMA_REGISTER(0x0696, kDword, CONTEXT_LOCK_6)
|
||||||
|
XE_XMA_REGISTER(0x0697, kDword, CONTEXT_LOCK_7)
|
||||||
|
XE_XMA_REGISTER(0x0698, kDword, CONTEXT_LOCK_8)
|
||||||
|
XE_XMA_REGISTER(0x0699, kDword, CONTEXT_LOCK_9)
|
||||||
|
|
||||||
|
XE_XMA_REGISTER(0x06A0, kDword, CONTEXT_CLEAR_0)
|
||||||
|
XE_XMA_REGISTER(0x06A1, kDword, CONTEXT_CLEAR_1)
|
||||||
|
XE_XMA_REGISTER(0x06A2, kDword, CONTEXT_CLEAR_2)
|
||||||
|
XE_XMA_REGISTER(0x06A3, kDword, CONTEXT_CLEAR_3)
|
||||||
|
XE_XMA_REGISTER(0x06A4, kDword, CONTEXT_CLEAR_4)
|
||||||
|
XE_XMA_REGISTER(0x06A5, kDword, CONTEXT_CLEAR_5)
|
||||||
|
XE_XMA_REGISTER(0x06A6, kDword, CONTEXT_CLEAR_6)
|
||||||
|
XE_XMA_REGISTER(0x06A7, kDword, CONTEXT_CLEAR_7)
|
||||||
|
XE_XMA_REGISTER(0x06A8, kDword, CONTEXT_CLEAR_8)
|
||||||
|
XE_XMA_REGISTER(0x06A9, kDword, CONTEXT_CLEAR_9)
|
|
@ -315,7 +315,7 @@ void LogLine(LogLevel log_level, const char prefix_char,
|
||||||
void FatalError(const char* fmt, ...) {
|
void FatalError(const char* fmt, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
LogLineVarargs(LogLevel::LOG_LEVEL_ERROR, 'X', fmt, args);
|
LogLineVarargs(LogLevel::Error, 'X', fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
#if XE_PLATFORM_WIN32
|
#if XE_PLATFORM_WIN32
|
||||||
|
|
|
@ -19,11 +19,17 @@ namespace xe {
|
||||||
|
|
||||||
#define XE_OPTION_ENABLE_LOGGING 1
|
#define XE_OPTION_ENABLE_LOGGING 1
|
||||||
|
|
||||||
|
// Log level is a general indication of the importance of a given log line.
|
||||||
|
//
|
||||||
|
// While log levels are named, they are a rough correlation of what the log line
|
||||||
|
// may be related to. These names should not be taken as fact as what a given
|
||||||
|
// log line from any log level actually is.
|
||||||
enum class LogLevel {
|
enum class LogLevel {
|
||||||
LOG_LEVEL_ERROR,
|
Error = 0,
|
||||||
LOG_LEVEL_WARNING,
|
Warning,
|
||||||
LOG_LEVEL_INFO,
|
Info,
|
||||||
LOG_LEVEL_DEBUG,
|
Debug,
|
||||||
|
Trace,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initializes the logging system and any outputs requested.
|
// Initializes the logging system and any outputs requested.
|
||||||
|
@ -56,25 +62,21 @@ void FatalError(const std::string& str);
|
||||||
} while (false)
|
} while (false)
|
||||||
#endif // ENABLE_LOGGING
|
#endif // ENABLE_LOGGING
|
||||||
|
|
||||||
#define XELOGE(fmt, ...) \
|
#define XELOGE(fmt, ...) XELOGCORE(xe::LogLevel::Error, '!', fmt, ##__VA_ARGS__)
|
||||||
XELOGCORE(xe::LogLevel::LOG_LEVEL_ERROR, '!', fmt, ##__VA_ARGS__)
|
|
||||||
#define XELOGW(fmt, ...) \
|
#define XELOGW(fmt, ...) \
|
||||||
XELOGCORE(xe::LogLevel::LOG_LEVEL_WARNING, 'w', fmt, ##__VA_ARGS__)
|
XELOGCORE(xe::LogLevel::Warning, 'w', fmt, ##__VA_ARGS__)
|
||||||
#define XELOGI(fmt, ...) \
|
#define XELOGI(fmt, ...) XELOGCORE(xe::LogLevel::Info, 'i', fmt, ##__VA_ARGS__)
|
||||||
XELOGCORE(xe::LogLevel::LOG_LEVEL_INFO, 'i', fmt, ##__VA_ARGS__)
|
#define XELOGD(fmt, ...) XELOGCORE(xe::LogLevel::Debug, 'd', fmt, ##__VA_ARGS__)
|
||||||
#define XELOGD(fmt, ...) \
|
|
||||||
XELOGCORE(xe::LogLevel::LOG_LEVEL_DEBUG, 'd', fmt, ##__VA_ARGS__)
|
|
||||||
|
|
||||||
#define XELOGCPU(fmt, ...) \
|
#define XELOGCPU(fmt, ...) \
|
||||||
XELOGCORE(xe::LogLevel::LOG_LEVEL_INFO, 'C', fmt, ##__VA_ARGS__)
|
XELOGCORE(xe::LogLevel::Info, 'C', fmt, ##__VA_ARGS__)
|
||||||
#define XELOGAPU(fmt, ...) \
|
#define XELOGAPU(fmt, ...) \
|
||||||
XELOGCORE(xe::LogLevel::LOG_LEVEL_INFO, 'A', fmt, ##__VA_ARGS__)
|
XELOGCORE(xe::LogLevel::Info, 'A', fmt, ##__VA_ARGS__)
|
||||||
#define XELOGGPU(fmt, ...) \
|
#define XELOGGPU(fmt, ...) \
|
||||||
XELOGCORE(xe::LogLevel::LOG_LEVEL_INFO, 'G', fmt, ##__VA_ARGS__)
|
XELOGCORE(xe::LogLevel::Info, 'G', fmt, ##__VA_ARGS__)
|
||||||
#define XELOGKERNEL(fmt, ...) \
|
#define XELOGKERNEL(fmt, ...) \
|
||||||
XELOGCORE(xe::LogLevel::LOG_LEVEL_INFO, 'K', fmt, ##__VA_ARGS__)
|
XELOGCORE(xe::LogLevel::Info, 'K', fmt, ##__VA_ARGS__)
|
||||||
#define XELOGFS(fmt, ...) \
|
#define XELOGFS(fmt, ...) XELOGCORE(xe::LogLevel::Info, 'F', fmt, ##__VA_ARGS__)
|
||||||
XELOGCORE(xe::LogLevel::LOG_LEVEL_INFO, 'F', fmt, ##__VA_ARGS__)
|
|
||||||
|
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,7 @@ const size_t kMaxPath = 1024; // PATH_MAX
|
||||||
#endif // XE_PLATFORM_WIN32
|
#endif // XE_PLATFORM_WIN32
|
||||||
|
|
||||||
// Launches a web browser to the given URL.
|
// Launches a web browser to the given URL.
|
||||||
void LaunchBrowser(const char* url);
|
void LaunchBrowser(const wchar_t* url);
|
||||||
|
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,12 @@
|
||||||
#include "xenia/base/platform_linux.h"
|
#include "xenia/base/platform_linux.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "xenia/base/string.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
|
||||||
void LaunchBrowser(const char* url) {
|
void LaunchBrowser(const wchar_t* url) {
|
||||||
auto cmd = std::string("xdg-open " + std::string(url));
|
auto cmd = std::string("xdg-open " + xe::to_string(url));
|
||||||
system(cmd.c_str());
|
system(cmd.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
|
||||||
void LaunchBrowser(const char* url) {
|
void LaunchBrowser(const wchar_t* url) {
|
||||||
ShellExecuteA(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL);
|
ShellExecuteW(NULL, L"open", url, NULL, NULL, SW_SHOWNORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -32,13 +32,12 @@ bool trace_enabled = true;
|
||||||
#define THREAD_MATCH \
|
#define THREAD_MATCH \
|
||||||
(!TARGET_THREAD || thread_state->thread_id() == TARGET_THREAD)
|
(!TARGET_THREAD || thread_state->thread_id() == TARGET_THREAD)
|
||||||
#define IFLUSH()
|
#define IFLUSH()
|
||||||
#define IPRINT(s) \
|
#define IPRINT(s) \
|
||||||
if (trace_enabled && THREAD_MATCH) \
|
if (trace_enabled && THREAD_MATCH) xe::LogLine(xe::LogLevel::Debug, 't', s)
|
||||||
xe::LogLine(xe::LogLevel::LOG_LEVEL_DEBUG, 't', s)
|
|
||||||
#define DFLUSH()
|
#define DFLUSH()
|
||||||
#define DPRINT(...) \
|
#define DPRINT(...) \
|
||||||
if (trace_enabled && THREAD_MATCH) \
|
if (trace_enabled && THREAD_MATCH) \
|
||||||
xe::LogLineFormat(xe::LogLevel::LOG_LEVEL_DEBUG, 't', __VA_ARGS__)
|
xe::LogLineFormat(xe::LogLevel::Debug, 't', __VA_ARGS__)
|
||||||
|
|
||||||
uint32_t GetTracingMode() {
|
uint32_t GetTracingMode() {
|
||||||
uint32_t mode = 0;
|
uint32_t mode = 0;
|
||||||
|
|
|
@ -804,7 +804,7 @@ void UserModule::Dump() {
|
||||||
sb.AppendFormat("\n");
|
sb.AppendFormat("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
xe::LogLine(xe::LogLevel::LOG_LEVEL_INFO, 'i', sb.GetString());
|
xe::LogLine(xe::LogLevel::Info, 'i', sb.GetString());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
|
|
|
@ -451,10 +451,10 @@ void PrintKernelCall(cpu::Export* export_entry, const Tuple& params) {
|
||||||
AppendKernelCallParams(string_buffer, export_entry, params);
|
AppendKernelCallParams(string_buffer, export_entry, params);
|
||||||
string_buffer.Append(')');
|
string_buffer.Append(')');
|
||||||
if (export_entry->tags & xe::cpu::ExportTag::kImportant) {
|
if (export_entry->tags & xe::cpu::ExportTag::kImportant) {
|
||||||
xe::LogLine(xe::LogLevel::LOG_LEVEL_INFO, 'i', string_buffer.GetString(),
|
xe::LogLine(xe::LogLevel::Info, 'i', string_buffer.GetString(),
|
||||||
string_buffer.length());
|
string_buffer.length());
|
||||||
} else {
|
} else {
|
||||||
xe::LogLine(xe::LogLevel::LOG_LEVEL_DEBUG, 'd', string_buffer.GetString(),
|
xe::LogLine(xe::LogLevel::Debug, 'd', string_buffer.GetString(),
|
||||||
string_buffer.length());
|
string_buffer.length());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ bool Win32Window::OnCreate() {
|
||||||
auto spda = (decltype(&SetProcessDpiAwareness))SetProcessDpiAwareness_;
|
auto spda = (decltype(&SetProcessDpiAwareness))SetProcessDpiAwareness_;
|
||||||
auto res = spda(PROCESS_PER_MONITOR_DPI_AWARE);
|
auto res = spda(PROCESS_PER_MONITOR_DPI_AWARE);
|
||||||
if (res != S_OK) {
|
if (res != S_OK) {
|
||||||
XELOGE("Failed to set process DPI awareness. (code = 0x%.8X)", res);
|
XELOGW("Failed to set process DPI awareness. (code = 0x%.8X)", res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue