REBASE: fixing xthread instruction decoding.
This commit is contained in:
parent
bcacb9b127
commit
383a173a18
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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',
|
||||||
|
|
Loading…
Reference in New Issue