2012-11-01 15:19:01 +00:00
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
2012-11-04 22:01:49 +00:00
// the Free Software Foundation, version 2.0 or later versions.
2012-11-01 15:19:01 +00:00
// This program 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
# pragma once
2019-02-18 13:02:39 +00:00
# include "ppsspp_config.h"
2017-07-05 14:46:47 +00:00
# include <cstddef>
2020-10-01 11:05:04 +00:00
# include "Common/Data/Random/Rng.h"
2017-07-05 13:59:17 +00:00
# include "Common/Common.h"
2013-12-30 09:17:11 +00:00
# include "Common/CommonTypes.h"
2017-03-02 11:36:54 +00:00
// #include "Core/CoreParameter.h"
2014-03-15 09:45:39 +00:00
# include "Core/Opcode.h"
2012-11-01 15:19:01 +00:00
2014-03-15 18:22:19 +00:00
class PointerWrap ;
2013-08-24 21:43:49 +00:00
typedef Memory : : Opcode MIPSOpcode ;
2014-12-12 22:48:48 +00:00
// Unlike on the PPC, opcode 0 is not unused and thus we have to choose another fake
// opcode to represent JIT blocks and other emu hacks.
// I've chosen 0x68000000.
# define MIPS_EMUHACK_OPCODE 0x68000000
# define MIPS_EMUHACK_MASK 0xFC000000
# define MIPS_JITBLOCK_MASK 0xFF000000
# define MIPS_EMUHACK_VALUE_MASK 0x00FFFFFF
// There are 2 bits available for sub-opcodes, 0x03000000.
# define EMUOP_RUNBLOCK 0 // Runs a JIT block
# define EMUOP_RETKERNEL 1 // Returns to the simulated PSP kernel from a thread
# define EMUOP_CALL_REPLACEMENT 2
# define MIPS_IS_EMUHACK(op) (((op) & 0xFC000000) == MIPS_EMUHACK_OPCODE) // masks away the subop
# define MIPS_IS_RUNBLOCK(op) (((op) & 0xFF000000) == MIPS_EMUHACK_OPCODE) // masks away the subop
# define MIPS_IS_REPLACEMENT(op) (((op) & 0xFF000000) == (MIPS_EMUHACK_OPCODE | (EMUOP_CALL_REPLACEMENT << 24))) // masks away the subop
# define MIPS_EMUHACK_CALL_REPLACEMENT (MIPS_EMUHACK_OPCODE | (EMUOP_CALL_REPLACEMENT << 24))
2014-10-09 19:38:25 +00:00
enum MIPSGPReg {
2012-11-01 15:19:01 +00:00
MIPS_REG_ZERO = 0 ,
MIPS_REG_COMPILER_SCRATCH = 1 ,
MIPS_REG_V0 = 2 ,
MIPS_REG_V1 = 3 ,
MIPS_REG_A0 = 4 ,
MIPS_REG_A1 = 5 ,
MIPS_REG_A2 = 6 ,
MIPS_REG_A3 = 7 ,
2014-10-05 12:20:30 +00:00
MIPS_REG_A4 = 8 ,
2012-11-01 15:19:01 +00:00
MIPS_REG_A5 = 9 ,
2015-02-19 10:14:23 +00:00
MIPS_REG_T0 = 8 , //alternate names for A4/A5
MIPS_REG_T1 = 9 ,
2014-10-05 12:20:30 +00:00
MIPS_REG_T2 = 10 ,
MIPS_REG_T3 = 11 ,
2013-11-08 11:30:31 +00:00
MIPS_REG_T4 = 12 ,
MIPS_REG_T5 = 13 ,
MIPS_REG_T6 = 14 ,
MIPS_REG_T7 = 15 ,
2012-11-01 15:19:01 +00:00
MIPS_REG_S0 = 16 ,
MIPS_REG_S1 = 17 ,
MIPS_REG_S2 = 18 ,
MIPS_REG_S3 = 19 ,
MIPS_REG_S4 = 20 ,
MIPS_REG_S5 = 21 ,
MIPS_REG_S6 = 22 ,
MIPS_REG_S7 = 23 ,
2013-11-08 11:30:31 +00:00
MIPS_REG_T8 = 24 ,
MIPS_REG_T9 = 25 ,
2012-11-01 15:19:01 +00:00
MIPS_REG_K0 = 26 ,
MIPS_REG_K1 = 27 ,
MIPS_REG_GP = 28 ,
MIPS_REG_SP = 29 ,
MIPS_REG_FP = 30 ,
MIPS_REG_RA = 31 ,
2013-11-09 02:51:49 +00:00
// Not real regs, just for convenience/jit mapping.
2016-05-09 21:47:56 +00:00
// NOTE: These are not the same as the offsets the IR has to use!
2013-11-09 02:51:49 +00:00
MIPS_REG_HI = 32 ,
MIPS_REG_LO = 33 ,
2013-11-11 15:46:22 +00:00
MIPS_REG_FPCOND = 34 ,
2013-11-12 10:48:38 +00:00
MIPS_REG_VFPUCC = 35 ,
2014-10-09 19:38:25 +00:00
MIPS_REG_INVALID = - 1 ,
2012-11-01 15:19:01 +00:00
} ;
2014-10-09 19:38:25 +00:00
enum {
2012-11-01 15:19:01 +00:00
VFPU_CTRL_SPREFIX ,
VFPU_CTRL_TPREFIX ,
VFPU_CTRL_DPREFIX ,
VFPU_CTRL_CC ,
VFPU_CTRL_INF4 ,
VFPU_CTRL_RSV5 ,
VFPU_CTRL_RSV6 ,
VFPU_CTRL_REV ,
VFPU_CTRL_RCX0 ,
VFPU_CTRL_RCX1 ,
VFPU_CTRL_RCX2 ,
VFPU_CTRL_RCX3 ,
VFPU_CTRL_RCX4 ,
VFPU_CTRL_RCX5 ,
VFPU_CTRL_RCX6 ,
VFPU_CTRL_RCX7 ,
2012-11-22 19:14:24 +00:00
VFPU_CTRL_MAX ,
2012-11-01 15:19:01 +00:00
//unknown....
} ;
2013-07-31 20:29:16 +00:00
enum VCondition
{
VC_FL ,
VC_EQ ,
VC_LT ,
VC_LE ,
VC_TR ,
VC_NE ,
VC_GE ,
VC_GT ,
VC_EZ ,
VC_EN ,
VC_EI ,
VC_ES ,
VC_NZ ,
VC_NN ,
VC_NI ,
VC_NS
} ;
2013-11-27 21:45:17 +00:00
// In memory, we order the VFPU registers differently.
// Games use columns a whole lot more than rows, and it would thus be good if columns
// were contiguous in memory. Also, matrices aren't but should be.
extern u8 voffset [ 128 ] ;
extern u8 fromvoffset [ 128 ] ;
2017-03-02 11:36:54 +00:00
enum class CPUCore ;
2019-02-18 13:02:39 +00:00
# if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)
2017-07-05 11:12:42 +00:00
// Note that CTXREG is offset to point at the first floating point register, intentionally. This is so that a byte offset
// can reach both GPR and FPR regs.
2017-07-07 10:48:17 +00:00
# define MIPSSTATE_VAR(x) MDisp(X64JitConstants::CTXREG, \
( int ) ( offsetof ( MIPSState , x ) - offsetof ( MIPSState , f [ 0 ] ) ) )
// Workaround for compilers that don't like dynamic indexing in offsetof
# define MIPSSTATE_VAR_ELEM32(x, i) MDisp(X64JitConstants::CTXREG, \
2017-07-07 13:46:14 +00:00
( int ) ( offsetof ( MIPSState , x ) - offsetof ( MIPSState , f [ 0 ] ) + ( i ) * 4 ) )
2017-07-05 11:12:42 +00:00
2017-07-05 11:51:27 +00:00
// To get RIP/relative addressing (requires tight memory control so generated code isn't too far from the binary, and a reachable variable called mips):
2021-02-26 04:20:36 +00:00
// #define MIPSSTATE_VAR(x) M(&mips_->x)
2017-07-05 11:51:27 +00:00
2017-07-05 11:12:42 +00:00
# endif
2017-07-05 12:23:52 +00:00
enum {
NUM_X86_FPU_TEMPS = 16 ,
} ;
2013-01-08 13:20:06 +00:00
class MIPSState
2012-11-01 15:19:01 +00:00
{
public :
MIPSState ( ) ;
~ MIPSState ( ) ;
2014-01-28 10:32:54 +00:00
void Init ( ) ;
void Shutdown ( ) ;
2012-11-01 15:19:01 +00:00
void Reset ( ) ;
2014-05-27 06:55:48 +00:00
void UpdateCore ( CPUCore desired ) ;
2014-01-28 10:32:54 +00:00
2012-12-28 04:33:10 +00:00
void DoState ( PointerWrap & p ) ;
2012-11-01 15:19:01 +00:00
2016-05-09 21:47:56 +00:00
// MUST start with r and be followed by f, v, and t!
2012-11-01 15:19:01 +00:00
u32 r [ 32 ] ;
2013-06-11 19:36:59 +00:00
union {
float f [ 32 ] ;
u32 fi [ 32 ] ;
int fs [ 32 ] ;
} ;
union {
float v [ 128 ] ;
u32 vi [ 128 ] ;
} ;
2016-05-09 21:47:56 +00:00
// Register-allocated JIT Temps don't get flushed so we don't reserve space for them.
// However, the IR interpreter needs some temps that can stick around between ops.
2016-05-06 21:45:37 +00:00
// Can be indexed through r[] using indices 192+.
2016-05-09 21:47:56 +00:00
u32 t [ 16 ] ; //192
2016-05-06 21:45:37 +00:00
2013-07-31 08:33:44 +00:00
// If vfpuCtrl (prefixes) get mysterious values, check the VFPU regcache code.
2016-05-09 21:47:56 +00:00
u32 vfpuCtrl [ 16 ] ; // 208
2012-11-01 15:19:01 +00:00
2016-05-10 22:16:07 +00:00
float vt [ 16 ] ; //224 TODO: VFPU temp
2015-07-03 03:23:27 +00:00
// ARM64 wants lo/hi to be aligned to 64 bits from the base of this struct.
2016-05-10 22:16:07 +00:00
u32 padLoHi ; // 240
2015-07-03 03:23:27 +00:00
2013-08-15 08:26:16 +00:00
union {
struct {
2016-05-10 22:16:07 +00:00
u32 pc ; //241
2013-01-11 23:44:18 +00:00
2016-05-10 22:16:07 +00:00
u32 lo ; //242
u32 hi ; //243
2012-11-01 15:19:01 +00:00
2016-05-10 22:16:07 +00:00
u32 fcr31 ; //244 fpu control register
u32 fpcond ; //245 cache the cond flag of fcr31 (& 1 << 23)
2013-08-15 08:26:16 +00:00
} ;
u32 other [ 6 ] ;
} ;
u32 nextPC ;
int downcount ; // This really doesn't belong here, it belongs in CoreTiming. But you gotta do what you gotta do, this needs to be reachable in the ARM JIT.
2012-11-01 15:19:01 +00:00
bool inDelaySlot ;
2012-11-07 16:34:25 +00:00
int llBit ; // ll/sc
2013-11-12 13:42:42 +00:00
u32 temp ; // can be used to save temporaries during calculations when we need more than R0 and R1
2017-07-05 12:10:36 +00:00
u32 mxcsrTemp ;
2017-07-05 10:45:56 +00:00
// Temporary used around delay slots and similar.
u64 saved_flags ;
2013-01-11 23:44:18 +00:00
GMRng rng ; // VFPU hardware random number generator. Probably not the right type.
2012-11-01 15:19:01 +00:00
// Debug stuff
u32 debugCount ; // can be used to count basic blocks before crashes, etc.
2017-07-05 12:19:54 +00:00
// Temps needed for JitBranch.cpp experiments
u32 intBranchExit ;
u32 jitBranchExit ;
2017-07-05 13:06:44 +00:00
u32 savedPC ;
2017-08-30 23:14:51 +00:00
alignas ( 16 ) u32 vcmpResult [ 4 ] ;
2017-07-05 13:59:17 +00:00
2017-07-05 14:44:22 +00:00
float sincostemp [ 2 ] ;
2013-11-14 06:41:25 +00:00
static const u32 FCR0_VALUE = 0x00003351 ;
2019-02-18 13:02:39 +00:00
# if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)
2017-07-05 12:23:52 +00:00
// FPU TEMP0, etc. are swapped in here if necessary (e.g. on x86.)
float tempValues [ NUM_X86_FPU_TEMPS ] ;
# endif
2013-02-15 21:56:38 +00:00
u8 VfpuWriteMask ( ) const {
return ( vfpuCtrl [ VFPU_CTRL_DPREFIX ] > > 8 ) & 0xF ;
}
bool VfpuWriteMask ( int i ) const {
return ( vfpuCtrl [ VFPU_CTRL_DPREFIX ] > > ( 8 + i ) ) & 1 ;
}
2012-11-01 15:19:01 +00:00
2014-06-28 06:21:22 +00:00
bool HasDefaultPrefix ( ) const ;
2012-11-01 15:19:01 +00:00
void SingleStep ( ) ;
2012-11-19 13:16:37 +00:00
int RunLoopUntil ( u64 globalTicks ) ;
2013-09-01 07:32:17 +00:00
// To clear jit caches, etc.
void InvalidateICache ( u32 address , int length = 4 ) ;
2014-12-12 22:48:48 +00:00
void ClearJitCache ( ) ;
2012-11-01 15:19:01 +00:00
} ;
class MIPSDebugInterface ;
//The one we are compiling or running currently
extern MIPSState * currentMIPS ;
extern MIPSDebugInterface * currentDebugMIPS ;
extern MIPSState mipsr4k ;
2013-07-27 20:14:01 +00:00
extern const float cst_constants [ 32 ] ;