Capturing guest/host context and showing registers in debugger.
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
#include "xenia/cpu/processor.h"
|
||||
#include "xenia/profiling.h"
|
||||
|
||||
DECLARE_bool(debug);
|
||||
|
||||
DEFINE_bool(store_all_context_values, false,
|
||||
"Don't strip dead context stores to aid in debugging.");
|
||||
|
||||
@@ -74,7 +76,9 @@ bool ContextPromotionPass::Run(HIRBuilder* builder) {
|
||||
}
|
||||
|
||||
// Remove all dead stores.
|
||||
if (!FLAGS_store_all_context_values) {
|
||||
// This will break debugging as we can't recover this information when
|
||||
// trying to extract stack traces/register values, so we don't do that.
|
||||
if (!FLAGS_debug && !FLAGS_store_all_context_values) {
|
||||
block = builder->first_block();
|
||||
while (block) {
|
||||
RemoveDeadStoresBlock(block);
|
||||
|
||||
@@ -12,82 +12,140 @@
|
||||
#include <cinttypes>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/string_util.h"
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
namespace frontend {
|
||||
|
||||
uint64_t ParseInt64(const char* value) {
|
||||
return std::strtoull(value, nullptr, 0);
|
||||
}
|
||||
|
||||
double ParseFloat64(const char* value) {
|
||||
if (strstr(value, "0x") == value) {
|
||||
union {
|
||||
uint64_t ui;
|
||||
double dbl;
|
||||
} v;
|
||||
v.ui = ParseInt64(value);
|
||||
return v.dbl;
|
||||
std::string PPCContext::GetRegisterName(PPCRegister reg) {
|
||||
switch (reg) {
|
||||
case PPCRegister::kLR:
|
||||
return "lr";
|
||||
case PPCRegister::kCTR:
|
||||
return "ctr";
|
||||
case PPCRegister::kXER:
|
||||
return "xer";
|
||||
case PPCRegister::kFPSCR:
|
||||
return "fpscr";
|
||||
case PPCRegister::kVSCR:
|
||||
return "vscr";
|
||||
case PPCRegister::kCR:
|
||||
return "cr";
|
||||
default:
|
||||
if (static_cast<int>(reg) >= static_cast<int>(PPCRegister::kR0) &&
|
||||
static_cast<int>(reg) <= static_cast<int>(PPCRegister::kR31)) {
|
||||
return std::string("r") +
|
||||
std::to_string(static_cast<int>(reg) -
|
||||
static_cast<int>(PPCRegister::kR0));
|
||||
} else if (static_cast<int>(reg) >= static_cast<int>(PPCRegister::kFR0) &&
|
||||
static_cast<int>(reg) <=
|
||||
static_cast<int>(PPCRegister::kFR31)) {
|
||||
return std::string("fr") +
|
||||
std::to_string(static_cast<int>(reg) -
|
||||
static_cast<int>(PPCRegister::kFR0));
|
||||
} else if (static_cast<int>(reg) >= static_cast<int>(PPCRegister::kVR0) &&
|
||||
static_cast<int>(reg) <=
|
||||
static_cast<int>(PPCRegister::kVR128)) {
|
||||
return std::string("vr") +
|
||||
std::to_string(static_cast<int>(reg) -
|
||||
static_cast<int>(PPCRegister::kVR0));
|
||||
} else {
|
||||
assert_unhandled_case(reg);
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
return std::strtod(value, nullptr);
|
||||
}
|
||||
|
||||
vec128_t ParseVec128(const char* value) {
|
||||
vec128_t v;
|
||||
char* p = const_cast<char*>(value);
|
||||
if (*p == '[') ++p;
|
||||
v.i32[0] = std::strtoul(p, &p, 16);
|
||||
while (*p == ' ' || *p == ',') ++p;
|
||||
v.i32[1] = std::strtoul(p, &p, 16);
|
||||
while (*p == ' ' || *p == ',') ++p;
|
||||
v.i32[2] = std::strtoul(p, &p, 16);
|
||||
while (*p == ' ' || *p == ',') ++p;
|
||||
v.i32[3] = std::strtoul(p, &p, 16);
|
||||
return v;
|
||||
std::string PPCContext::GetStringFromValue(PPCRegister reg) const {
|
||||
switch (reg) {
|
||||
case PPCRegister::kLR:
|
||||
return string_util::to_hex_string(lr);
|
||||
case PPCRegister::kCTR:
|
||||
return string_util::to_hex_string(ctr);
|
||||
case PPCRegister::kXER:
|
||||
// return Int64ToHex(xer_ca);
|
||||
return "?";
|
||||
case PPCRegister::kFPSCR:
|
||||
// return Int64ToHex(fpscr);
|
||||
return "?";
|
||||
case PPCRegister::kVSCR:
|
||||
// return Int64ToHex(vscr_sat);
|
||||
return "?";
|
||||
case PPCRegister::kCR:
|
||||
// return Int64ToHex(cr);
|
||||
return "?";
|
||||
default:
|
||||
if (static_cast<int>(reg) >= static_cast<int>(PPCRegister::kR0) &&
|
||||
static_cast<int>(reg) <= static_cast<int>(PPCRegister::kR31)) {
|
||||
return string_util::to_hex_string(
|
||||
r[static_cast<int>(reg) - static_cast<int>(PPCRegister::kR0)]);
|
||||
} else if (static_cast<int>(reg) >= static_cast<int>(PPCRegister::kFR0) &&
|
||||
static_cast<int>(reg) <=
|
||||
static_cast<int>(PPCRegister::kFR31)) {
|
||||
return string_util::to_hex_string(
|
||||
f[static_cast<int>(reg) - static_cast<int>(PPCRegister::kFR0)]);
|
||||
} else if (static_cast<int>(reg) >= static_cast<int>(PPCRegister::kVR0) &&
|
||||
static_cast<int>(reg) <=
|
||||
static_cast<int>(PPCRegister::kVR128)) {
|
||||
return string_util::to_hex_string(
|
||||
v[static_cast<int>(reg) - static_cast<int>(PPCRegister::kVR0)]);
|
||||
} else {
|
||||
assert_unhandled_case(reg);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PPCContext::SetValueFromString(PPCRegister reg, std::string value) {
|
||||
// TODO(benvanik): set value from string to replace SetRegFromString?
|
||||
assert_always(false);
|
||||
}
|
||||
|
||||
void PPCContext::SetRegFromString(const char* name, const char* value) {
|
||||
int n;
|
||||
if (sscanf(name, "r%d", &n) == 1) {
|
||||
this->r[n] = ParseInt64(value);
|
||||
this->r[n] = string_util::from_string<uint64_t>(value);
|
||||
} else if (sscanf(name, "f%d", &n) == 1) {
|
||||
this->f[n] = ParseFloat64(value);
|
||||
this->f[n] = string_util::from_string<double>(value);
|
||||
} else if (sscanf(name, "v%d", &n) == 1) {
|
||||
this->v[n] = ParseVec128(value);
|
||||
this->v[n] = string_util::from_string<vec128_t>(value);
|
||||
} else {
|
||||
printf("Unrecognized register name: %s\n", name);
|
||||
}
|
||||
}
|
||||
|
||||
bool PPCContext::CompareRegWithString(const char* name, const char* value,
|
||||
char* out_value, size_t out_value_size) {
|
||||
char* out_value,
|
||||
size_t out_value_size) const {
|
||||
int n;
|
||||
if (sscanf(name, "r%d", &n) == 1) {
|
||||
uint64_t expected = ParseInt64(value);
|
||||
uint64_t expected = string_util::from_string<uint64_t>(value);
|
||||
if (this->r[n] != expected) {
|
||||
snprintf(out_value, out_value_size, "%016" PRIX64, this->r[n]);
|
||||
std::snprintf(out_value, out_value_size, "%016" PRIX64, this->r[n]);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else if (sscanf(name, "f%d", &n) == 1) {
|
||||
double expected = ParseFloat64(value);
|
||||
double expected = string_util::from_string<double>(value);
|
||||
// TODO(benvanik): epsilon
|
||||
if (this->f[n] != expected) {
|
||||
snprintf(out_value, out_value_size, "%f", this->f[n]);
|
||||
std::snprintf(out_value, out_value_size, "%f", this->f[n]);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else if (sscanf(name, "v%d", &n) == 1) {
|
||||
vec128_t expected = ParseVec128(value);
|
||||
vec128_t expected = string_util::from_string<vec128_t>(value);
|
||||
if (this->v[n] != expected) {
|
||||
snprintf(out_value, out_value_size, "[%.8X, %.8X, %.8X, %.8X]",
|
||||
this->v[n].i32[0], this->v[n].i32[1], this->v[n].i32[2],
|
||||
this->v[n].i32[3]);
|
||||
std::snprintf(out_value, out_value_size, "[%.8X, %.8X, %.8X, %.8X]",
|
||||
this->v[n].i32[0], this->v[n].i32[1], this->v[n].i32[2],
|
||||
this->v[n].i32[3]);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
printf("Unrecognized register name: %s\n", name);
|
||||
assert_always("Unrecognized register name: %s\n", name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#define XENIA_CPU_FRONTEND_PPC_CONTEXT_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "xenia/base/vec128.h"
|
||||
|
||||
@@ -40,6 +41,209 @@ namespace frontend {
|
||||
// 100: invalid
|
||||
// 128-256: VR
|
||||
|
||||
enum class PPCRegister {
|
||||
kR0 = 0,
|
||||
kR1,
|
||||
kR2,
|
||||
kR3,
|
||||
kR4,
|
||||
kR5,
|
||||
kR6,
|
||||
kR7,
|
||||
kR8,
|
||||
kR9,
|
||||
kR10,
|
||||
kR11,
|
||||
kR12,
|
||||
kR13,
|
||||
kR14,
|
||||
kR15,
|
||||
kR16,
|
||||
kR17,
|
||||
kR18,
|
||||
kR19,
|
||||
kR20,
|
||||
kR21,
|
||||
kR22,
|
||||
kR23,
|
||||
kR24,
|
||||
kR25,
|
||||
kR26,
|
||||
kR27,
|
||||
kR28,
|
||||
kR29,
|
||||
kR30,
|
||||
kR31,
|
||||
kFR0 = 32,
|
||||
kFR1,
|
||||
kFR2,
|
||||
kFR3,
|
||||
kFR4,
|
||||
kFR5,
|
||||
kFR6,
|
||||
kFR7,
|
||||
kFR8,
|
||||
kFR9,
|
||||
kFR10,
|
||||
kFR11,
|
||||
kFR12,
|
||||
kFR13,
|
||||
kFR14,
|
||||
kFR15,
|
||||
kFR16,
|
||||
kFR17,
|
||||
kFR18,
|
||||
kFR19,
|
||||
kFR20,
|
||||
kFR21,
|
||||
kFR22,
|
||||
kFR23,
|
||||
kFR24,
|
||||
kFR25,
|
||||
kFR26,
|
||||
kFR27,
|
||||
kFR28,
|
||||
kFR29,
|
||||
kFR30,
|
||||
kFR31,
|
||||
kVR0 = 64,
|
||||
kVR1,
|
||||
kVR2,
|
||||
kVR3,
|
||||
kVR4,
|
||||
kVR5,
|
||||
kVR6,
|
||||
kVR7,
|
||||
kVR8,
|
||||
kVR9,
|
||||
kVR10,
|
||||
kVR11,
|
||||
kVR12,
|
||||
kVR13,
|
||||
kVR14,
|
||||
kVR15,
|
||||
kVR16,
|
||||
kVR17,
|
||||
kVR18,
|
||||
kVR19,
|
||||
kVR20,
|
||||
kVR21,
|
||||
kVR22,
|
||||
kVR23,
|
||||
kVR24,
|
||||
kVR25,
|
||||
kVR26,
|
||||
kVR27,
|
||||
kVR28,
|
||||
kVR29,
|
||||
kVR30,
|
||||
kVR31,
|
||||
kVR32,
|
||||
kVR33,
|
||||
kVR34,
|
||||
kVR35,
|
||||
kVR36,
|
||||
kVR37,
|
||||
kVR38,
|
||||
kVR39,
|
||||
kVR40,
|
||||
kVR41,
|
||||
kVR42,
|
||||
kVR43,
|
||||
kVR44,
|
||||
kVR45,
|
||||
kVR46,
|
||||
kVR47,
|
||||
kVR48,
|
||||
kVR49,
|
||||
kVR50,
|
||||
kVR51,
|
||||
kVR52,
|
||||
kVR53,
|
||||
kVR54,
|
||||
kVR55,
|
||||
kVR56,
|
||||
kVR57,
|
||||
kVR58,
|
||||
kVR59,
|
||||
kVR60,
|
||||
kVR61,
|
||||
kVR62,
|
||||
kVR63,
|
||||
kVR64,
|
||||
kVR65,
|
||||
kVR66,
|
||||
kVR67,
|
||||
kVR68,
|
||||
kVR69,
|
||||
kVR70,
|
||||
kVR71,
|
||||
kVR72,
|
||||
kVR73,
|
||||
kVR74,
|
||||
kVR75,
|
||||
kVR76,
|
||||
kVR77,
|
||||
kVR78,
|
||||
kVR79,
|
||||
kVR80,
|
||||
kVR81,
|
||||
kVR82,
|
||||
kVR83,
|
||||
kVR84,
|
||||
kVR85,
|
||||
kVR86,
|
||||
kVR87,
|
||||
kVR88,
|
||||
kVR89,
|
||||
kVR90,
|
||||
kVR91,
|
||||
kVR92,
|
||||
kVR93,
|
||||
kVR94,
|
||||
kVR95,
|
||||
kVR96,
|
||||
kVR97,
|
||||
kVR98,
|
||||
kVR99,
|
||||
kVR100,
|
||||
kVR101,
|
||||
kVR102,
|
||||
kVR103,
|
||||
kVR104,
|
||||
kVR105,
|
||||
kVR106,
|
||||
kVR107,
|
||||
kVR108,
|
||||
kVR109,
|
||||
kVR110,
|
||||
kVR111,
|
||||
kVR112,
|
||||
kVR113,
|
||||
kVR114,
|
||||
kVR115,
|
||||
kVR116,
|
||||
kVR117,
|
||||
kVR118,
|
||||
kVR119,
|
||||
kVR120,
|
||||
kVR121,
|
||||
kVR122,
|
||||
kVR123,
|
||||
kVR124,
|
||||
kVR125,
|
||||
kVR126,
|
||||
kVR127,
|
||||
kVR128,
|
||||
|
||||
kLR,
|
||||
kCTR,
|
||||
kXER,
|
||||
kFPSCR,
|
||||
kVSCR,
|
||||
kCR,
|
||||
};
|
||||
|
||||
#pragma pack(push, 8)
|
||||
typedef struct alignas(64) PPCContext_s {
|
||||
// Must be stored at 0x0 for now.
|
||||
@@ -218,9 +422,13 @@ typedef struct alignas(64) PPCContext_s {
|
||||
// Keep the struct padded out to 64b total.
|
||||
uint8_t _padding[8];
|
||||
|
||||
static std::string GetRegisterName(PPCRegister reg);
|
||||
std::string GetStringFromValue(PPCRegister reg) const;
|
||||
void SetValueFromString(PPCRegister reg, std::string value);
|
||||
|
||||
void SetRegFromString(const char* name, const char* value);
|
||||
bool CompareRegWithString(const char* name, const char* value,
|
||||
char* out_value, size_t out_value_size);
|
||||
char* out_value, size_t out_value_size) const;
|
||||
} PPCContext;
|
||||
#pragma pack(pop)
|
||||
static_assert(sizeof(PPCContext) % 64 == 0, "64b padded");
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "xenia/cpu/function.h"
|
||||
#include "xenia/cpu/x64_context.h"
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
@@ -81,6 +82,7 @@ class StackWalker {
|
||||
virtual size_t CaptureStackTrace(void* thread_handle,
|
||||
uint64_t* frame_host_pcs,
|
||||
size_t frame_offset, size_t frame_count,
|
||||
X64Context* out_host_context,
|
||||
uint64_t* out_stack_hash = nullptr) = 0;
|
||||
|
||||
// Resolves symbol information for the given stack frames.
|
||||
|
||||
@@ -152,7 +152,10 @@ class Win32StackWalker : public StackWalker {
|
||||
|
||||
size_t CaptureStackTrace(void* thread_handle, uint64_t* frame_host_pcs,
|
||||
size_t frame_offset, size_t frame_count,
|
||||
X64Context* out_host_context,
|
||||
uint64_t* out_stack_hash) override {
|
||||
// TODO(benvanik): use xstate?
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/hh134240(v=vs.85).aspx
|
||||
// Query context. Thread must be suspended.
|
||||
// Need at least CONTEXT_CONTROL (for rip and rsp) and CONTEXT_INTEGER (for
|
||||
// rbp).
|
||||
@@ -163,6 +166,15 @@ class Win32StackWalker : public StackWalker {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (out_host_context) {
|
||||
out_host_context->rip = thread_context.Rip;
|
||||
out_host_context->eflags = thread_context.EFlags;
|
||||
std::memcpy(&out_host_context->int_registers.values, &thread_context.Rax,
|
||||
sizeof(out_host_context->int_registers.values));
|
||||
std::memcpy(&out_host_context->xmm_registers.values, &thread_context.Xmm0,
|
||||
sizeof(out_host_context->xmm_registers.values));
|
||||
}
|
||||
|
||||
// Setup the frame for walking.
|
||||
STACKFRAME64 stack_frame = {0};
|
||||
stack_frame.AddrPC.Mode = AddrModeFlat;
|
||||
|
||||
63
src/xenia/cpu/x64_context.cc
Normal file
63
src/xenia/cpu/x64_context.cc
Normal file
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/cpu/x64_context.h"
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/string_util.h"
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
|
||||
// NOTE: this order matches 1:1 with the X64Register enum.
|
||||
static const char* kRegisterNames[] = {
|
||||
"rip", "eflags", "rax", "rcx", "rdx", "rbx", "rsp",
|
||||
"rbp", "rsi", "rdi", "r8", "r9", "r10", "r11",
|
||||
"r12", "r13", "r14", "r15", "xmm0", "xmm1", "xmm2",
|
||||
"xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "xmm8", "xmm9",
|
||||
"xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15",
|
||||
};
|
||||
|
||||
const char* X64Context::GetRegisterName(X64Register reg) {
|
||||
return kRegisterNames[static_cast<int>(reg)];
|
||||
}
|
||||
|
||||
std::string X64Context::GetStringFromValue(X64Register reg) const {
|
||||
switch (reg) {
|
||||
case X64Register::kRip:
|
||||
return string_util::to_hex_string(rip);
|
||||
case X64Register::kEflags:
|
||||
return string_util::to_hex_string(eflags);
|
||||
default:
|
||||
if (static_cast<int>(reg) >= static_cast<int>(X64Register::kRax) &&
|
||||
static_cast<int>(reg) <= static_cast<int>(X64Register::kR15)) {
|
||||
return string_util::to_hex_string(
|
||||
int_registers.values[static_cast<int>(reg) -
|
||||
static_cast<int>(X64Register::kRax)]);
|
||||
} else if (static_cast<int>(reg) >=
|
||||
static_cast<int>(X64Register::kXmm0) &&
|
||||
static_cast<int>(reg) <=
|
||||
static_cast<int>(X64Register::kXmm15)) {
|
||||
return string_util::to_hex_string(
|
||||
xmm_registers.values[static_cast<int>(reg) -
|
||||
static_cast<int>(X64Register::kXmm0)]);
|
||||
} else {
|
||||
assert_unhandled_case(reg);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void X64Context::SetValueFromString(X64Register reg, std::string value) {
|
||||
// TODO(benvanik): set value from string.
|
||||
assert_always(false);
|
||||
}
|
||||
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
113
src/xenia/cpu/x64_context.h
Normal file
113
src/xenia/cpu/x64_context.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_CPU_X64_CONTEXT_H_
|
||||
#define XENIA_CPU_X64_CONTEXT_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
|
||||
enum class X64Register {
|
||||
// NOTE: this order matches 1:1 with the order in the X64Context.
|
||||
// NOTE: this order matches 1:1 with a string table in the x64_context.cc.
|
||||
kRip,
|
||||
kEflags,
|
||||
kRax,
|
||||
kRcx,
|
||||
kRdx,
|
||||
kRbx,
|
||||
kRsp,
|
||||
kRbp,
|
||||
kRsi,
|
||||
kRdi,
|
||||
kR8,
|
||||
kR9,
|
||||
kR10,
|
||||
kR11,
|
||||
kR12,
|
||||
kR13,
|
||||
kR14,
|
||||
kR15,
|
||||
kXmm0,
|
||||
kXmm1,
|
||||
kXmm2,
|
||||
kXmm3,
|
||||
kXmm4,
|
||||
kXmm5,
|
||||
kXmm6,
|
||||
kXmm7,
|
||||
kXmm8,
|
||||
kXmm9,
|
||||
kXmm10,
|
||||
kXmm11,
|
||||
kXmm12,
|
||||
kXmm13,
|
||||
kXmm14,
|
||||
kXmm15,
|
||||
};
|
||||
|
||||
struct X64Context {
|
||||
// TODO(benvanik): x64 registers.
|
||||
uint64_t rip;
|
||||
uint32_t eflags;
|
||||
union {
|
||||
struct {
|
||||
uint64_t rax;
|
||||
uint64_t rcx;
|
||||
uint64_t rdx;
|
||||
uint64_t rbx;
|
||||
uint64_t rsp;
|
||||
uint64_t rbp;
|
||||
uint64_t rsi;
|
||||
uint64_t rdi;
|
||||
uint64_t r8;
|
||||
uint64_t r9;
|
||||
uint64_t r10;
|
||||
uint64_t r11;
|
||||
uint64_t r12;
|
||||
uint64_t r13;
|
||||
uint64_t r14;
|
||||
uint64_t r15;
|
||||
};
|
||||
uint64_t values[16];
|
||||
} int_registers;
|
||||
union {
|
||||
struct {
|
||||
__m128 xmm0;
|
||||
__m128 xmm1;
|
||||
__m128 xmm2;
|
||||
__m128 xmm3;
|
||||
__m128 xmm4;
|
||||
__m128 xmm5;
|
||||
__m128 xmm6;
|
||||
__m128 xmm7;
|
||||
__m128 xmm8;
|
||||
__m128 xmm9;
|
||||
__m128 xmm10;
|
||||
__m128 xmm11;
|
||||
__m128 xmm12;
|
||||
__m128 xmm13;
|
||||
__m128 xmm14;
|
||||
__m128 xmm15;
|
||||
};
|
||||
__m128 values[16];
|
||||
} xmm_registers;
|
||||
|
||||
static const char* GetRegisterName(X64Register reg);
|
||||
std::string GetStringFromValue(X64Register reg) const;
|
||||
void SetValueFromString(X64Register reg, std::string value);
|
||||
};
|
||||
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_CPU_X64_CONTEXT_H_
|
||||
Reference in New Issue
Block a user