pcsx2/pcsx2/R5900.h

417 lines
14 KiB
C++

/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2009 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
//////////////////////////////////////////////////////////////////////////////////////////
#ifndef __LINUX__
#pragma region Recompiler Stuffs
#endif
// This code section contains recompiler vars that are used in "shared" code. Placing
// them in iR5900.h would mean having to include that into more files than I care to
// right now, so we're sticking them here for now until a better solution comes along.
extern bool g_EEFreezeRegs;
extern bool g_ExecBiosHack;
namespace Exception
{
// Implementation Note: this exception has no meaningful type information and we don't
// care to have it be caught by any BaseException handlers lying about, so let's not
// derive from BaseException :D
class ExitCpuExecute
{
public:
explicit ExitCpuExecute() { }
};
}
#ifndef __LINUX__
#pragma endregion
#endif
//////////////////////////////////////////////////////////////////////////////////////////
// EE Bios function name tables.
namespace R5900 {
extern const char* const bios[256];
}
extern s32 EEsCycle;
extern u32 EEoCycle;
union GPR_reg { // Declare union type GPR register
u64 UD[2]; //128 bits
s64 SD[2];
u32 UL[4];
s32 SL[4];
u16 US[8];
s16 SS[8];
u8 UC[16];
s8 SC[16];
};
union GPRregs {
struct {
GPR_reg r0, at, v0, v1, a0, a1, a2, a3,
t0, t1, t2, t3, t4, t5, t6, t7,
s0, s1, s2, s3, s4, s5, s6, s7,
t8, t9, k0, k1, gp, sp, s8, ra;
} n;
GPR_reg r[32];
};
union PERFregs {
struct
{
union
{
struct
{
u32 pad0:1; // LSB should always be zero (or undefined)
u32 EXL0:1; // enable PCR0 during Level 1 exception handling
u32 K0:1; // enable PCR0 during Kernel Mode execution
u32 S0:1; // enable PCR0 during Supervisor mode execution
u32 U0:1; // enable PCR0 during User-mode execution
u32 Event0:5; // PCR0 event counter (all values except 1 ignored at this time)
u32 pad1:1; // more zero/undefined padding [bit 10]
u32 EXL1:1; // enable PCR1 during Level 1 exception handling
u32 K1:1; // enable PCR1 during Kernel Mode execution
u32 S1:1; // enable PCR1 during Supervisor mode execution
u32 U1:1; // enable PCR1 during User-mode execution
u32 Event1:5; // PCR1 event counter (all values except 1 ignored at this time)
u32 Reserved:11;
u32 CTE:1; // Counter enable bit, no counting if set to zero.
} b;
u32 val;
} pccr;
u32 pcr0, pcr1, pad;
} n;
u32 r[4];
};
union CP0regs {
struct {
u32 Index, Random, EntryLo0, EntryLo1,
Context, PageMask, Wired, Reserved0,
BadVAddr, Count, EntryHi, Compare;
union {
struct {
u32 IE:1; // Bit 0: Interrupt Enable flag.
u32 EXL:1; // Bit 1: Exception Level, set on any exception not covered by ERL.
u32 ERL:1; // Bit 2: Error level, set on Resetm NMI, perf/debug exceptions.
u32 KSU:2; // Bits 3-4: Kernel [clear] / Supervisor [set] mode
u32 unused0:3;
u32 IM:8; // Bits 10-15: Interrupt mask (bits 12,13,14 are unused)
u32 EIE:1; // Bit 16: IE bit enabler. When cleared, ints are disabled regardless of IE status.
u32 _EDI:1; // Bit 17: Interrupt Enable (set enables ints in all modes, clear enables ints in kernel mode only)
u32 CH:1; // Bit 18: Status of most recent cache instruction (set for hit, clear for miss)
u32 unused1:3;
u32 BEV:1; // Bit 22: if set, use bootstrap for TLB/general exceptions
u32 DEV:1; // Bit 23: if set, use bootstrap for perf/debug exceptions
u32 unused2:2;
u32 FR:1; // (?)
u32 unused3:1;
u32 CU:4; // Bits 28-31: Co-processor Usable flag
} b;
u32 val;
} Status;
u32 Cause, EPC, PRid,
Config, LLAddr, WatchLO, WatchHI,
XContext, Reserved1, Reserved2, Debug,
DEPC, PerfCnt, ErrCtl, CacheErr,
TagLo, TagHi, ErrorEPC, DESAVE;
} n;
u32 r[32];
};
struct cpuRegisters {
GPRregs GPR; // GPR regs
// NOTE: don't change order since recompiler uses it
GPR_reg HI;
GPR_reg LO; // hi & log 128bit wide
CP0regs CP0; // is COP0 32bit?
u32 sa; // shift amount (32bit), needs to be 16 byte aligned
u32 IsDelaySlot; // set true when the current instruction is a delay slot.
u32 pc; // Program counter, when changing offset in struct, check iR5900-X.S to make sure offset is correct
u32 code; // current instruction
PERFregs PERF;
u32 eCycle[32];
u32 sCycle[32]; // for internal counters
u32 cycle; // calculate cpucycles..
u32 interrupt;
int branch;
int opmode; // operating mode
u32 tempcycles;
};
// used for optimization
union GPR_reg64 {
u64 UD[1]; //64 bits
s64 SD[1];
u32 UL[2];
s32 SL[3];
u16 US[4];
s16 SS[4];
u8 UC[8];
s8 SC[8];
};
union FPRreg {
float f;
u32 UL;
s32 SL; // signed 32bit used for sign extension in interpreters.
};
struct fpuRegisters {
FPRreg fpr[32]; // 32bit floating point registers
u32 fprc[32]; // 32bit floating point control registers
FPRreg ACC; // 32 bit accumulator
u32 ACCflag; // an internal accumulator overflow flag
};
struct tlbs
{
u32 PageMask,EntryHi;
u32 EntryLo0,EntryLo1;
u32 Mask, nMask;
u32 G;
u32 ASID;
u32 VPN2;
u32 PFN0;
u32 PFN1;
u32 S;
};
#ifndef _PC_
/*#define _i64(x) (s64)x
#define _u64(x) (u64)x
#define _i32(x) (s32)x
#define _u32(x) (u32)x
#define _i16(x) (s16)x
#define _u16(x) (u16)x
#define _i8(x) (s8)x
#define _u8(x) (u8)x*/
////////////////////////////////////////////////////////////////////
// R5900 Instruction Macros
#define _PC_ cpuRegs.pc // The next PC to be executed - only used in this header and R3000A.h
#define _Funct_ ((cpuRegs.code ) & 0x3F) // The funct part of the instruction register
#define _Rd_ ((cpuRegs.code >> 11) & 0x1F) // The rd part of the instruction register
#define _Rt_ ((cpuRegs.code >> 16) & 0x1F) // The rt part of the instruction register
#define _Rs_ ((cpuRegs.code >> 21) & 0x1F) // The rs part of the instruction register
#define _Sa_ ((cpuRegs.code >> 6) & 0x1F) // The sa part of the instruction register
#define _Im_ ((u16)cpuRegs.code) // The immediate part of the instruction register
#define _Target_ (cpuRegs.code & 0x03ffffff) // The target part of the instruction register
#define _Imm_ ((s16)cpuRegs.code) // sign-extended immediate
#define _ImmU_ (cpuRegs.code&0xffff) // zero-extended immediate
#define _ImmSB_ (cpuRegs.code&0x8000) // gets the sign-bit of the immediate value
#define _Opcode_ (cpuRegs.code >> 26 )
#define _JumpTarget_ ((_Target_ << 2) + (_PC_ & 0xf0000000)) // Calculates the target during a jump instruction
#define _BranchTarget_ (((s32)(s16)_Im_ * 4) + _PC_) // Calculates the target during a branch instruction
#define _TrapCode_ ((u16)cpuRegs.code >> 6) // error code for non-immediate trap instructions.
#define _SetLink(x) (cpuRegs.GPR.r[x].UD[0] = _PC_ + 4) // Sets the return address in the link register
#endif
extern __aligned16 cpuRegisters cpuRegs;
extern __aligned16 fpuRegisters fpuRegs;
extern __aligned16 tlbs tlb[48];
extern u32 g_nextBranchCycle;
extern bool eeEventTestIsActive;
extern u32 s_iLastCOP0Cycle;
extern u32 s_iLastPERFCycle[2];
void intSetBranch();
// This is a special form of the interpreter's doBranch that is run from various
// parts of the Recs (namely COP0's branch codes and stuff).
void __fastcall intDoBranch(u32 target);
////////////////////////////////////////////////////////////////////
// R5900 Public Interface / API
//
// [TODO] : This is on the list to get converted to a proper C++ class. I'm putting it
// off until I get my new IOPint and IOPrec re-merged. --air
//
struct R5900cpu
{
// Memory allocation function, for allocating virtual memory spaces needed by
// the emulator. (ints/recs are free to allocate additional memory while running
// code, however any virtual mapped memory should always be allocated as soon
// as possible, to claim the memory before some plugin does..)
//
// Thread Affinity:
// Can be called from any thread. Execute status must be suspended or stopped
// to prevent multi-thread race conditions.
//
// Notable Exception Throws:
// OutOfMemory - Not enough memory, or the memory areas required were already
// reserved.
//
void (*Allocate)();
// Deallocates ram allocated by Allocate and/or by runtime code execution.
//
// Thread Affinity:
// Can be called from any thread. Execute status must be suspended or stopped
// to prevent multi-thread race conditions.
//
// Exception Throws: None. This function is a destructor, and should not throw.
//
void (*Shutdown)();
// Initializes / Resets code execution states. Typically implementation is only
// needed for recompilers, as interpreters have no internal execution states and
// rely on the CPU/VM states almost entirely.
//
// Thread Affinity:
// Can be called from any thread. Execute status must be suspended or stopped
// to prevent multi-thread race conditions.
//
// Exception Throws: Emulator-defined. Common exception types to look for:
// OutOfMemory, Stream Exceptions
//
void (*Reset)();
// Steps a single instruction. Meant to be used by debuggers. Is currently unused
// and unimplemented. Future note: recompiler "step" should *always* fall back
// on interpreters.
//
// Exception Throws: [TODO] (possible execution-related throws to be added)
//
void (*Step)();
// Executes code until a break is signaled. Execution can be paused or suspended
// via thread-style signals that are handled by CheckExecutionState callbacks.
// Execution Breakages are handled the same way, where-by a signal causes the Execute
// call to return at the nearest state check (typically handled internally using
// either C++ exceptions or setjmp/longjmp).
//
// Exception Throws: [TODO] (possible execution-related throws to be added)
//
void (*Execute)();
// This function performs a "hackish" execution of the BIOS stub, which initializes
// EE memory and hardware. It forcefully breaks execution when the stub is finished,
// prior to the PS2 logos being displayed. This allows us to "shortcut" right into
// a game without having to wait through the logos or endure game/bios localization
// checks.
//
// Use of this function must be followed by the proper injection of the elf header's
// code execution entry point into cpuRegs.pc. Failure to modify cpuRegs.pc will
// result in the bios continuing its normal unimpeded splash screen execution.
//
// Exception Throws: [TODO] (possible execution-related throws to be added)
//
void (*ExecuteBiosStub)();
// Checks for execution suspension or cancellation. In pthreads terms this provides
// a "cancellation point." Execution state checks are typically performed at Vsyncs
// by the generic VM event handlers in R5900.cpp/Counters.cpp (applies to both recs
// and ints).
//
// Implementation note: Because of the nuances of recompiled code execution, setjmp
// may be used in place of thread cancellation or C++ exceptions (non-SEH exceptions
// cannot unwind through the recompiled code stackframes).
//
// Thread Affinity:
// Must be called on the same thread as Execute only.
//
// Exception Throws:
// May throw threading/Pthreads cancellations if the compiler supports SEH.
// ThreadTimedOut - For canceling VM execution in response to MTGS deadlock. (if the
// core emulator does not support multithreaded GS then this will not be a throw
// exception).
//
void (*CheckExecutionState)();
// Manual recompiled code cache clear; typically useful to recompilers only. Size is
// in MIPS words (32 bits). Dev note: this callback is nearly obsolete, and might be
// better off replaced with some generic API callbacks from VTLB block protection.
// Also: the calls from COP0's TLB remap code should be replaced with full recompiler
// resets, since TLB remaps affect more than just the code they contain (code that
// may reference the remaped blocks via memory loads/stores, for example).
//
// Thread Affinity Rule:
// Can be called from any thread (namely for being called from debugging threads)
//
// Exception Throws: [TODO] Emulator defined? (probably shouldn't throw, probably
// doesn't matter if we're stripping it out soon. ;)
//
void (*Clear)(u32 Addr, u32 Size);
};
extern R5900cpu *Cpu;
extern R5900cpu intCpu;
extern R5900cpu recCpu;
extern void cpuInit();
extern void cpuReset(); // can throw Exception::FileNotFound.
extern void cpuException(u32 code, u32 bd);
extern void cpuTlbMissR(u32 addr, u32 bd);
extern void cpuTlbMissW(u32 addr, u32 bd);
extern void cpuTestHwInts();
extern void cpuSetNextBranch( u32 startCycle, s32 delta );
extern void cpuSetNextBranchDelta( s32 delta );
extern int cpuTestCycle( u32 startCycle, s32 delta );
extern void cpuSetBranch();
extern void _cpuBranchTest_Shared(); // for internal use by the Dynarecs and Ints inside R5900:
extern void cpuTestINTCInts();
extern void cpuTestDMACInts();
extern void cpuTestTIMRInts();
////////////////////////////////////////////////////////////////////
// Exception Codes
#define EXC_CODE(x) ((x)<<2)
#define EXC_CODE_Int EXC_CODE(0)
#define EXC_CODE_Mod EXC_CODE(1) /* TLB Modification exception */
#define EXC_CODE_TLBL EXC_CODE(2) /* TLB Miss exception (load or instruction fetch) */
#define EXC_CODE_TLBS EXC_CODE(3) /* TLB Miss exception (store) */
#define EXC_CODE_AdEL EXC_CODE(4)
#define EXC_CODE_AdES EXC_CODE(5)
#define EXC_CODE_IBE EXC_CODE(6)
#define EXC_CODE_DBE EXC_CODE(7)
#define EXC_CODE_Sys EXC_CODE(8)
#define EXC_CODE_Bp EXC_CODE(9)
#define EXC_CODE_Ri EXC_CODE(10)
#define EXC_CODE_CpU EXC_CODE(11)
#define EXC_CODE_Ov EXC_CODE(12)
#define EXC_CODE_Tr EXC_CODE(13)
#define EXC_CODE_FPE EXC_CODE(15)
#define EXC_CODE_WATCH EXC_CODE(23)
#define EXC_CODE__MASK 0x0000007c
#define EXC_CODE__SHIFT 2