parent
90c248146e
commit
ec326119cf
|
@ -1,6 +1,3 @@
|
||||||
[submodule "third_party/beaengine"]
|
|
||||||
path = third_party/beaengine
|
|
||||||
url = https://github.com/benvanik/beaengine.git
|
|
||||||
[submodule "third_party/xbyak"]
|
[submodule "third_party/xbyak"]
|
||||||
path = third_party/xbyak
|
path = third_party/xbyak
|
||||||
url = https://github.com/xenia-project/xbyak.git
|
url = https://github.com/xenia-project/xbyak.git
|
||||||
|
|
|
@ -168,7 +168,6 @@ solution("xenia")
|
||||||
include("src/xenia/ui/gl")
|
include("src/xenia/ui/gl")
|
||||||
include("src/xenia/vfs")
|
include("src/xenia/vfs")
|
||||||
|
|
||||||
include("third_party/beaengine.lua")
|
|
||||||
include("third_party/capstone.lua")
|
include("third_party/capstone.lua")
|
||||||
include("third_party/elemental-forms")
|
include("third_party/elemental-forms")
|
||||||
include("third_party/glew.lua")
|
include("third_party/glew.lua")
|
||||||
|
|
|
@ -8,7 +8,6 @@ project("xenia-app")
|
||||||
targetname("xenia")
|
targetname("xenia")
|
||||||
language("C++")
|
language("C++")
|
||||||
links({
|
links({
|
||||||
"beaengine",
|
|
||||||
"elemental-forms",
|
"elemental-forms",
|
||||||
"gflags",
|
"gflags",
|
||||||
"xenia-apu",
|
"xenia-apu",
|
||||||
|
|
|
@ -175,7 +175,7 @@ bool XmaDecoder::BlockOnContext(uint32_t guest_ptr, bool poll) {
|
||||||
// piece of hardware:
|
// piece of hardware:
|
||||||
// https://github.com/Free60Project/libxenon/blob/master/libxenon/drivers/xenon_sound/sound.c
|
// https://github.com/Free60Project/libxenon/blob/master/libxenon/drivers/xenon_sound/sound.c
|
||||||
|
|
||||||
uint64_t XmaDecoder::ReadRegister(uint32_t addr) {
|
uint32_t XmaDecoder::ReadRegister(uint32_t addr) {
|
||||||
uint32_t r = addr & 0xFFFF;
|
uint32_t r = addr & 0xFFFF;
|
||||||
XELOGAPU("ReadRegister(%.4X)", r);
|
XELOGAPU("ReadRegister(%.4X)", r);
|
||||||
// 1800h is read on startup and stored -- context? buffers?
|
// 1800h is read on startup and stored -- context? buffers?
|
||||||
|
@ -200,11 +200,11 @@ uint64_t XmaDecoder::ReadRegister(uint32_t addr) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void XmaDecoder::WriteRegister(uint32_t addr, uint64_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;
|
||||||
value = xe::byte_swap(uint32_t(value));
|
value = xe::byte_swap(value);
|
||||||
XELOGAPU("WriteRegister(%.4X, %.8X)", r, value);
|
XELOGAPU("WriteRegister(%.4X, %.8X)", r, value);
|
||||||
// 1804h is written to with 0x02000000 and 0x03000000 around a lock operation
|
// 1804h is written to with 0x02000000 and 0x03000000 around a lock operation
|
||||||
|
|
||||||
|
|
|
@ -47,8 +47,8 @@ class XmaDecoder {
|
||||||
void ReleaseContext(uint32_t guest_ptr);
|
void ReleaseContext(uint32_t guest_ptr);
|
||||||
bool BlockOnContext(uint32_t guest_ptr, bool poll);
|
bool BlockOnContext(uint32_t guest_ptr, bool poll);
|
||||||
|
|
||||||
virtual uint64_t ReadRegister(uint32_t addr);
|
virtual uint32_t ReadRegister(uint32_t addr);
|
||||||
virtual void WriteRegister(uint32_t addr, uint64_t value);
|
virtual void WriteRegister(uint32_t addr, uint32_t value);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int GetContextId(uint32_t guest_ptr);
|
int GetContextId(uint32_t guest_ptr);
|
||||||
|
@ -56,12 +56,12 @@ class XmaDecoder {
|
||||||
private:
|
private:
|
||||||
void WorkerThreadMain();
|
void WorkerThreadMain();
|
||||||
|
|
||||||
static uint64_t MMIOReadRegisterThunk(void* ppc_context, XmaDecoder* as,
|
static uint32_t MMIOReadRegisterThunk(void* ppc_context, XmaDecoder* as,
|
||||||
uint32_t addr) {
|
uint32_t addr) {
|
||||||
return as->ReadRegister(addr);
|
return as->ReadRegister(addr);
|
||||||
}
|
}
|
||||||
static void MMIOWriteRegisterThunk(void* ppc_context, XmaDecoder* as,
|
static void MMIOWriteRegisterThunk(void* ppc_context, XmaDecoder* as,
|
||||||
uint32_t addr, uint64_t value) {
|
uint32_t addr, uint32_t value) {
|
||||||
as->WriteRegister(addr, value);
|
as->WriteRegister(addr, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@ project("xenia-cpu-backend-x64")
|
||||||
"XBYAK_NO_OP_NAMES",
|
"XBYAK_NO_OP_NAMES",
|
||||||
})
|
})
|
||||||
includedirs({
|
includedirs({
|
||||||
project_root.."/third_party/beaengine/include",
|
|
||||||
project_root.."/third_party/capstone/include",
|
project_root.."/third_party/capstone/include",
|
||||||
})
|
})
|
||||||
local_platform_files()
|
local_platform_files()
|
||||||
|
|
|
@ -7,7 +7,6 @@ project("xenia-cpu-frontend-tests")
|
||||||
kind("ConsoleApp")
|
kind("ConsoleApp")
|
||||||
language("C++")
|
language("C++")
|
||||||
links({
|
links({
|
||||||
"beaengine",
|
|
||||||
"gflags",
|
"gflags",
|
||||||
"xenia-base",
|
"xenia-base",
|
||||||
"xenia-core",
|
"xenia-core",
|
||||||
|
|
|
@ -11,13 +11,10 @@
|
||||||
|
|
||||||
#include "xenia/base/assert.h"
|
#include "xenia/base/assert.h"
|
||||||
#include "xenia/base/byte_order.h"
|
#include "xenia/base/byte_order.h"
|
||||||
|
#include "xenia/base/logging.h"
|
||||||
#include "xenia/base/math.h"
|
#include "xenia/base/math.h"
|
||||||
#include "xenia/base/memory.h"
|
#include "xenia/base/memory.h"
|
||||||
|
|
||||||
namespace BE {
|
|
||||||
#include <beaengine/BeaEngine.h>
|
|
||||||
} // namespace BE
|
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
|
||||||
|
@ -71,7 +68,7 @@ MMIORange* MMIOHandler::LookupRange(uint32_t virtual_address) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MMIOHandler::CheckLoad(uint32_t virtual_address, uint64_t* out_value) {
|
bool MMIOHandler::CheckLoad(uint32_t virtual_address, uint32_t* out_value) {
|
||||||
for (const auto& range : mapped_ranges_) {
|
for (const auto& range : mapped_ranges_) {
|
||||||
if ((virtual_address & range.mask) == range.address) {
|
if ((virtual_address & range.mask) == range.address) {
|
||||||
*out_value = static_cast<uint32_t>(
|
*out_value = static_cast<uint32_t>(
|
||||||
|
@ -82,7 +79,7 @@ bool MMIOHandler::CheckLoad(uint32_t virtual_address, uint64_t* out_value) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MMIOHandler::CheckStore(uint32_t virtual_address, uint64_t value) {
|
bool MMIOHandler::CheckStore(uint32_t virtual_address, uint32_t value) {
|
||||||
for (const auto& range : mapped_ranges_) {
|
for (const auto& range : mapped_ranges_) {
|
||||||
if ((virtual_address & range.mask) == range.address) {
|
if ((virtual_address & range.mask) == range.address) {
|
||||||
range.write(nullptr, range.callback_context, virtual_address, value);
|
range.write(nullptr, range.callback_context, virtual_address, value);
|
||||||
|
@ -205,6 +202,167 @@ bool MMIOHandler::CheckWriteWatch(void* thread_state, uint64_t fault_address) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct DecodedMov {
|
||||||
|
size_t length;
|
||||||
|
// Inidicates this is a load (or conversely a store).
|
||||||
|
bool is_load;
|
||||||
|
// Indicates the memory must be swapped.
|
||||||
|
bool byte_swap;
|
||||||
|
// Source (for store) or target (for load) register.
|
||||||
|
// AX CX DX BX SP BP SI DI // REX.R=0
|
||||||
|
// R8 R9 R10 R11 R12 R13 R14 R15 // REX.R=1
|
||||||
|
uint32_t value_reg;
|
||||||
|
// [base + (index * scale) + displacement]
|
||||||
|
bool mem_has_base;
|
||||||
|
uint8_t mem_base_reg;
|
||||||
|
bool mem_has_index;
|
||||||
|
uint8_t mem_index_reg;
|
||||||
|
uint8_t mem_scale;
|
||||||
|
int32_t mem_displacement;
|
||||||
|
bool is_constant;
|
||||||
|
int32_t constant;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool TryDecodeMov(const uint8_t* p, DecodedMov& mov) {
|
||||||
|
uint8_t i = 0; // Current byte decode index.
|
||||||
|
uint8_t rex = 0;
|
||||||
|
if ((p[i] & 0xF0) == 0x40) {
|
||||||
|
rex = p[0];
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
if (p[i] == 0x0F && p[i + 1] == 0x38 && p[i + 2] == 0xF1) {
|
||||||
|
// MOVBE m32, r32 (store)
|
||||||
|
// http://www.tptp.cc/mirrors/siyobik.info/instruction/MOVBE.html
|
||||||
|
// 44 0f 38 f1 a4 02 00 movbe DWORD PTR [rdx+rax*1+0x0],r12d
|
||||||
|
// 42 0f 38 f1 8c 22 00 movbe DWORD PTR [rdx+r12*1+0x0],ecx
|
||||||
|
// 0f 38 f1 8c 02 00 00 movbe DWORD PTR [rdx + rax * 1 + 0x0], ecx
|
||||||
|
mov.is_load = false;
|
||||||
|
mov.byte_swap = true;
|
||||||
|
i += 3;
|
||||||
|
} else if (p[i] == 0x0F && p[i + 1] == 0x38 && p[i + 2] == 0xF0) {
|
||||||
|
// MOVBE r32, m32 (load)
|
||||||
|
// http://www.tptp.cc/mirrors/siyobik.info/instruction/MOVBE.html
|
||||||
|
// 44 0f 38 f0 a4 02 00 movbe r12d,DWORD PTR [rdx+rax*1+0x0]
|
||||||
|
// 42 0f 38 f0 8c 22 00 movbe ecx,DWORD PTR [rdx+r12*1+0x0]
|
||||||
|
// 46 0f 38 f0 a4 22 00 movbe r12d,DWORD PTR [rdx+r12*1+0x0]
|
||||||
|
// 0f 38 f0 8c 02 00 00 movbe ecx,DWORD PTR [rdx+rax*1+0x0]
|
||||||
|
// 0F 38 F0 1C 02 movbe ebx,dword ptr [rdx+rax]
|
||||||
|
mov.is_load = true;
|
||||||
|
mov.byte_swap = true;
|
||||||
|
i += 3;
|
||||||
|
} else if (p[i] == 0x89) {
|
||||||
|
// MOV m32, r32 (store)
|
||||||
|
// http://www.tptp.cc/mirrors/siyobik.info/instruction/MOV.html
|
||||||
|
// 44 89 24 02 mov DWORD PTR[rdx + rax * 1], r12d
|
||||||
|
// 42 89 0c 22 mov DWORD PTR[rdx + r12 * 1], ecx
|
||||||
|
// 89 0c 02 mov DWORD PTR[rdx + rax * 1], ecx
|
||||||
|
mov.is_load = false;
|
||||||
|
mov.byte_swap = false;
|
||||||
|
++i;
|
||||||
|
} else if (p[i] == 0x8B) {
|
||||||
|
// MOV r32, m32 (load)
|
||||||
|
// http://www.tptp.cc/mirrors/siyobik.info/instruction/MOV.html
|
||||||
|
// 44 8b 24 02 mov r12d, DWORD PTR[rdx + rax * 1]
|
||||||
|
// 42 8b 0c 22 mov ecx, DWORD PTR[rdx + r12 * 1]
|
||||||
|
// 46 8b 24 22 mov r12d, DWORD PTR[rdx + r12 * 1]
|
||||||
|
// 8b 0c 02 mov ecx, DWORD PTR[rdx + rax * 1]
|
||||||
|
mov.is_load = true;
|
||||||
|
mov.byte_swap = false;
|
||||||
|
++i;
|
||||||
|
} else if (p[i] == 0xC7) {
|
||||||
|
// MOV m32, simm32
|
||||||
|
// http://www.asmpedia.org/index.php?title=MOV
|
||||||
|
// C7 04 02 02 00 00 00 mov dword ptr [rdx+rax],2
|
||||||
|
mov.is_load = false;
|
||||||
|
mov.byte_swap = false;
|
||||||
|
mov.is_constant = true;
|
||||||
|
++i;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t rex_b = rex & 0b0001;
|
||||||
|
uint8_t rex_x = rex & 0b0010;
|
||||||
|
uint8_t rex_r = rex & 0b0100;
|
||||||
|
uint8_t rex_w = rex & 0b1000;
|
||||||
|
|
||||||
|
// http://www.sandpile.org/x86/opc_rm.htm
|
||||||
|
// http://www.sandpile.org/x86/opc_sib.htm
|
||||||
|
uint8_t modrm = p[i++];
|
||||||
|
uint8_t mod = (modrm & 0b11000000) >> 6;
|
||||||
|
uint8_t reg = (modrm & 0b00111000) >> 3;
|
||||||
|
uint8_t rm = (modrm & 0b00000111);
|
||||||
|
mov.value_reg = reg + (rex_r ? 8 : 0);
|
||||||
|
mov.mem_has_base = false;
|
||||||
|
mov.mem_base_reg = 0;
|
||||||
|
mov.mem_has_index = false;
|
||||||
|
mov.mem_index_reg = 0;
|
||||||
|
mov.mem_scale = 1;
|
||||||
|
mov.mem_displacement = 0;
|
||||||
|
bool has_sib = false;
|
||||||
|
switch (rm) {
|
||||||
|
case 0b100: // SIB
|
||||||
|
has_sib = true;
|
||||||
|
break;
|
||||||
|
case 0b101:
|
||||||
|
if (mod == 0b00) {
|
||||||
|
// RIP-relative not supported.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mov.mem_has_base = true;
|
||||||
|
mov.mem_base_reg = rm + (rex_b ? 8 : 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mov.mem_has_base = true;
|
||||||
|
mov.mem_base_reg = rm + (rex_b ? 8 : 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (has_sib) {
|
||||||
|
uint8_t sib = p[i++];
|
||||||
|
mov.mem_scale = 1 << ((sib & 0b11000000) >> 8);
|
||||||
|
uint8_t sib_index = (sib & 0b00111000) >> 3;
|
||||||
|
uint8_t sib_base = (sib & 0b00000111);
|
||||||
|
switch (sib_index) {
|
||||||
|
case 0b100:
|
||||||
|
// No index.
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mov.mem_has_index = true;
|
||||||
|
mov.mem_index_reg = sib_index + (rex_x ? 8 : 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (sib_base) {
|
||||||
|
case 0b101:
|
||||||
|
// Alternate rbp-relative addressing not supported.
|
||||||
|
assert_zero(mod);
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
mov.mem_has_base = true;
|
||||||
|
mov.mem_base_reg = sib_base + (rex_b ? 8 : 0);
|
||||||
|
;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (mod) {
|
||||||
|
case 0b00: {
|
||||||
|
mov.mem_displacement += 0;
|
||||||
|
} break;
|
||||||
|
case 0b01: {
|
||||||
|
mov.mem_displacement += int8_t(p[i++]);
|
||||||
|
} break;
|
||||||
|
case 0b10: {
|
||||||
|
mov.mem_displacement += xe::load<int32_t>(p + i);
|
||||||
|
i += 4;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
if (mov.is_constant) {
|
||||||
|
mov.constant = xe::load<int32_t>(p + i);
|
||||||
|
i += 4;
|
||||||
|
}
|
||||||
|
mov.length = i;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool MMIOHandler::HandleAccessFault(void* thread_state,
|
bool MMIOHandler::HandleAccessFault(void* thread_state,
|
||||||
uint64_t fault_address) {
|
uint64_t fault_address) {
|
||||||
if (fault_address < uint64_t(virtual_membase_)) {
|
if (fault_address < uint64_t(virtual_membase_)) {
|
||||||
|
@ -230,94 +388,46 @@ bool MMIOHandler::HandleAccessFault(void* thread_state,
|
||||||
return CheckWriteWatch(thread_state, fault_address);
|
return CheckWriteWatch(thread_state, fault_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(benvanik): replace with simple check of mov (that's all
|
|
||||||
// we care about).
|
|
||||||
auto rip = GetThreadStateRip(thread_state);
|
auto rip = GetThreadStateRip(thread_state);
|
||||||
BE::DISASM disasm = {0};
|
auto p = reinterpret_cast<const uint8_t*>(rip);
|
||||||
disasm.Archi = 64;
|
DecodedMov mov = {0};
|
||||||
disasm.Options = BE::MasmSyntax + BE::PrefixedNumeral;
|
bool decoded = TryDecodeMov(p, mov);
|
||||||
disasm.EIP = static_cast<BE::UIntPtr>(rip);
|
if (!decoded) {
|
||||||
size_t instr_length = BE::Disasm(&disasm);
|
XELOGE("Unable to decode MMIO mov at %p", p);
|
||||||
if (instr_length == BE::UNKNOWN_OPCODE) {
|
|
||||||
// Failed to decode instruction. Either it's an unhandled mov case or
|
|
||||||
// not a mov.
|
|
||||||
assert_always();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t arg1_type = disasm.Argument1.ArgType;
|
|
||||||
int32_t arg2_type = disasm.Argument2.ArgType;
|
|
||||||
bool is_load = (arg1_type & BE::REGISTER_TYPE) == BE::REGISTER_TYPE &&
|
|
||||||
(arg1_type & BE::GENERAL_REG) == BE::GENERAL_REG &&
|
|
||||||
(disasm.Argument1.AccessMode & BE::WRITE) == BE::WRITE;
|
|
||||||
bool is_store = (arg1_type & BE::MEMORY_TYPE) == BE::MEMORY_TYPE &&
|
|
||||||
(((arg2_type & BE::REGISTER_TYPE) == BE::REGISTER_TYPE &&
|
|
||||||
(arg2_type & BE::GENERAL_REG) == BE::GENERAL_REG) ||
|
|
||||||
(arg2_type & BE::CONSTANT_TYPE) == BE::CONSTANT_TYPE) &&
|
|
||||||
(disasm.Argument1.AccessMode & BE::WRITE) == BE::WRITE;
|
|
||||||
if (is_load) {
|
|
||||||
// Load of a memory value - read from range, swap, and store in the
|
|
||||||
// register.
|
|
||||||
uint64_t value = range->read(nullptr, range->callback_context,
|
|
||||||
fault_address & 0xFFFFFFFF);
|
|
||||||
uint32_t be_reg_index;
|
|
||||||
if (!xe::bit_scan_forward(arg1_type & 0xFFFF, &be_reg_index)) {
|
|
||||||
be_reg_index = 0;
|
|
||||||
}
|
|
||||||
uint64_t* reg_ptr = GetThreadStateRegPtr(thread_state, be_reg_index);
|
|
||||||
switch (disasm.Argument1.ArgSize) {
|
|
||||||
case 8:
|
|
||||||
*reg_ptr = static_cast<uint8_t>(value);
|
|
||||||
break;
|
|
||||||
case 16:
|
|
||||||
*reg_ptr = xe::byte_swap(static_cast<uint16_t>(value));
|
|
||||||
break;
|
|
||||||
case 32:
|
|
||||||
*reg_ptr = xe::byte_swap(static_cast<uint32_t>(value));
|
|
||||||
break;
|
|
||||||
case 64:
|
|
||||||
*reg_ptr = xe::byte_swap(static_cast<uint64_t>(value));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (is_store) {
|
|
||||||
// Store of a register value - read register, swap, write to range.
|
|
||||||
uint64_t value = 0;
|
|
||||||
if ((arg2_type & BE::REGISTER_TYPE) == BE::REGISTER_TYPE) {
|
|
||||||
uint32_t be_reg_index;
|
|
||||||
if (!xe::bit_scan_forward(arg2_type & 0xFFFF, &be_reg_index)) {
|
|
||||||
be_reg_index = 0;
|
|
||||||
}
|
|
||||||
uint64_t* reg_ptr = GetThreadStateRegPtr(thread_state, be_reg_index);
|
|
||||||
value = *reg_ptr;
|
|
||||||
} else if ((arg2_type & BE::CONSTANT_TYPE) == BE::CONSTANT_TYPE) {
|
|
||||||
value = disasm.Instruction.Immediat;
|
|
||||||
} else {
|
|
||||||
// Unknown destination type in mov.
|
|
||||||
assert_always();
|
|
||||||
}
|
|
||||||
switch (disasm.Argument2.ArgSize) {
|
|
||||||
case 8:
|
|
||||||
value = static_cast<uint8_t>(value);
|
|
||||||
break;
|
|
||||||
case 16:
|
|
||||||
value = xe::byte_swap(static_cast<uint16_t>(value));
|
|
||||||
break;
|
|
||||||
case 32:
|
|
||||||
value = xe::byte_swap(static_cast<uint32_t>(value));
|
|
||||||
break;
|
|
||||||
case 64:
|
|
||||||
value = xe::byte_swap(static_cast<uint64_t>(value));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
range->write(nullptr, range->callback_context, fault_address & 0xFFFFFFFF,
|
|
||||||
value);
|
|
||||||
} else {
|
|
||||||
assert_always("Unknown MMIO instruction type");
|
assert_always("Unknown MMIO instruction type");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mov.is_load) {
|
||||||
|
// Load of a memory value - read from range, swap, and store in the
|
||||||
|
// register.
|
||||||
|
uint32_t value = range->read(nullptr, range->callback_context,
|
||||||
|
fault_address & 0xFFFFFFFF);
|
||||||
|
uint64_t* reg_ptr = GetThreadStateRegPtr(thread_state, mov.value_reg);
|
||||||
|
if (!mov.byte_swap) {
|
||||||
|
// We swap only if it's not a movbe, as otherwise we are swapping twice.
|
||||||
|
value = xe::byte_swap(value);
|
||||||
|
}
|
||||||
|
*reg_ptr = value;
|
||||||
|
} else {
|
||||||
|
// Store of a register value - read register, swap, write to range.
|
||||||
|
int32_t value;
|
||||||
|
if (mov.is_constant) {
|
||||||
|
value = uint32_t(mov.constant);
|
||||||
|
} else {
|
||||||
|
uint64_t* reg_ptr = GetThreadStateRegPtr(thread_state, mov.value_reg);
|
||||||
|
value = static_cast<uint32_t>(*reg_ptr);
|
||||||
|
if (!mov.byte_swap) {
|
||||||
|
// We swap only if it's not a movbe, as otherwise we are swapping twice.
|
||||||
|
value = xe::byte_swap(static_cast<uint32_t>(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
range->write(nullptr, range->callback_context, fault_address & 0xFFFFFFFF,
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
|
||||||
// Advance RIP to the next instruction so that we resume properly.
|
// Advance RIP to the next instruction so that we resume properly.
|
||||||
SetThreadStateRip(thread_state, rip + instr_length);
|
SetThreadStateRip(thread_state, rip + mov.length);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,10 @@
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
|
||||||
typedef uint64_t (*MMIOReadCallback)(void* ppc_context, void* callback_context,
|
typedef uint32_t (*MMIOReadCallback)(void* ppc_context, void* callback_context,
|
||||||
uint32_t addr);
|
uint32_t addr);
|
||||||
typedef void (*MMIOWriteCallback)(void* ppc_context, void* callback_context,
|
typedef void (*MMIOWriteCallback)(void* ppc_context, void* callback_context,
|
||||||
uint32_t addr, uint64_t value);
|
uint32_t addr, uint32_t value);
|
||||||
|
|
||||||
typedef void (*WriteWatchCallback)(void* context_ptr, void* data_ptr,
|
typedef void (*WriteWatchCallback)(void* context_ptr, void* data_ptr,
|
||||||
uint32_t address);
|
uint32_t address);
|
||||||
|
@ -51,8 +51,8 @@ class MMIOHandler {
|
||||||
MMIOWriteCallback write_callback);
|
MMIOWriteCallback write_callback);
|
||||||
MMIORange* LookupRange(uint32_t virtual_address);
|
MMIORange* LookupRange(uint32_t virtual_address);
|
||||||
|
|
||||||
bool CheckLoad(uint32_t virtual_address, uint64_t* out_value);
|
bool CheckLoad(uint32_t virtual_address, uint32_t* out_value);
|
||||||
bool CheckStore(uint32_t virtual_address, uint64_t value);
|
bool CheckStore(uint32_t virtual_address, uint32_t value);
|
||||||
|
|
||||||
uintptr_t AddPhysicalWriteWatch(uint32_t guest_address, size_t length,
|
uintptr_t AddPhysicalWriteWatch(uint32_t guest_address, size_t length,
|
||||||
WriteWatchCallback callback,
|
WriteWatchCallback callback,
|
||||||
|
|
|
@ -33,7 +33,7 @@ class WinMMIOHandler : public MMIOHandler {
|
||||||
uint64_t GetThreadStateRip(void* thread_state_ptr) override;
|
uint64_t GetThreadStateRip(void* thread_state_ptr) override;
|
||||||
void SetThreadStateRip(void* thread_state_ptr, uint64_t rip) override;
|
void SetThreadStateRip(void* thread_state_ptr, uint64_t rip) override;
|
||||||
uint64_t* GetThreadStateRegPtr(void* thread_state_ptr,
|
uint64_t* GetThreadStateRegPtr(void* thread_state_ptr,
|
||||||
int32_t be_reg_index) override;
|
int32_t reg_index) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<MMIOHandler> CreateMMIOHandler(uint8_t* virtual_membase,
|
std::unique_ptr<MMIOHandler> CreateMMIOHandler(uint8_t* virtual_membase,
|
||||||
|
@ -99,10 +99,10 @@ void WinMMIOHandler::SetThreadStateRip(void* thread_state_ptr, uint64_t rip) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t* WinMMIOHandler::GetThreadStateRegPtr(void* thread_state_ptr,
|
uint64_t* WinMMIOHandler::GetThreadStateRegPtr(void* thread_state_ptr,
|
||||||
int32_t be_reg_index) {
|
int32_t reg_index) {
|
||||||
auto context = reinterpret_cast<LPCONTEXT>(thread_state_ptr);
|
auto context = reinterpret_cast<LPCONTEXT>(thread_state_ptr);
|
||||||
// BeaEngine register indices line up with the CONTEXT structure format.
|
// Register indices line up with the CONTEXT structure format.
|
||||||
return &context->Rax + be_reg_index;
|
return &context->Rax + reg_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace cpu
|
} // namespace cpu
|
||||||
|
|
|
@ -7,14 +7,9 @@ project("xenia-cpu")
|
||||||
kind("StaticLib")
|
kind("StaticLib")
|
||||||
language("C++")
|
language("C++")
|
||||||
links({
|
links({
|
||||||
"beaengine",
|
|
||||||
"xenia-base",
|
"xenia-base",
|
||||||
})
|
})
|
||||||
defines({
|
|
||||||
"BEA_ENGINE_STATIC=1",
|
|
||||||
})
|
|
||||||
includedirs({
|
includedirs({
|
||||||
project_root.."/third_party/beaengine/include",
|
|
||||||
project_root.."/third_party/llvm/include",
|
project_root.."/third_party/llvm/include",
|
||||||
})
|
})
|
||||||
local_platform_files()
|
local_platform_files()
|
||||||
|
|
|
@ -7,7 +7,6 @@ project("xenia-debug-ui")
|
||||||
kind("WindowedApp")
|
kind("WindowedApp")
|
||||||
language("C++")
|
language("C++")
|
||||||
links({
|
links({
|
||||||
"beaengine",
|
|
||||||
"elemental-forms",
|
"elemental-forms",
|
||||||
"gflags",
|
"gflags",
|
||||||
"xenia-apu",
|
"xenia-apu",
|
||||||
|
|
|
@ -315,7 +315,7 @@ void GL4GraphicsSystem::Swap(xe::ui::UIEvent& e) {
|
||||||
GL_LINEAR);
|
GL_LINEAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t GL4GraphicsSystem::ReadRegister(uint32_t addr) {
|
uint32_t GL4GraphicsSystem::ReadRegister(uint32_t addr) {
|
||||||
uint32_t r = addr & 0xFFFF;
|
uint32_t r = addr & 0xFFFF;
|
||||||
|
|
||||||
switch (r) {
|
switch (r) {
|
||||||
|
@ -335,12 +335,12 @@ uint64_t GL4GraphicsSystem::ReadRegister(uint32_t addr) {
|
||||||
return register_file_.values[r].u32;
|
return register_file_.values[r].u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GL4GraphicsSystem::WriteRegister(uint32_t addr, uint64_t value) {
|
void GL4GraphicsSystem::WriteRegister(uint32_t addr, uint32_t value) {
|
||||||
uint32_t r = addr & 0xFFFF;
|
uint32_t r = addr & 0xFFFF;
|
||||||
|
|
||||||
switch (r) {
|
switch (r) {
|
||||||
case 0x0714: // CP_RB_WPTR
|
case 0x0714: // CP_RB_WPTR
|
||||||
command_processor_->UpdateWritePointer(static_cast<uint32_t>(value));
|
command_processor_->UpdateWritePointer(value);
|
||||||
break;
|
break;
|
||||||
case 0x6110: // ? swap related?
|
case 0x6110: // ? swap related?
|
||||||
XELOGW("Unimplemented GPU register %.4X write: %.8X", r, value);
|
XELOGW("Unimplemented GPU register %.4X write: %.8X", r, value);
|
||||||
|
@ -351,7 +351,7 @@ void GL4GraphicsSystem::WriteRegister(uint32_t addr, uint64_t value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_true(r < RegisterFile::kRegisterCount);
|
assert_true(r < RegisterFile::kRegisterCount);
|
||||||
register_file_.values[r].u32 = static_cast<uint32_t>(value);
|
register_file_.values[r].u32 = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace gl4
|
} // namespace gl4
|
||||||
|
|
|
@ -52,15 +52,15 @@ class GL4GraphicsSystem : public GraphicsSystem {
|
||||||
private:
|
private:
|
||||||
void MarkVblank();
|
void MarkVblank();
|
||||||
void Swap(xe::ui::UIEvent& e);
|
void Swap(xe::ui::UIEvent& e);
|
||||||
uint64_t ReadRegister(uint32_t addr);
|
uint32_t ReadRegister(uint32_t addr);
|
||||||
void WriteRegister(uint32_t addr, uint64_t value);
|
void WriteRegister(uint32_t addr, uint32_t value);
|
||||||
|
|
||||||
static uint64_t MMIOReadRegisterThunk(void* ppc_context,
|
static uint32_t MMIOReadRegisterThunk(void* ppc_context,
|
||||||
GL4GraphicsSystem* gs, uint32_t addr) {
|
GL4GraphicsSystem* gs, uint32_t addr) {
|
||||||
return gs->ReadRegister(addr);
|
return gs->ReadRegister(addr);
|
||||||
}
|
}
|
||||||
static void MMIOWriteRegisterThunk(void* ppc_context, GL4GraphicsSystem* gs,
|
static void MMIOWriteRegisterThunk(void* ppc_context, GL4GraphicsSystem* gs,
|
||||||
uint32_t addr, uint64_t value) {
|
uint32_t addr, uint32_t value) {
|
||||||
gs->WriteRegister(addr, value);
|
gs->WriteRegister(addr, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,6 @@ project("xenia-gpu-gl4-trace-viewer")
|
||||||
kind("WindowedApp")
|
kind("WindowedApp")
|
||||||
language("C++")
|
language("C++")
|
||||||
links({
|
links({
|
||||||
"beaengine",
|
|
||||||
"elemental-forms",
|
"elemental-forms",
|
||||||
"gflags",
|
"gflags",
|
||||||
"glew",
|
"glew",
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit ee1add269fa3487f9157fffb4c360051e3e5ed7f
|
|
|
@ -1,20 +0,0 @@
|
||||||
group("third_party")
|
|
||||||
project("beaengine")
|
|
||||||
uuid("56e7d457-9955-4217-aadf-52e5ab45afab")
|
|
||||||
kind("StaticLib")
|
|
||||||
language("C++")
|
|
||||||
links({
|
|
||||||
})
|
|
||||||
defines({
|
|
||||||
"BEA_ENGINE_STATIC=1",
|
|
||||||
"_LIB",
|
|
||||||
})
|
|
||||||
includedirs({
|
|
||||||
"beaengine/include",
|
|
||||||
"beaengine/beaengineSources",
|
|
||||||
})
|
|
||||||
files({
|
|
||||||
"beaengine/beaengineSources/*.h",
|
|
||||||
"beaengine/beaengineSources/*.c",
|
|
||||||
"beaengine/include/beaengine/**.h",
|
|
||||||
})
|
|
Loading…
Reference in New Issue