Files
Xenia-Canary/src/xenia/cpu/ppc/ppc_context.h
2018-02-14 16:22:14 -06:00

445 lines
9.3 KiB
C++

/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_CPU_PPC_PPC_CONTEXT_H_
#define XENIA_CPU_PPC_PPC_CONTEXT_H_
#include <cstdint>
#include <mutex>
#include <string>
#include "xenia/base/vec128.h"
namespace xe {
namespace cpu {
class Processor;
class ThreadState;
} // namespace cpu
namespace kernel {
class KernelState;
} // namespace kernel
} // namespace xe
namespace xe {
namespace cpu {
namespace ppc {
// Map:
// 0-31: GPR
// 32-63: FPR
// 64: LR
// 65: CTR
// 66: XER
// 67: FPSCR
// 68: VSCR
// 69-76: CR0-7
// 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 PPCContext_s {
// Must be stored at 0x0 for now.
// TODO(benvanik): find a nice way to describe this to the JIT.
ThreadState* thread_state; // 0x0
// TODO(benvanik): this is getting nasty. Must be here.
uint8_t* virtual_membase; // 0x8
// Most frequently used registers first.
uint64_t lr; // 0x10 Link register
uint64_t ctr; // 0x18 Count register
uint64_t r[32]; // 0x20 General purpose registers
double f[32]; // 0x120 Floating-point registers
vec128_t v[128]; // 0x220 VMX128 vector registers
// XER register:
// Split to make it easier to do individual updates.
uint8_t xer_ca; // 0xA20
uint8_t xer_ov; // 0xA21
uint8_t xer_so; // 0xA22
// Condition registers:
// These are split to make it easier to do DCE on unused stores.
uint64_t cr() const;
void set_cr(uint64_t value);
union {
uint32_t value;
struct {
uint8_t cr0_lt; // Negative (LT) - result is negative
uint8_t cr0_gt; // Positive (GT) - result is positive (and not zero)
uint8_t cr0_eq; // Zero (EQ) - result is zero or a stwcx/stdcx completed
// successfully
uint8_t cr0_so; // Summary Overflow (SO) - copy of XER[SO]
};
} cr0; // 0xA24
union {
uint32_t value;
struct {
uint8_t cr1_fx; // FP exception summary - copy of FPSCR[FX]
uint8_t cr1_fex; // FP enabled exception summary - copy of FPSCR[FEX]
uint8_t
cr1_vx; // FP invalid operation exception summary - copy of FPSCR[VX]
uint8_t cr1_ox; // FP overflow exception - copy of FPSCR[OX]
};
} cr1;
union {
uint32_t value;
struct {
uint8_t cr2_0;
uint8_t cr2_1;
uint8_t cr2_2;
uint8_t cr2_3;
};
} cr2;
union {
uint32_t value;
struct {
uint8_t cr3_0;
uint8_t cr3_1;
uint8_t cr3_2;
uint8_t cr3_3;
};
} cr3;
union {
uint32_t value;
struct {
uint8_t cr4_0;
uint8_t cr4_1;
uint8_t cr4_2;
uint8_t cr4_3;
};
} cr4;
union {
uint32_t value;
struct {
uint8_t cr5_0;
uint8_t cr5_1;
uint8_t cr5_2;
uint8_t cr5_3;
};
} cr5;
union {
uint32_t value;
struct {
uint8_t cr6_all_equal;
uint8_t cr6_1;
uint8_t cr6_none_equal;
uint8_t cr6_3;
};
} cr6;
union {
uint32_t value;
struct {
uint8_t cr7_0;
uint8_t cr7_1;
uint8_t cr7_2;
uint8_t cr7_3;
};
} cr7;
union {
uint32_t value;
struct {
uint32_t rn : 2; // FP rounding control: 00 = nearest
// 01 = toward zero
// 10 = toward +infinity
// 11 = toward -infinity
uint32_t ni : 1; // Floating-point non-IEEE mode
uint32_t xe : 1; // IEEE floating-point inexact exception enable
uint32_t ze : 1; // IEEE floating-point zero divide exception enable
uint32_t ue : 1; // IEEE floating-point underflow exception enable
uint32_t oe : 1; // IEEE floating-point overflow exception enable
uint32_t ve : 1; // FP invalid op exception enable
uint32_t vxcvi : 1; // FP invalid op exception: invalid integer convert
// -- sticky
uint32_t vxsqrt : 1; // FP invalid op exception: invalid sqrt -- sticky
uint32_t vxsoft : 1; // FP invalid op exception: software request
// -- sticky
uint32_t reserved : 1;
uint32_t fprf_un : 1; // FP result unordered or NaN (FU or ?)
uint32_t fprf_eq : 1; // FP result equal or zero (FE or =)
uint32_t fprf_gt : 1; // FP result greater than or positive (FG or >)
uint32_t fprf_lt : 1; // FP result less than or negative (FL or <)
uint32_t fprf_c : 1; // FP result class
uint32_t fi : 1; // FP fraction inexact
uint32_t fr : 1; // FP fraction rounded
uint32_t vxvc : 1; // FP invalid op exception: invalid compare --
// sticky
uint32_t vximz : 1; // FP invalid op exception: infinity * 0 -- sticky
uint32_t vxzdz : 1; // FP invalid op exception: 0 / 0 -- sticky
uint32_t vxidi : 1; // FP invalid op exception: infinity / infinity
// -- sticky
uint32_t vxisi : 1; // FP invalid op exception: infinity - infinity
// -- sticky
uint32_t vxsnan : 1; // FP invalid op exception: SNaN -- sticky
uint32_t
xx : 1; // FP inexact exception -- sticky
uint32_t
zx : 1; // FP zero divide exception -- sticky
uint32_t
ux : 1; // FP underflow exception -- sticky
uint32_t
ox : 1; // FP overflow exception -- sticky
uint32_t vx : 1; // FP invalid operation exception summary
uint32_t fex : 1; // FP enabled exception summary
uint32_t
fx : 1; // FP exception summary -- sticky
} bits;
} fpscr; // Floating-point status and control register
uint8_t vscr_sat;
// uint32_t get_fprf() {
// return fpscr.value & 0x000F8000;
// }
// void set_fprf(const uint32_t v) {
// fpscr.value = (fpscr.value & ~0x000F8000) | v;
// }
// Thread ID assigned to this context.
uint32_t thread_id;
// Global interrupt lock, held while interrupts are disabled or interrupts are
// executing. This is shared among all threads and comes from the processor.
std::recursive_mutex* global_mutex;
// Used to shuttle data into externs. Contents volatile.
uint64_t scratch;
// Processor-specific data pointer. Used on callbacks to get access to the
// current runtime and its data.
Processor* processor;
// Shared kernel state, for easy access from kernel exports.
xe::kernel::KernelState* kernel_state;
uint8_t* physical_membase;
// Value of last reserved load
uint64_t reserved_val;
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) const;
} PPCContext;
#pragma pack(pop)
static_assert(sizeof(PPCContext) % 64 == 0, "64b padded");
} // namespace ppc
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_PPC_PPC_CONTEXT_H_