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);
|
||||
|
||||
struct PPCOpcodeInfo {
|
||||
PPCOpcodeGroup group;
|
||||
PPCOpcodeType type;
|
||||
InstrEmitFn emit;
|
||||
};
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace cpu {
|
|||
namespace ppc {
|
||||
|
||||
#define INSTRUCTION(opcode, mnem, form, group, type) \
|
||||
{PPCOpcodeType::type, nullptr}
|
||||
{PPCOpcodeGroup::group, PPCOpcodeType::type, nullptr}
|
||||
PPCOpcodeInfo ppc_opcode_table[] = {
|
||||
INSTRUCTION(0x7c000014, "addcx" , kXO , kI, kGeneral),
|
||||
INSTRUCTION(0x7c000114, "addex" , kXO , kI, kGeneral),
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "xenia/base/profiling.h"
|
||||
#include "xenia/base/threading.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/stack_walker.h"
|
||||
#include "xenia/emulator.h"
|
||||
|
@ -36,6 +36,8 @@ DEFINE_bool(ignore_thread_affinities, true,
|
|||
namespace xe {
|
||||
namespace kernel {
|
||||
|
||||
using xe::cpu::ppc::PPCOpcode;
|
||||
|
||||
uint32_t next_xthread_id_ = 0;
|
||||
thread_local XThread* current_thread_tls_ = nullptr;
|
||||
|
||||
|
@ -805,39 +807,27 @@ bool XThread::StepToAddress(uint32_t pc) {
|
|||
}
|
||||
|
||||
uint32_t XThread::StepIntoBranch(uint32_t pc) {
|
||||
cpu::frontend::InstrData i;
|
||||
i.address = pc;
|
||||
i.code = xe::load_and_swap<uint32_t>(memory()->TranslateVirtual(i.address));
|
||||
i.type = cpu::frontend::GetInstrType(i.code);
|
||||
xe::cpu::ppc::PPCDecodeData d;
|
||||
d.address = pc;
|
||||
d.code = xe::load_and_swap<uint32_t>(memory()->TranslateVirtual(d.address));
|
||||
auto opcode = xe::cpu::ppc::LookupOpcode(d.code);
|
||||
|
||||
auto context = thread_state_->context();
|
||||
|
||||
if (i.type->type & (1 << 4) /* BranchAlways */
|
||||
|| i.code == 0x4E800020 /* blr */
|
||||
|| i.code == 0x4E800420 /* bctr */) {
|
||||
if (i.code == 0x4E800020) {
|
||||
// blr
|
||||
uint32_t nia = uint32_t(context->lr);
|
||||
StepToAddress(nia);
|
||||
} else if (i.code == 0x4E800420) {
|
||||
// bctr
|
||||
uint32_t nia = uint32_t(context->ctr);
|
||||
StepToAddress(nia);
|
||||
} else if (i.type->opcode == 0x48000000) {
|
||||
// bx
|
||||
uint32_t nia = 0;
|
||||
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);
|
||||
} else {
|
||||
// Unknown opcode.
|
||||
assert_always();
|
||||
}
|
||||
} else if (i.type->type & (1 << 3) /* BranchCond */) {
|
||||
if (d.code == 0x4E800020) {
|
||||
// blr
|
||||
uint32_t nia = uint32_t(context->lr);
|
||||
StepToAddress(nia);
|
||||
} else if (d.code == 0x4E800420) {
|
||||
// bctr
|
||||
uint32_t nia = uint32_t(context->ctr);
|
||||
StepToAddress(nia);
|
||||
} else if (opcode == PPCOpcode::bx) {
|
||||
// bx
|
||||
uint32_t nia = d.I.ADDR();
|
||||
StepToAddress(nia);
|
||||
} else if (opcode == PPCOpcode::bcx || opcode == PPCOpcode::bcctrx ||
|
||||
opcode == PPCOpcode::bclrx) {
|
||||
threading::Fence fence;
|
||||
auto callback = [&fence, &pc](uint32_t guest_pc, uint64_t) {
|
||||
pc = guest_pc;
|
||||
|
@ -852,22 +842,15 @@ uint32_t XThread::StepIntoBranch(uint32_t pc) {
|
|||
}
|
||||
|
||||
uint32_t nia = 0;
|
||||
if (i.type->opcode == 0x40000000) {
|
||||
if (opcode == PPCOpcode::bcx) {
|
||||
// bcx
|
||||
if (i.B.AA) {
|
||||
nia = (uint32_t)cpu::frontend::XEEXTS16(i.B.BD << 2);
|
||||
} else {
|
||||
nia = (uint32_t)(i.address + cpu::frontend::XEEXTS16(i.B.BD << 2));
|
||||
}
|
||||
} else if (i.type->opcode == 0x4C000420) {
|
||||
nia = d.B.ADDR();
|
||||
} else if (opcode == PPCOpcode::bcctrx) {
|
||||
// bcctrx
|
||||
nia = uint32_t(context->ctr);
|
||||
} else if (i.type->opcode == 0x4C000020) {
|
||||
} else if (opcode == PPCOpcode::bclrx) {
|
||||
// bclrx
|
||||
nia = uint32_t(context->lr);
|
||||
} else {
|
||||
// Unknown opcode.
|
||||
assert_always();
|
||||
}
|
||||
|
||||
bpt.set_address(nia);
|
||||
|
@ -938,19 +921,23 @@ uint32_t XThread::StepToSafePoint(bool ignore_host) {
|
|||
|
||||
// We're in guest code.
|
||||
// First: Find a synchronizing instruction and go to it.
|
||||
cpu::frontend::InstrData i;
|
||||
i.address = cpu_frames[0].guest_pc - 4;
|
||||
xe::cpu::ppc::PPCDecodeData d;
|
||||
const xe::cpu::ppc::PPCOpcodeInfo* sync_info = nullptr;
|
||||
d.address = cpu_frames[0].guest_pc - 4;
|
||||
do {
|
||||
i.address += 4;
|
||||
i.code =
|
||||
xe::load_and_swap<uint32_t>(memory()->TranslateVirtual(i.address));
|
||||
i.type = cpu::frontend::GetInstrType(i.code);
|
||||
} while ((i.type->type & (cpu::frontend::kXEPPCInstrTypeSynchronizeContext |
|
||||
cpu::frontend::kXEPPCInstrTypeBranch)) == 0);
|
||||
d.address += 4;
|
||||
d.code =
|
||||
xe::load_and_swap<uint32_t>(memory()->TranslateVirtual(d.address));
|
||||
auto& opcode_info = xe::cpu::ppc::LookupOpcodeInfo(d.code);
|
||||
if (opcode_info.type == cpu::ppc::PPCOpcodeType::kSync) {
|
||||
sync_info = &opcode_info;
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
if (i.address != pc) {
|
||||
StepToAddress(i.address);
|
||||
pc = i.address;
|
||||
if (d.address != pc) {
|
||||
StepToAddress(d.address);
|
||||
pc = d.address;
|
||||
}
|
||||
|
||||
// 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
|
||||
// two possible targets. For non-branching instructions, we can just step
|
||||
// over them.
|
||||
if (i.type->type & cpu::frontend::kXEPPCInstrTypeBranch) {
|
||||
pc = StepIntoBranch(i.address);
|
||||
if (sync_info->group == xe::cpu::ppc::PPCOpcodeGroup::kB) {
|
||||
pc = StepIntoBranch(d.address);
|
||||
}
|
||||
} else {
|
||||
// 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
|
||||
// synchronizing, we can just save here. Otherwise, step forward
|
||||
// (and call ourselves again so we run the correct logic).
|
||||
cpu::frontend::InstrData i;
|
||||
i.address = first_pc;
|
||||
i.code =
|
||||
uint32_t code =
|
||||
xe::load_and_swap<uint32_t>(memory()->TranslateVirtual(first_pc));
|
||||
i.type = cpu::frontend::GetInstrType(i.code);
|
||||
if (i.type->type & cpu::frontend::kXEPPCInstrTypeSynchronizeContext) {
|
||||
auto& opcode_info = xe::cpu::ppc::LookupOpcodeInfo(code);
|
||||
if (opcode_info.type == xe::cpu::ppc::PPCOpcodeType::kSync) {
|
||||
// Good to go.
|
||||
pc = first_pc;
|
||||
} else {
|
||||
|
|
|
@ -200,7 +200,7 @@ def generate_table(insns):
|
|||
insns = sorted(insns, key = lambda i: i.mnem)
|
||||
|
||||
w0('#define INSTRUCTION(opcode, mnem, form, group, type) \\')
|
||||
w0(' {PPCOpcodeType::type, nullptr}')
|
||||
w0(' {PPCOpcodeGroup::group, PPCOpcodeType::type, nullptr}')
|
||||
w0('PPCOpcodeInfo ppc_opcode_table[] = {')
|
||||
fmt = 'INSTRUCTION(' + ', '.join([
|
||||
'0x%08x',
|
||||
|
|
Loading…
Reference in New Issue