REBASE: fixing xthread instruction decoding.

This commit is contained in:
Ben Vanik 2015-12-29 12:54:46 -08:00
parent bcacb9b127
commit 383a173a18
4 changed files with 48 additions and 62 deletions

View File

@ -69,6 +69,7 @@ enum class PPCOpcodeType {
typedef int (*InstrEmitFn)(PPCHIRBuilder& f, const InstrData& i); typedef int (*InstrEmitFn)(PPCHIRBuilder& f, const InstrData& i);
struct PPCOpcodeInfo { struct PPCOpcodeInfo {
PPCOpcodeGroup group;
PPCOpcodeType type; PPCOpcodeType type;
InstrEmitFn emit; InstrEmitFn emit;
}; };

View File

@ -11,7 +11,7 @@ namespace cpu {
namespace ppc { namespace ppc {
#define INSTRUCTION(opcode, mnem, form, group, type) \ #define INSTRUCTION(opcode, mnem, form, group, type) \
{PPCOpcodeType::type, nullptr} {PPCOpcodeGroup::group, PPCOpcodeType::type, nullptr}
PPCOpcodeInfo ppc_opcode_table[] = { PPCOpcodeInfo ppc_opcode_table[] = {
INSTRUCTION(0x7c000014, "addcx" , kXO , kI, kGeneral), INSTRUCTION(0x7c000014, "addcx" , kXO , kI, kGeneral),
INSTRUCTION(0x7c000114, "addex" , kXO , kI, kGeneral), INSTRUCTION(0x7c000114, "addex" , kXO , kI, kGeneral),

View File

@ -20,7 +20,7 @@
#include "xenia/base/profiling.h" #include "xenia/base/profiling.h"
#include "xenia/base/threading.h" #include "xenia/base/threading.h"
#include "xenia/cpu/breakpoint.h" #include "xenia/cpu/breakpoint.h"
#include "xenia/cpu/frontend/ppc_instr.h" #include "xenia/cpu/ppc/ppc_decode_data.h"
#include "xenia/cpu/processor.h" #include "xenia/cpu/processor.h"
#include "xenia/cpu/stack_walker.h" #include "xenia/cpu/stack_walker.h"
#include "xenia/emulator.h" #include "xenia/emulator.h"
@ -36,6 +36,8 @@ DEFINE_bool(ignore_thread_affinities, true,
namespace xe { namespace xe {
namespace kernel { namespace kernel {
using xe::cpu::ppc::PPCOpcode;
uint32_t next_xthread_id_ = 0; uint32_t next_xthread_id_ = 0;
thread_local XThread* current_thread_tls_ = nullptr; thread_local XThread* current_thread_tls_ = nullptr;
@ -805,39 +807,27 @@ bool XThread::StepToAddress(uint32_t pc) {
} }
uint32_t XThread::StepIntoBranch(uint32_t pc) { uint32_t XThread::StepIntoBranch(uint32_t pc) {
cpu::frontend::InstrData i; xe::cpu::ppc::PPCDecodeData d;
i.address = pc; d.address = pc;
i.code = xe::load_and_swap<uint32_t>(memory()->TranslateVirtual(i.address)); d.code = xe::load_and_swap<uint32_t>(memory()->TranslateVirtual(d.address));
i.type = cpu::frontend::GetInstrType(i.code); auto opcode = xe::cpu::ppc::LookupOpcode(d.code);
auto context = thread_state_->context(); auto context = thread_state_->context();
if (i.type->type & (1 << 4) /* BranchAlways */ if (d.code == 0x4E800020) {
|| i.code == 0x4E800020 /* blr */
|| i.code == 0x4E800420 /* bctr */) {
if (i.code == 0x4E800020) {
// blr // blr
uint32_t nia = uint32_t(context->lr); uint32_t nia = uint32_t(context->lr);
StepToAddress(nia); StepToAddress(nia);
} else if (i.code == 0x4E800420) { } else if (d.code == 0x4E800420) {
// bctr // bctr
uint32_t nia = uint32_t(context->ctr); uint32_t nia = uint32_t(context->ctr);
StepToAddress(nia); StepToAddress(nia);
} else if (i.type->opcode == 0x48000000) { } else if (opcode == PPCOpcode::bx) {
// bx // bx
uint32_t nia = 0; uint32_t nia = d.I.ADDR();
if (i.I.AA) {
nia = (uint32_t)cpu::frontend::XEEXTS26(i.I.LI << 2);
} else {
nia = i.address + (uint32_t)cpu::frontend::XEEXTS26(i.I.LI << 2);
}
StepToAddress(nia); StepToAddress(nia);
} else { } else if (opcode == PPCOpcode::bcx || opcode == PPCOpcode::bcctrx ||
// Unknown opcode. opcode == PPCOpcode::bclrx) {
assert_always();
}
} else if (i.type->type & (1 << 3) /* BranchCond */) {
threading::Fence fence; threading::Fence fence;
auto callback = [&fence, &pc](uint32_t guest_pc, uint64_t) { auto callback = [&fence, &pc](uint32_t guest_pc, uint64_t) {
pc = guest_pc; pc = guest_pc;
@ -852,22 +842,15 @@ uint32_t XThread::StepIntoBranch(uint32_t pc) {
} }
uint32_t nia = 0; uint32_t nia = 0;
if (i.type->opcode == 0x40000000) { if (opcode == PPCOpcode::bcx) {
// bcx // bcx
if (i.B.AA) { nia = d.B.ADDR();
nia = (uint32_t)cpu::frontend::XEEXTS16(i.B.BD << 2); } else if (opcode == PPCOpcode::bcctrx) {
} else {
nia = (uint32_t)(i.address + cpu::frontend::XEEXTS16(i.B.BD << 2));
}
} else if (i.type->opcode == 0x4C000420) {
// bcctrx // bcctrx
nia = uint32_t(context->ctr); nia = uint32_t(context->ctr);
} else if (i.type->opcode == 0x4C000020) { } else if (opcode == PPCOpcode::bclrx) {
// bclrx // bclrx
nia = uint32_t(context->lr); nia = uint32_t(context->lr);
} else {
// Unknown opcode.
assert_always();
} }
bpt.set_address(nia); bpt.set_address(nia);
@ -938,19 +921,23 @@ uint32_t XThread::StepToSafePoint(bool ignore_host) {
// We're in guest code. // We're in guest code.
// First: Find a synchronizing instruction and go to it. // First: Find a synchronizing instruction and go to it.
cpu::frontend::InstrData i; xe::cpu::ppc::PPCDecodeData d;
i.address = cpu_frames[0].guest_pc - 4; const xe::cpu::ppc::PPCOpcodeInfo* sync_info = nullptr;
d.address = cpu_frames[0].guest_pc - 4;
do { do {
i.address += 4; d.address += 4;
i.code = d.code =
xe::load_and_swap<uint32_t>(memory()->TranslateVirtual(i.address)); xe::load_and_swap<uint32_t>(memory()->TranslateVirtual(d.address));
i.type = cpu::frontend::GetInstrType(i.code); auto& opcode_info = xe::cpu::ppc::LookupOpcodeInfo(d.code);
} while ((i.type->type & (cpu::frontend::kXEPPCInstrTypeSynchronizeContext | if (opcode_info.type == cpu::ppc::PPCOpcodeType::kSync) {
cpu::frontend::kXEPPCInstrTypeBranch)) == 0); sync_info = &opcode_info;
break;
}
} while (true);
if (i.address != pc) { if (d.address != pc) {
StepToAddress(i.address); StepToAddress(d.address);
pc = i.address; pc = d.address;
} }
// Okay. Now we're on a synchronizing instruction but we need to step // Okay. Now we're on a synchronizing instruction but we need to step
@ -958,8 +945,8 @@ uint32_t XThread::StepToSafePoint(bool ignore_host) {
// If we're on a branching instruction, it's guaranteed only going to have // If we're on a branching instruction, it's guaranteed only going to have
// two possible targets. For non-branching instructions, we can just step // two possible targets. For non-branching instructions, we can just step
// over them. // over them.
if (i.type->type & cpu::frontend::kXEPPCInstrTypeBranch) { if (sync_info->group == xe::cpu::ppc::PPCOpcodeGroup::kB) {
pc = StepIntoBranch(i.address); pc = StepIntoBranch(d.address);
} }
} else { } else {
// We're in host code. Search backwards til we can get an idea of where // We're in host code. Search backwards til we can get an idea of where
@ -999,12 +986,10 @@ uint32_t XThread::StepToSafePoint(bool ignore_host) {
// that doesn't use an export. If the current instruction is // that doesn't use an export. If the current instruction is
// synchronizing, we can just save here. Otherwise, step forward // synchronizing, we can just save here. Otherwise, step forward
// (and call ourselves again so we run the correct logic). // (and call ourselves again so we run the correct logic).
cpu::frontend::InstrData i; uint32_t code =
i.address = first_pc;
i.code =
xe::load_and_swap<uint32_t>(memory()->TranslateVirtual(first_pc)); xe::load_and_swap<uint32_t>(memory()->TranslateVirtual(first_pc));
i.type = cpu::frontend::GetInstrType(i.code); auto& opcode_info = xe::cpu::ppc::LookupOpcodeInfo(code);
if (i.type->type & cpu::frontend::kXEPPCInstrTypeSynchronizeContext) { if (opcode_info.type == xe::cpu::ppc::PPCOpcodeType::kSync) {
// Good to go. // Good to go.
pc = first_pc; pc = first_pc;
} else { } else {

View File

@ -200,7 +200,7 @@ def generate_table(insns):
insns = sorted(insns, key = lambda i: i.mnem) insns = sorted(insns, key = lambda i: i.mnem)
w0('#define INSTRUCTION(opcode, mnem, form, group, type) \\') w0('#define INSTRUCTION(opcode, mnem, form, group, type) \\')
w0(' {PPCOpcodeType::type, nullptr}') w0(' {PPCOpcodeGroup::group, PPCOpcodeType::type, nullptr}')
w0('PPCOpcodeInfo ppc_opcode_table[] = {') w0('PPCOpcodeInfo ppc_opcode_table[] = {')
fmt = 'INSTRUCTION(' + ', '.join([ fmt = 'INSTRUCTION(' + ', '.join([
'0x%08x', '0x%08x',