Attempting to inline a lot of MMIO operations. Works for GPU stuff mainly.
This commit is contained in:
parent
6618bcf2db
commit
40a6a12800
|
@ -156,11 +156,12 @@ class AudioSystem {
|
||||||
|
|
||||||
void ProcessXmaContext(XMAContext& context, XMAContextData& data);
|
void ProcessXmaContext(XMAContext& context, XMAContextData& data);
|
||||||
|
|
||||||
static uint64_t MMIOReadRegisterThunk(AudioSystem* as, uint32_t addr) {
|
static uint64_t MMIOReadRegisterThunk(void* ppc_context, AudioSystem* as,
|
||||||
|
uint32_t addr) {
|
||||||
return as->ReadRegister(addr);
|
return as->ReadRegister(addr);
|
||||||
}
|
}
|
||||||
static void MMIOWriteRegisterThunk(AudioSystem* as, uint32_t addr,
|
static void MMIOWriteRegisterThunk(void* ppc_context, AudioSystem* as,
|
||||||
uint64_t value) {
|
uint32_t addr, uint64_t value) {
|
||||||
as->WriteRegister(addr, value);
|
as->WriteRegister(addr, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -481,9 +481,10 @@ void X64Emitter::CallNative(uint64_t (*fn)(void* raw_context, uint64_t arg0),
|
||||||
|
|
||||||
void X64Emitter::CallNativeSafe(void* fn) {
|
void X64Emitter::CallNativeSafe(void* fn) {
|
||||||
// rcx = context
|
// rcx = context
|
||||||
// rdx = target host function
|
// rdx = target function
|
||||||
// r8 = arg0
|
// r8 = arg0
|
||||||
// r9 = arg1
|
// r9 = arg1
|
||||||
|
// r10 = arg2
|
||||||
mov(rdx, reinterpret_cast<uint64_t>(fn));
|
mov(rdx, reinterpret_cast<uint64_t>(fn));
|
||||||
auto thunk = backend()->guest_to_host_thunk();
|
auto thunk = backend()->guest_to_host_thunk();
|
||||||
mov(rax, reinterpret_cast<uint64_t>(thunk));
|
mov(rax, reinterpret_cast<uint64_t>(thunk));
|
||||||
|
|
|
@ -1425,6 +1425,68 @@ EMITTER_OPCODE_TABLE(
|
||||||
STORE_CONTEXT_V128);
|
STORE_CONTEXT_V128);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// OPCODE_LOAD_MMIO
|
||||||
|
// ============================================================================
|
||||||
|
// Note: all types are always aligned in the context.
|
||||||
|
EMITTER(LOAD_MMIO_I32, MATCH(I<OPCODE_LOAD_MMIO, I32<>, OffsetOp, OffsetOp>)) {
|
||||||
|
static void Emit(X64Emitter& e, const EmitArgType& i) {
|
||||||
|
// uint64_t (context, addr)
|
||||||
|
auto mmio_range = reinterpret_cast<MMIORange*>(i.src1.value);
|
||||||
|
auto read_address = uint32_t(i.src2.value);
|
||||||
|
e.mov(e.r8, uint64_t(mmio_range->callback_context));
|
||||||
|
e.mov(e.r9d, read_address);
|
||||||
|
e.CallNativeSafe(mmio_range->read);
|
||||||
|
e.bswap(e.eax);
|
||||||
|
e.mov(i.dest, e.eax);
|
||||||
|
if (IsTracingData()) {
|
||||||
|
e.mov(e.r8, i.dest);
|
||||||
|
e.mov(e.edx, read_address);
|
||||||
|
e.CallNative(reinterpret_cast<void*>(TraceContextLoadI32));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
EMITTER_OPCODE_TABLE(
|
||||||
|
OPCODE_LOAD_MMIO,
|
||||||
|
LOAD_MMIO_I32);
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// OPCODE_STORE_MMIO
|
||||||
|
// ============================================================================
|
||||||
|
// Note: all types are always aligned on the stack.
|
||||||
|
EMITTER(STORE_MMIO_I32, MATCH(I<OPCODE_STORE_MMIO, VoidOp, OffsetOp, OffsetOp, I32<>>)) {
|
||||||
|
static void Emit(X64Emitter& e, const EmitArgType& i) {
|
||||||
|
// void (context, addr, value)
|
||||||
|
auto mmio_range = reinterpret_cast<MMIORange*>(i.src1.value);
|
||||||
|
auto write_address = uint32_t(i.src2.value);
|
||||||
|
e.mov(e.r8, uint64_t(mmio_range->callback_context));
|
||||||
|
e.mov(e.r9d, write_address);
|
||||||
|
if (i.src3.is_constant) {
|
||||||
|
e.mov(e.r10d, xe::byte_swap(i.src3.constant()));
|
||||||
|
} else {
|
||||||
|
e.mov(e.r10d, i.src3);
|
||||||
|
e.bswap(e.r10d);
|
||||||
|
}
|
||||||
|
e.CallNativeSafe(mmio_range->write);
|
||||||
|
if (IsTracingData()) {
|
||||||
|
if (i.src3.is_constant) {
|
||||||
|
e.mov(e.r8d, i.src3.constant());
|
||||||
|
} else {
|
||||||
|
e.mov(e.r8d, i.src3);
|
||||||
|
}
|
||||||
|
e.mov(e.edx, write_address);
|
||||||
|
e.CallNative(reinterpret_cast<void*>(TraceContextStoreI32));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
EMITTER_OPCODE_TABLE(
|
||||||
|
OPCODE_STORE_MMIO,
|
||||||
|
STORE_MMIO_I32);
|
||||||
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// OPCODE_LOAD
|
// OPCODE_LOAD
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
@ -6374,6 +6436,8 @@ void RegisterSequences() {
|
||||||
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_STORE_LOCAL);
|
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_STORE_LOCAL);
|
||||||
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_LOAD_CONTEXT);
|
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_LOAD_CONTEXT);
|
||||||
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_STORE_CONTEXT);
|
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_STORE_CONTEXT);
|
||||||
|
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_LOAD_MMIO);
|
||||||
|
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_STORE_MMIO);
|
||||||
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_LOAD);
|
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_LOAD);
|
||||||
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_STORE);
|
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_STORE);
|
||||||
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_MEMSET);
|
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_MEMSET);
|
||||||
|
|
|
@ -97,6 +97,7 @@ GuestToHostThunk X64ThunkEmitter::EmitGuestToHostThunk() {
|
||||||
// rdx = target function
|
// rdx = target function
|
||||||
// r8 = arg0
|
// r8 = arg0
|
||||||
// r9 = arg1
|
// r9 = arg1
|
||||||
|
// r10 = arg2
|
||||||
|
|
||||||
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
|
const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
|
||||||
// rsp + 0 = return address
|
// rsp + 0 = return address
|
||||||
|
|
|
@ -174,6 +174,51 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OPCODE_LOAD:
|
||||||
|
if (i->src1.value->IsConstant()) {
|
||||||
|
auto memory = processor_->memory();
|
||||||
|
auto address = i->src1.value->constant.i32;
|
||||||
|
auto mmio_range =
|
||||||
|
processor_->memory()->LookupVirtualMappedRange(address);
|
||||||
|
if (mmio_range) {
|
||||||
|
i->Replace(&OPCODE_LOAD_MMIO_info, 0);
|
||||||
|
i->src1.offset = reinterpret_cast<uint64_t>(mmio_range);
|
||||||
|
i->src2.offset = address;
|
||||||
|
} else {
|
||||||
|
auto heap = memory->LookupHeap(address);
|
||||||
|
uint32_t protect;
|
||||||
|
if (heap->QueryProtect(address, &protect) &&
|
||||||
|
!(protect & kMemoryProtectWrite)) {
|
||||||
|
// Memory is readonly - can just return the value.
|
||||||
|
switch (v->type) {
|
||||||
|
case INT32_TYPE:
|
||||||
|
v->set_constant(xe::load_and_swap<uint32_t>(
|
||||||
|
memory->TranslateVirtual(address)));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert_unhandled_case(v->type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i->Remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPCODE_STORE:
|
||||||
|
if (i->src1.value->IsConstant()) {
|
||||||
|
auto address = i->src1.value->constant.i32;
|
||||||
|
auto mmio_range =
|
||||||
|
processor_->memory()->LookupVirtualMappedRange(address);
|
||||||
|
if (mmio_range) {
|
||||||
|
auto value = i->src2.value;
|
||||||
|
i->Replace(&OPCODE_STORE_MMIO_info, 0);
|
||||||
|
i->src1.offset = reinterpret_cast<uint64_t>(mmio_range);
|
||||||
|
i->src2.offset = address;
|
||||||
|
i->set_src3(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case OPCODE_SELECT:
|
case OPCODE_SELECT:
|
||||||
if (i->src1.value->IsConstant()) {
|
if (i->src1.value->IsConstant()) {
|
||||||
if (i->src1.value->IsConstantTrue()) {
|
if (i->src1.value->IsConstantTrue()) {
|
||||||
|
|
|
@ -1087,6 +1087,23 @@ void HIRBuilder::StoreContext(size_t offset, Value* value) {
|
||||||
i->src3.value = NULL;
|
i->src3.value = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value* HIRBuilder::LoadMmio(cpu::MMIORange* mmio_range, uint32_t address,
|
||||||
|
TypeName type) {
|
||||||
|
Instr* i = AppendInstr(OPCODE_LOAD_MMIO_info, 0, AllocValue(type));
|
||||||
|
i->src1.offset = reinterpret_cast<uint64_t>(mmio_range);
|
||||||
|
i->src2.offset = address;
|
||||||
|
i->src3.value = NULL;
|
||||||
|
return i->dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HIRBuilder::StoreMmio(cpu::MMIORange* mmio_range, uint32_t address,
|
||||||
|
Value* value) {
|
||||||
|
Instr* i = AppendInstr(OPCODE_STORE_MMIO_info, 0);
|
||||||
|
i->src1.offset = reinterpret_cast<uint64_t>(mmio_range);
|
||||||
|
i->src2.offset = address;
|
||||||
|
i->set_src3(value);
|
||||||
|
}
|
||||||
|
|
||||||
Value* HIRBuilder::Load(Value* address, TypeName type, uint32_t load_flags) {
|
Value* HIRBuilder::Load(Value* address, TypeName type, uint32_t load_flags) {
|
||||||
ASSERT_ADDRESS_TYPE(address);
|
ASSERT_ADDRESS_TYPE(address);
|
||||||
Instr* i = AppendInstr(OPCODE_LOAD_info, load_flags, AllocValue(type));
|
Instr* i = AppendInstr(OPCODE_LOAD_info, load_flags, AllocValue(type));
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "xenia/cpu/hir/label.h"
|
#include "xenia/cpu/hir/label.h"
|
||||||
#include "xenia/cpu/hir/opcodes.h"
|
#include "xenia/cpu/hir/opcodes.h"
|
||||||
#include "xenia/cpu/hir/value.h"
|
#include "xenia/cpu/hir/value.h"
|
||||||
|
#include "xenia/cpu/mmio_handler.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
@ -130,6 +131,9 @@ class HIRBuilder {
|
||||||
Value* LoadContext(size_t offset, TypeName type);
|
Value* LoadContext(size_t offset, TypeName type);
|
||||||
void StoreContext(size_t offset, Value* value);
|
void StoreContext(size_t offset, Value* value);
|
||||||
|
|
||||||
|
Value* LoadMmio(cpu::MMIORange* mmio_range, uint32_t address, TypeName type);
|
||||||
|
void StoreMmio(cpu::MMIORange* mmio_range, uint32_t address, Value* value);
|
||||||
|
|
||||||
Value* Load(Value* address, TypeName type, uint32_t load_flags = 0);
|
Value* Load(Value* address, TypeName type, uint32_t load_flags = 0);
|
||||||
void Store(Value* address, Value* value, uint32_t store_flags = 0);
|
void Store(Value* address, Value* value, uint32_t store_flags = 0);
|
||||||
void Memset(Value* address, Value* value, Value* length);
|
void Memset(Value* address, Value* value, Value* length);
|
||||||
|
|
|
@ -140,6 +140,8 @@ enum Opcode {
|
||||||
OPCODE_STORE_LOCAL,
|
OPCODE_STORE_LOCAL,
|
||||||
OPCODE_LOAD_CONTEXT,
|
OPCODE_LOAD_CONTEXT,
|
||||||
OPCODE_STORE_CONTEXT,
|
OPCODE_STORE_CONTEXT,
|
||||||
|
OPCODE_LOAD_MMIO,
|
||||||
|
OPCODE_STORE_MMIO,
|
||||||
OPCODE_LOAD,
|
OPCODE_LOAD,
|
||||||
OPCODE_STORE,
|
OPCODE_STORE,
|
||||||
OPCODE_MEMSET,
|
OPCODE_MEMSET,
|
||||||
|
@ -243,6 +245,8 @@ enum OpcodeSignature {
|
||||||
(OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_O << 3) | (OPCODE_SIG_TYPE_V << 6),
|
(OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_O << 3) | (OPCODE_SIG_TYPE_V << 6),
|
||||||
OPCODE_SIG_X_O_V_V = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_O << 3) |
|
OPCODE_SIG_X_O_V_V = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_O << 3) |
|
||||||
(OPCODE_SIG_TYPE_V << 6) | (OPCODE_SIG_TYPE_V << 9),
|
(OPCODE_SIG_TYPE_V << 6) | (OPCODE_SIG_TYPE_V << 9),
|
||||||
|
OPCODE_SIG_X_O_O_V = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_O << 3) |
|
||||||
|
(OPCODE_SIG_TYPE_O << 6) | (OPCODE_SIG_TYPE_V << 9),
|
||||||
OPCODE_SIG_X_S = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_S << 3),
|
OPCODE_SIG_X_S = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_S << 3),
|
||||||
OPCODE_SIG_X_V = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_V << 3),
|
OPCODE_SIG_X_V = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_V << 3),
|
||||||
OPCODE_SIG_X_V_L =
|
OPCODE_SIG_X_V_L =
|
||||||
|
@ -260,6 +264,8 @@ enum OpcodeSignature {
|
||||||
OPCODE_SIG_V = (OPCODE_SIG_TYPE_V),
|
OPCODE_SIG_V = (OPCODE_SIG_TYPE_V),
|
||||||
OPCODE_SIG_V_O = (OPCODE_SIG_TYPE_V) | (OPCODE_SIG_TYPE_O << 3),
|
OPCODE_SIG_V_O = (OPCODE_SIG_TYPE_V) | (OPCODE_SIG_TYPE_O << 3),
|
||||||
OPCODE_SIG_V_V = (OPCODE_SIG_TYPE_V) | (OPCODE_SIG_TYPE_V << 3),
|
OPCODE_SIG_V_V = (OPCODE_SIG_TYPE_V) | (OPCODE_SIG_TYPE_V << 3),
|
||||||
|
OPCODE_SIG_V_O_O =
|
||||||
|
(OPCODE_SIG_TYPE_V) | (OPCODE_SIG_TYPE_O << 3) | (OPCODE_SIG_TYPE_O << 6),
|
||||||
OPCODE_SIG_V_V_O =
|
OPCODE_SIG_V_V_O =
|
||||||
(OPCODE_SIG_TYPE_V) | (OPCODE_SIG_TYPE_V << 3) | (OPCODE_SIG_TYPE_O << 6),
|
(OPCODE_SIG_TYPE_V) | (OPCODE_SIG_TYPE_V << 3) | (OPCODE_SIG_TYPE_O << 6),
|
||||||
OPCODE_SIG_V_V_O_V = (OPCODE_SIG_TYPE_V) | (OPCODE_SIG_TYPE_V << 3) |
|
OPCODE_SIG_V_V_O_V = (OPCODE_SIG_TYPE_V) | (OPCODE_SIG_TYPE_V << 3) |
|
||||||
|
|
|
@ -212,6 +212,18 @@ DEFINE_OPCODE(
|
||||||
OPCODE_SIG_X_O_V,
|
OPCODE_SIG_X_O_V,
|
||||||
0)
|
0)
|
||||||
|
|
||||||
|
DEFINE_OPCODE(
|
||||||
|
OPCODE_LOAD_MMIO,
|
||||||
|
"load_mmio",
|
||||||
|
OPCODE_SIG_V_O_O,
|
||||||
|
OPCODE_FLAG_MEMORY)
|
||||||
|
|
||||||
|
DEFINE_OPCODE(
|
||||||
|
OPCODE_STORE_MMIO,
|
||||||
|
"store_mmio",
|
||||||
|
OPCODE_SIG_X_O_O_V,
|
||||||
|
OPCODE_FLAG_MEMORY)
|
||||||
|
|
||||||
DEFINE_OPCODE(
|
DEFINE_OPCODE(
|
||||||
OPCODE_LOAD,
|
OPCODE_LOAD,
|
||||||
"load",
|
"load",
|
||||||
|
|
|
@ -62,11 +62,20 @@ bool MMIOHandler::RegisterRange(uint32_t virtual_address, uint32_t mask,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MMIORange* MMIOHandler::LookupRange(uint32_t virtual_address) {
|
||||||
|
for (auto& range : mapped_ranges_) {
|
||||||
|
if ((virtual_address & range.mask) == range.address) {
|
||||||
|
return ⦥
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
bool MMIOHandler::CheckLoad(uint32_t virtual_address, uint64_t* out_value) {
|
bool MMIOHandler::CheckLoad(uint32_t virtual_address, uint64_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 =
|
*out_value = static_cast<uint32_t>(
|
||||||
static_cast<uint32_t>(range.read(range.context, virtual_address));
|
range.read(nullptr, range.callback_context, virtual_address));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,7 +85,7 @@ bool MMIOHandler::CheckLoad(uint32_t virtual_address, uint64_t* out_value) {
|
||||||
bool MMIOHandler::CheckStore(uint32_t virtual_address, uint64_t value) {
|
bool MMIOHandler::CheckStore(uint32_t virtual_address, uint64_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(range.context, virtual_address, value);
|
range.write(nullptr, range.callback_context, virtual_address, value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -243,7 +252,8 @@ bool MMIOHandler::HandleAccessFault(void* thread_state,
|
||||||
if (is_load) {
|
if (is_load) {
|
||||||
// Load of a memory value - read from range, swap, and store in the
|
// Load of a memory value - read from range, swap, and store in the
|
||||||
// register.
|
// register.
|
||||||
uint64_t value = range->read(range->context, fault_address & 0xFFFFFFFF);
|
uint64_t value = range->read(nullptr, range->callback_context,
|
||||||
|
fault_address & 0xFFFFFFFF);
|
||||||
uint32_t be_reg_index;
|
uint32_t be_reg_index;
|
||||||
if (!xe::bit_scan_forward(arg1_type & 0xFFFF, &be_reg_index)) {
|
if (!xe::bit_scan_forward(arg1_type & 0xFFFF, &be_reg_index)) {
|
||||||
be_reg_index = 0;
|
be_reg_index = 0;
|
||||||
|
@ -293,7 +303,8 @@ bool MMIOHandler::HandleAccessFault(void* thread_state,
|
||||||
value = xe::byte_swap(static_cast<uint64_t>(value));
|
value = xe::byte_swap(static_cast<uint64_t>(value));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
range->write(range->context, fault_address & 0xFFFFFFFF, value);
|
range->write(nullptr, range->callback_context, fault_address & 0xFFFFFFFF,
|
||||||
|
value);
|
||||||
} else {
|
} else {
|
||||||
assert_always("Unknown MMIO instruction type");
|
assert_always("Unknown MMIO instruction type");
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -20,12 +20,23 @@
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
|
||||||
typedef uint64_t (*MMIOReadCallback)(void* context, uint32_t addr);
|
typedef uint64_t (*MMIOReadCallback)(void* ppc_context, void* callback_context,
|
||||||
typedef void (*MMIOWriteCallback)(void* context, uint32_t addr, uint64_t value);
|
uint32_t addr);
|
||||||
|
typedef void (*MMIOWriteCallback)(void* ppc_context, void* callback_context,
|
||||||
|
uint32_t addr, uint64_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);
|
||||||
|
|
||||||
|
struct MMIORange {
|
||||||
|
uint32_t address;
|
||||||
|
uint32_t mask;
|
||||||
|
uint32_t size;
|
||||||
|
void* callback_context;
|
||||||
|
MMIOReadCallback read;
|
||||||
|
MMIOWriteCallback write;
|
||||||
|
};
|
||||||
|
|
||||||
// NOTE: only one can exist at a time!
|
// NOTE: only one can exist at a time!
|
||||||
class MMIOHandler {
|
class MMIOHandler {
|
||||||
public:
|
public:
|
||||||
|
@ -38,6 +49,7 @@ class MMIOHandler {
|
||||||
bool RegisterRange(uint32_t virtual_address, uint32_t mask, uint32_t size,
|
bool RegisterRange(uint32_t virtual_address, uint32_t mask, uint32_t size,
|
||||||
void* context, MMIOReadCallback read_callback,
|
void* context, MMIOReadCallback read_callback,
|
||||||
MMIOWriteCallback write_callback);
|
MMIOWriteCallback write_callback);
|
||||||
|
MMIORange* LookupRange(uint32_t virtual_address);
|
||||||
|
|
||||||
bool CheckLoad(uint32_t virtual_address, uint64_t* out_value);
|
bool CheckLoad(uint32_t virtual_address, uint64_t* out_value);
|
||||||
bool CheckStore(uint32_t virtual_address, uint64_t value);
|
bool CheckStore(uint32_t virtual_address, uint64_t value);
|
||||||
|
@ -76,14 +88,6 @@ class MMIOHandler {
|
||||||
uint8_t* virtual_membase_;
|
uint8_t* virtual_membase_;
|
||||||
uint8_t* physical_membase_;
|
uint8_t* physical_membase_;
|
||||||
|
|
||||||
struct MMIORange {
|
|
||||||
uint32_t address;
|
|
||||||
uint32_t mask;
|
|
||||||
uint32_t size;
|
|
||||||
void* context;
|
|
||||||
MMIOReadCallback read;
|
|
||||||
MMIOWriteCallback write;
|
|
||||||
};
|
|
||||||
std::vector<MMIORange> mapped_ranges_;
|
std::vector<MMIORange> mapped_ranges_;
|
||||||
|
|
||||||
// TODO(benvanik): data structure magic.
|
// TODO(benvanik): data structure magic.
|
||||||
|
|
|
@ -63,6 +63,11 @@ WinMMIOHandler::~WinMMIOHandler() {
|
||||||
// addresses in our range and call into the registered handlers, if any.
|
// addresses in our range and call into the registered handlers, if any.
|
||||||
// If there are none, we continue.
|
// If there are none, we continue.
|
||||||
LONG CALLBACK MMIOExceptionHandler(PEXCEPTION_POINTERS ex_info) {
|
LONG CALLBACK MMIOExceptionHandler(PEXCEPTION_POINTERS ex_info) {
|
||||||
|
// Fast path for SetThreadName.
|
||||||
|
if (ex_info->ExceptionRecord->ExceptionCode == 0x406D1388) {
|
||||||
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
}
|
||||||
|
|
||||||
SCOPE_profile_cpu_i("cpu", "MMIOExceptionHandler");
|
SCOPE_profile_cpu_i("cpu", "MMIOExceptionHandler");
|
||||||
|
|
||||||
// http://msdn.microsoft.com/en-us/library/ms679331(v=vs.85).aspx
|
// http://msdn.microsoft.com/en-us/library/ms679331(v=vs.85).aspx
|
||||||
|
|
|
@ -54,11 +54,12 @@ class GL4GraphicsSystem : public GraphicsSystem {
|
||||||
uint64_t ReadRegister(uint32_t addr);
|
uint64_t ReadRegister(uint32_t addr);
|
||||||
void WriteRegister(uint32_t addr, uint64_t value);
|
void WriteRegister(uint32_t addr, uint64_t value);
|
||||||
|
|
||||||
static uint64_t MMIOReadRegisterThunk(GL4GraphicsSystem* gs, uint32_t addr) {
|
static uint64_t MMIOReadRegisterThunk(void* ppc_context,
|
||||||
|
GL4GraphicsSystem* gs, uint32_t addr) {
|
||||||
return gs->ReadRegister(addr);
|
return gs->ReadRegister(addr);
|
||||||
}
|
}
|
||||||
static void MMIOWriteRegisterThunk(GL4GraphicsSystem* gs, uint32_t addr,
|
static void MMIOWriteRegisterThunk(void* ppc_context, GL4GraphicsSystem* gs,
|
||||||
uint64_t value) {
|
uint32_t addr, uint64_t value) {
|
||||||
gs->WriteRegister(addr, value);
|
gs->WriteRegister(addr, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -362,6 +362,10 @@ bool Memory::AddVirtualMappedRange(uint32_t virtual_address, uint32_t mask,
|
||||||
read_callback, write_callback);
|
read_callback, write_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cpu::MMIORange* Memory::LookupVirtualMappedRange(uint32_t virtual_address) {
|
||||||
|
return mmio_handler_->LookupRange(virtual_address);
|
||||||
|
}
|
||||||
|
|
||||||
uintptr_t Memory::AddPhysicalWriteWatch(uint32_t physical_address,
|
uintptr_t Memory::AddPhysicalWriteWatch(uint32_t physical_address,
|
||||||
uint32_t length,
|
uint32_t length,
|
||||||
cpu::WriteWatchCallback callback,
|
cpu::WriteWatchCallback callback,
|
||||||
|
|
|
@ -195,6 +195,7 @@ class Memory {
|
||||||
uint32_t size, void* context,
|
uint32_t size, void* context,
|
||||||
cpu::MMIOReadCallback read_callback,
|
cpu::MMIOReadCallback read_callback,
|
||||||
cpu::MMIOWriteCallback write_callback);
|
cpu::MMIOWriteCallback write_callback);
|
||||||
|
cpu::MMIORange* LookupVirtualMappedRange(uint32_t virtual_address);
|
||||||
|
|
||||||
uintptr_t AddPhysicalWriteWatch(uint32_t physical_address, uint32_t length,
|
uintptr_t AddPhysicalWriteWatch(uint32_t physical_address, uint32_t length,
|
||||||
cpu::WriteWatchCallback callback,
|
cpu::WriteWatchCallback callback,
|
||||||
|
|
Loading…
Reference in New Issue