Lioncash 0049ef3a2a Gekko: Centralize bitmasking of the FPSCR within UReg_FPSCR
Rather than introduce this handling in every system instruction that modifies
the FPSCR directly, we can instead just handle it within the data structure
instead, which avoids duplicating mask handling across instructions.

This also allows handling proper masking from the debugger register
windows themselves without duplicating masking behavior there either.
2018-06-12 14:15:50 -04:00

866 lines
15 KiB
C++

// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
// Gekko related unions, structs, ...
#pragma once
#include "Common/BitField.h"
#include "Common/CommonTypes.h"
// --- Gekko Instruction ---
union UGeckoInstruction
{
u32 hex = 0;
UGeckoInstruction() = default;
UGeckoInstruction(u32 hex_) : hex(hex_) {}
struct
{
// Record bit
// 1, if the condition register should be updated by this instruction
u32 Rc : 1;
u32 SUBOP10 : 10;
// Source GPR
u32 RB : 5;
// Source or destination GPR
u32 RA : 5;
// Destination GPR
u32 RD : 5;
// Primary opcode
u32 OPCD : 6;
};
struct
{
// Immediate, signed 16-bit
signed SIMM_16 : 16;
u32 : 5;
// Conditions on which to trap
u32 TO : 5;
u32 OPCD_2 : 6;
};
struct
{
u32 Rc_2 : 1;
u32 : 10;
u32 : 5;
u32 : 5;
// Source GPR
u32 RS : 5;
u32 OPCD_3 : 6;
};
struct
{
// Immediate, unsigned 16-bit
u32 UIMM : 16;
u32 : 5;
u32 : 5;
u32 OPCD_4 : 6;
};
struct
{
// Link bit
// 1, if branch instructions should put the address of the next instruction into the link
// register
u32 LK : 1;
// Absolute address bit
// 1, if the immediate field represents an absolute address
u32 AA : 1;
// Immediate, signed 24-bit
u32 LI : 24;
u32 OPCD_5 : 6;
};
struct
{
u32 LK_2 : 1;
u32 AA_2 : 1;
// Branch displacement, signed 14-bit (right-extended by 0b00)
u32 BD : 14;
// Branch condition
u32 BI : 5;
// Conditional branch control
u32 BO : 5;
u32 OPCD_6 : 6;
};
struct
{
u32 LK_3 : 1;
u32 : 10;
u32 : 5;
u32 BI_2 : 5;
u32 BO_2 : 5;
u32 OPCD_7 : 6;
};
struct
{
u32 : 11;
u32 RB_2 : 5;
u32 RA_2 : 5;
// ?
u32 L : 1;
u32 : 1;
// Destination field in CR or FPSCR
u32 CRFD : 3;
u32 OPCD_8 : 6;
};
struct
{
signed SIMM_16_2 : 16;
u32 RA_3 : 5;
u32 L_2 : 1;
u32 : 1;
u32 CRFD_2 : 3;
u32 OPCD_9 : 6;
};
struct
{
u32 UIMM_2 : 16;
u32 RA_4 : 5;
u32 L_3 : 1;
u32 : 1;
u32 CRFD_3 : 3;
u32 OPCD_A : 6;
};
struct
{
u32 : 1;
u32 SUBOP10_2 : 10;
u32 RB_5 : 5;
u32 RA_5 : 5;
u32 L_4 : 1;
u32 : 1;
u32 CRFD_4 : 3;
u32 OPCD_B : 6;
};
struct
{
u32 : 16;
// Segment register
u32 SR : 4;
u32 : 1;
u32 RS_2 : 5;
u32 OPCD_C : 6;
};
// Table 59
struct
{
u32 Rc_4 : 1;
u32 SUBOP5 : 5;
// ?
u32 RC : 5;
u32 : 5;
u32 RA_6 : 5;
u32 RD_2 : 5;
u32 OPCD_D : 6;
};
struct
{
u32 : 10;
// Overflow enable
u32 OE : 1;
// Special-purpose register
u32 SPR : 10;
u32 : 11;
};
struct
{
u32 : 10;
u32 OE_3 : 1;
// Upper special-purpose register
u32 SPRU : 5;
// Lower special-purpose register
u32 SPRL : 5;
u32 : 11;
};
// rlwinmx
struct
{
u32 Rc_3 : 1;
// Mask end
u32 ME : 5;
// Mask begin
u32 MB : 5;
// Shift amount
u32 SH : 5;
u32 : 16;
};
// crxor
struct
{
u32 : 11;
// Source bit in the CR
u32 CRBB : 5;
// Source bit in the CR
u32 CRBA : 5;
// Destination bit in the CR
u32 CRBD : 5;
u32 : 6;
};
// mftb
struct
{
u32 : 11;
// Time base register
u32 TBR : 10;
u32 : 11;
};
struct
{
u32 : 11;
// Upper time base register
u32 TBRU : 5;
// Lower time base register
u32 TBRL : 5;
u32 : 11;
};
struct
{
u32 : 18;
// Source field in the CR or FPSCR
u32 CRFS : 3;
u32 : 2;
u32 CRFD_5 : 3;
u32 : 6;
};
struct
{
u32 : 12;
// Field mask, identifies the CR fields to be updated by mtcrf
u32 CRM : 8;
u32 : 1;
// Destination FPR
u32 FD : 5;
u32 : 6;
};
struct
{
u32 : 6;
// Source FPR
u32 FC : 5;
// Source FPR
u32 FB : 5;
// Source FPR
u32 FA : 5;
// Source FPR
u32 FS : 5;
u32 : 6;
};
struct
{
u32 : 17;
// Field mask, identifies the FPSCR fields to be updated by mtfsf
u32 FM : 8;
u32 : 7;
};
// paired single quantized load/store
struct
{
u32 : 1;
u32 SUBOP6 : 6;
// Graphics quantization register to use
u32 Ix : 3;
// 0: paired single, 1: scalar
u32 Wx : 1;
u32 : 1;
// Graphics quantization register to use
u32 I : 3;
// 0: paired single, 1: scalar
u32 W : 1;
u32 : 16;
};
struct
{
signed SIMM_12 : 12;
u32 : 20;
};
struct
{
u32 : 11;
// Number of bytes to use in lswi/stswi (0 means 32 bytes)
u32 NB : 5;
};
};
//
// --- Gekko Special Registers ---
//
// quantize types
enum EQuantizeType : u32
{
QUANTIZE_FLOAT = 0,
QUANTIZE_INVALID1 = 1,
QUANTIZE_INVALID2 = 2,
QUANTIZE_INVALID3 = 3,
QUANTIZE_U8 = 4,
QUANTIZE_U16 = 5,
QUANTIZE_S8 = 6,
QUANTIZE_S16 = 7,
};
// GQR Register
union UGQR
{
BitField<0, 3, EQuantizeType> st_type;
BitField<8, 6, u32> st_scale;
BitField<16, 3, EQuantizeType> ld_type;
BitField<24, 6, u32> ld_scale;
u32 Hex = 0;
UGQR() = default;
explicit UGQR(u32 hex_) : Hex{hex_} {}
};
#define XER_CA_SHIFT 29
#define XER_OV_SHIFT 30
#define XER_SO_SHIFT 31
#define XER_OV_MASK 1
#define XER_SO_MASK 2
// XER
union UReg_XER
{
struct
{
u32 BYTE_COUNT : 7;
u32 : 1;
u32 BYTE_CMP : 8;
u32 : 13;
u32 CA : 1;
u32 OV : 1;
u32 SO : 1;
};
u32 Hex = 0;
UReg_XER() = default;
explicit UReg_XER(u32 hex_) : Hex{hex_} {}
};
// Machine State Register
union UReg_MSR
{
struct
{
u32 LE : 1;
u32 RI : 1;
u32 PM : 1;
u32 : 1; // res28
u32 DR : 1;
u32 IR : 1;
u32 IP : 1;
u32 : 1; // res24
u32 FE1 : 1;
u32 BE : 1;
u32 SE : 1;
u32 FE0 : 1;
u32 MCHECK : 1;
u32 FP : 1;
u32 PR : 1;
u32 EE : 1;
u32 ILE : 1;
u32 : 1; // res14
u32 POW : 1;
u32 res : 13;
};
u32 Hex = 0;
UReg_MSR() = default;
explicit UReg_MSR(u32 hex_) : Hex{hex_} {}
};
#define FPRF_SHIFT 12
#define FPRF_MASK (0x1F << FPRF_SHIFT)
// FPSCR exception flags
enum FPSCRExceptionFlag : u32
{
FPSCR_FX = 1U << (31 - 0),
FPSCR_FEX = 1U << (31 - 1),
FPSCR_VX = 1U << (31 - 2),
FPSCR_OX = 1U << (31 - 3),
FPSCR_UX = 1U << (31 - 4),
FPSCR_ZX = 1U << (31 - 5),
FPSCR_XX = 1U << (31 - 6),
FPSCR_VXSNAN = 1U << (31 - 7),
FPSCR_VXISI = 1U << (31 - 8),
FPSCR_VXIDI = 1U << (31 - 9),
FPSCR_VXZDZ = 1U << (31 - 10),
FPSCR_VXIMZ = 1U << (31 - 11),
FPSCR_VXVC = 1U << (31 - 12),
FPSCR_VXSOFT = 1U << (31 - 21),
FPSCR_VXSQRT = 1U << (31 - 22),
FPSCR_VXCVI = 1U << (31 - 23),
FPSCR_VE = 1U << (31 - 24),
FPSCR_VX_ANY = FPSCR_VXSNAN | FPSCR_VXISI | FPSCR_VXIDI | FPSCR_VXZDZ | FPSCR_VXIMZ | FPSCR_VXVC |
FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI,
FPSCR_ANY_X = FPSCR_OX | FPSCR_UX | FPSCR_ZX | FPSCR_XX | FPSCR_VX_ANY,
};
// Floating Point Status and Control Register
union UReg_FPSCR
{
struct
{
// Rounding mode (towards: nearest, zero, +inf, -inf)
u32 RN : 2;
// Non-IEEE mode enable (aka flush-to-zero)
u32 NI : 1;
// Inexact exception enable
u32 XE : 1;
// IEEE division by zero exception enable
u32 ZE : 1;
// IEEE underflow exception enable
u32 UE : 1;
// IEEE overflow exception enable
u32 OE : 1;
// Invalid operation exception enable
u32 VE : 1;
// Invalid operation exception for integer conversion (sticky)
u32 VXCVI : 1;
// Invalid operation exception for square root (sticky)
u32 VXSQRT : 1;
// Invalid operation exception for software request (sticky)
u32 VXSOFT : 1;
// reserved
u32 : 1;
// Floating point result flags (includes FPCC) (not sticky)
// from more to less significand: class, <, >, =, ?
u32 FPRF : 5;
// Fraction inexact (not sticky)
u32 FI : 1;
// Fraction rounded (not sticky)
u32 FR : 1;
// Invalid operation exception for invalid comparison (sticky)
u32 VXVC : 1;
// Invalid operation exception for inf * 0 (sticky)
u32 VXIMZ : 1;
// Invalid operation exception for 0 / 0 (sticky)
u32 VXZDZ : 1;
// Invalid operation exception for inf / inf (sticky)
u32 VXIDI : 1;
// Invalid operation exception for inf - inf (sticky)
u32 VXISI : 1;
// Invalid operation exception for SNaN (sticky)
u32 VXSNAN : 1;
// Inexact exception (sticky)
u32 XX : 1;
// Division by zero exception (sticky)
u32 ZX : 1;
// Underflow exception (sticky)
u32 UX : 1;
// Overflow exception (sticky)
u32 OX : 1;
// Invalid operation exception summary (not sticky)
u32 VX : 1;
// Enabled exception summary (not sticky)
u32 FEX : 1;
// Exception summary (sticky)
u32 FX : 1;
};
u32 Hex = 0;
// The FPSCR's 20th bit (11th from a little endian perspective)
// is defined as reserved and set to zero. Attempts to modify it
// are ignored by hardware, so we do the same.
static constexpr u32 mask = 0xFFFFF7FF;
UReg_FPSCR() = default;
explicit UReg_FPSCR(u32 hex_) : Hex{hex_ & mask} {}
UReg_FPSCR& operator=(u32 value)
{
Hex = value & mask;
return *this;
}
UReg_FPSCR& operator|=(u32 value)
{
Hex |= value & mask;
return *this;
}
UReg_FPSCR& operator&=(u32 value)
{
Hex &= value;
return *this;
}
UReg_FPSCR& operator^=(u32 value)
{
Hex ^= value & mask;
return *this;
}
void ClearFIFR()
{
FI = 0;
FR = 0;
}
};
// Hardware Implementation-Dependent Register 0
union UReg_HID0
{
struct
{
u32 NOOPTI : 1;
u32 : 1;
u32 BHT : 1;
u32 ABE : 1;
u32 : 1;
u32 BTIC : 1;
u32 DCFA : 1;
u32 SGE : 1;
u32 IFEM : 1;
u32 SPD : 1;
u32 DCFI : 1;
u32 ICFI : 1;
u32 DLOCK : 1;
u32 ILOCK : 1;
u32 DCE : 1;
u32 ICE : 1;
u32 NHR : 1;
u32 : 3;
u32 DPM : 1;
u32 SLEEP : 1;
u32 NAP : 1;
u32 DOZE : 1;
u32 PAR : 1;
u32 ECLK : 1;
u32 : 1;
u32 BCLK : 1;
u32 EBD : 1;
u32 EBA : 1;
u32 DBP : 1;
u32 EMCP : 1;
};
u32 Hex = 0;
};
// Hardware Implementation-Dependent Register 2
union UReg_HID2
{
struct
{
u32 : 16;
u32 DQOEE : 1;
u32 DCMEE : 1;
u32 DNCEE : 1;
u32 DCHEE : 1;
u32 DQOERR : 1;
u32 DCMERR : 1;
u32 DNCERR : 1;
u32 DCHERR : 1;
u32 DMAQL : 4;
u32 LCE : 1;
u32 PSE : 1;
u32 WPE : 1;
u32 LSQE : 1;
};
u32 Hex = 0;
UReg_HID2() = default;
explicit UReg_HID2(u32 hex_) : Hex{hex_} {}
};
// Hardware Implementation-Dependent Register 4
union UReg_HID4
{
struct
{
u32 : 20;
u32 L2CFI : 1;
u32 L2MUM : 1;
u32 DBP : 1;
u32 LPE : 1;
u32 ST0 : 1;
u32 SBE : 1;
u32 : 1;
u32 BPD : 2;
u32 L2FM : 2;
u32 : 1;
};
u32 Hex = 0;
UReg_HID4() = default;
explicit UReg_HID4(u32 hex_) : Hex{hex_} {}
};
// SPR1 - Page Table format
union UReg_SPR1
{
u32 Hex;
struct
{
u32 htaborg : 16;
u32 : 7;
u32 htabmask : 9;
};
};
// MMCR0 - Monitor Mode Control Register 0 format
union UReg_MMCR0
{
u32 Hex;
struct
{
u32 PMC2SELECT : 6;
u32 PMC1SELECT : 7;
u32 PMCTRIGGER : 1;
u32 PMCINTCONTROL : 1;
u32 PMC1INTCONTROL : 1;
u32 THRESHOLD : 6;
u32 INTONBITTRANS : 1;
u32 RTCSELECT : 2;
u32 DISCOUNT : 1;
u32 ENINT : 1;
u32 DMR : 1;
u32 DMS : 1;
u32 DU : 1;
u32 DP : 1;
u32 DIS : 1;
};
};
// MMCR1 - Monitor Mode Control Register 1 format
union UReg_MMCR1
{
u32 Hex;
struct
{
u32 : 22;
u32 PMC4SELECT : 5;
u32 PMC3SELECT : 5;
};
};
// Write Pipe Address Register
union UReg_WPAR
{
struct
{
u32 BNE : 1;
u32 : 4;
u32 GB_ADDR : 27;
};
u32 Hex = 0;
UReg_WPAR() = default;
explicit UReg_WPAR(u32 hex_) : Hex{hex_} {}
};
// Direct Memory Access Upper register
union UReg_DMAU
{
struct
{
u32 DMA_LEN_U : 5;
u32 MEM_ADDR : 27;
};
u32 Hex = 0;
UReg_DMAU() = default;
explicit UReg_DMAU(u32 hex_) : Hex{hex_} {}
};
// Direct Memory Access Lower (DMAL) register
union UReg_DMAL
{
struct
{
u32 DMA_F : 1;
u32 DMA_T : 1;
u32 DMA_LEN_L : 2;
u32 DMA_LD : 1;
u32 LC_ADDR : 27;
};
u32 Hex = 0;
UReg_DMAL() = default;
explicit UReg_DMAL(u32 hex_) : Hex{hex_} {}
};
union UReg_BAT_Up
{
struct
{
u32 VP : 1;
u32 VS : 1;
u32 BL : 11; // Block length (aka block size mask)
u32 : 4;
u32 BEPI : 15;
};
u32 Hex = 0;
UReg_BAT_Up() = default;
explicit UReg_BAT_Up(u32 hex_) : Hex{hex_} {}
};
union UReg_BAT_Lo
{
struct
{
u32 PP : 2;
u32 : 1;
u32 WIMG : 4;
u32 : 10;
u32 BRPN : 15; // Physical Block Number
};
u32 Hex = 0;
UReg_BAT_Lo() = default;
explicit UReg_BAT_Lo(u32 hex_) : Hex{hex_} {}
};
union UReg_PTE
{
struct
{
u64 API : 6;
u64 H : 1;
u64 VSID : 24;
u64 V : 1;
u64 PP : 2;
u64 : 1;
u64 WIMG : 4;
u64 C : 1;
u64 R : 1;
u64 : 3;
u64 RPN : 20;
};
u64 Hex = 0;
u32 Hex32[2];
};
//
// --- Gekko Types and Defs ---
//
// branches
enum
{
BO_BRANCH_IF_CTR_0 = 2, // 3
BO_DONT_DECREMENT_FLAG = 4, // 2
BO_BRANCH_IF_TRUE = 8, // 1
BO_DONT_CHECK_CONDITION = 16, // 0
};
// Special purpose register indices
enum
{
SPR_XER = 1,
SPR_LR = 8,
SPR_CTR = 9,
SPR_DSISR = 18,
SPR_DAR = 19,
SPR_DEC = 22,
SPR_SDR = 25,
SPR_SRR0 = 26,
SPR_SRR1 = 27,
SPR_TL = 268,
SPR_TU = 269,
SPR_TL_W = 284,
SPR_TU_W = 285,
SPR_PVR = 287,
SPR_SPRG0 = 272,
SPR_SPRG1 = 273,
SPR_SPRG2 = 274,
SPR_SPRG3 = 275,
SPR_EAR = 282,
SPR_IBAT0U = 528,
SPR_IBAT0L = 529,
SPR_IBAT1U = 530,
SPR_IBAT1L = 531,
SPR_IBAT2U = 532,
SPR_IBAT2L = 533,
SPR_IBAT3U = 534,
SPR_IBAT3L = 535,
SPR_DBAT0U = 536,
SPR_DBAT0L = 537,
SPR_DBAT1U = 538,
SPR_DBAT1L = 539,
SPR_DBAT2U = 540,
SPR_DBAT2L = 541,
SPR_DBAT3U = 542,
SPR_DBAT3L = 543,
SPR_IBAT4U = 560,
SPR_IBAT4L = 561,
SPR_IBAT5U = 562,
SPR_IBAT5L = 563,
SPR_IBAT6U = 564,
SPR_IBAT6L = 565,
SPR_IBAT7U = 566,
SPR_IBAT7L = 567,
SPR_DBAT4U = 568,
SPR_DBAT4L = 569,
SPR_DBAT5U = 570,
SPR_DBAT5L = 571,
SPR_DBAT6U = 572,
SPR_DBAT6L = 573,
SPR_DBAT7U = 574,
SPR_DBAT7L = 575,
SPR_GQR0 = 912,
SPR_HID0 = 1008,
SPR_HID1 = 1009,
SPR_HID2 = 920,
SPR_HID4 = 1011,
SPR_WPAR = 921,
SPR_DMAU = 922,
SPR_DMAL = 923,
SPR_ECID_U = 924,
SPR_ECID_M = 925,
SPR_ECID_L = 926,
SPR_L2CR = 1017,
SPR_UMMCR0 = 936,
SPR_MMCR0 = 952,
SPR_PMC1 = 953,
SPR_PMC2 = 954,
SPR_UMMCR1 = 940,
SPR_MMCR1 = 956,
SPR_PMC3 = 957,
SPR_PMC4 = 958,
};
// Exceptions
enum
{
EXCEPTION_DECREMENTER = 0x00000001,
EXCEPTION_SYSCALL = 0x00000002,
EXCEPTION_EXTERNAL_INT = 0x00000004,
EXCEPTION_DSI = 0x00000008,
EXCEPTION_ISI = 0x00000010,
EXCEPTION_ALIGNMENT = 0x00000020,
EXCEPTION_FPU_UNAVAILABLE = 0x00000040,
EXCEPTION_PROGRAM = 0x00000080,
EXCEPTION_PERFORMANCE_MONITOR = 0x00000100,
EXCEPTION_FAKE_MEMCHECK_HIT = 0x00000200,
};
constexpr s32 SignExt16(s16 x)
{
return (s32)x;
}
constexpr s32 SignExt26(u32 x)
{
return x & 0x2000000 ? (s32)(x | 0xFC000000) : (s32)(x);
}