1 // Copyright (c) 2012- PPSSPP Project. 2 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU General Public License as published by 5 // the Free Software Foundation, version 2.0 or later versions. 6 7 // This program is distributed in the hope that it will be useful, 8 // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 // GNU General Public License 2.0 for more details. 11 12 // A copy of the GPL 2.0 should have been included with the program. 13 // If not, see http://www.gnu.org/licenses/ 14 15 // Official git repository and contact information can be found at 16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. 17 18 #pragma once 19 20 #include "ppsspp_config.h" 21 22 #include <cstddef> 23 24 #include "Common/Data/Random/Rng.h" 25 #include "Common/Common.h" 26 #include "Common/CommonTypes.h" 27 // #include "Core/CoreParameter.h" 28 #include "Core/Opcode.h" 29 30 class PointerWrap; 31 32 typedef Memory::Opcode MIPSOpcode; 33 34 // Unlike on the PPC, opcode 0 is not unused and thus we have to choose another fake 35 // opcode to represent JIT blocks and other emu hacks. 36 // I've chosen 0x68000000. 37 #define MIPS_EMUHACK_OPCODE 0x68000000 38 #define MIPS_EMUHACK_MASK 0xFC000000 39 #define MIPS_JITBLOCK_MASK 0xFF000000 40 #define MIPS_EMUHACK_VALUE_MASK 0x00FFFFFF 41 42 // There are 2 bits available for sub-opcodes, 0x03000000. 43 #define EMUOP_RUNBLOCK 0 // Runs a JIT block 44 #define EMUOP_RETKERNEL 1 // Returns to the simulated PSP kernel from a thread 45 #define EMUOP_CALL_REPLACEMENT 2 46 47 #define MIPS_IS_EMUHACK(op) (((op) & 0xFC000000) == MIPS_EMUHACK_OPCODE) // masks away the subop 48 #define MIPS_IS_RUNBLOCK(op) (((op) & 0xFF000000) == MIPS_EMUHACK_OPCODE) // masks away the subop 49 #define MIPS_IS_REPLACEMENT(op) (((op) & 0xFF000000) == (MIPS_EMUHACK_OPCODE | (EMUOP_CALL_REPLACEMENT << 24))) // masks away the subop 50 51 #define MIPS_EMUHACK_CALL_REPLACEMENT (MIPS_EMUHACK_OPCODE | (EMUOP_CALL_REPLACEMENT << 24)) 52 53 enum MIPSGPReg { 54 MIPS_REG_ZERO=0, 55 MIPS_REG_COMPILER_SCRATCH=1, 56 57 MIPS_REG_V0=2, 58 MIPS_REG_V1=3, 59 60 MIPS_REG_A0=4, 61 MIPS_REG_A1=5, 62 MIPS_REG_A2=6, 63 MIPS_REG_A3=7, 64 MIPS_REG_A4=8, 65 MIPS_REG_A5=9, 66 67 MIPS_REG_T0=8, //alternate names for A4/A5 68 MIPS_REG_T1=9, 69 MIPS_REG_T2=10, 70 MIPS_REG_T3=11, 71 MIPS_REG_T4=12, 72 MIPS_REG_T5=13, 73 MIPS_REG_T6=14, 74 MIPS_REG_T7=15, 75 76 MIPS_REG_S0=16, 77 MIPS_REG_S1=17, 78 MIPS_REG_S2=18, 79 MIPS_REG_S3=19, 80 MIPS_REG_S4=20, 81 MIPS_REG_S5=21, 82 MIPS_REG_S6=22, 83 MIPS_REG_S7=23, 84 MIPS_REG_T8=24, 85 MIPS_REG_T9=25, 86 MIPS_REG_K0=26, 87 MIPS_REG_K1=27, 88 MIPS_REG_GP=28, 89 MIPS_REG_SP=29, 90 MIPS_REG_FP=30, 91 MIPS_REG_RA=31, 92 93 // Not real regs, just for convenience/jit mapping. 94 // NOTE: These are not the same as the offsets the IR has to use! 95 MIPS_REG_HI = 32, 96 MIPS_REG_LO = 33, 97 MIPS_REG_FPCOND = 34, 98 MIPS_REG_VFPUCC = 35, 99 100 MIPS_REG_INVALID=-1, 101 }; 102 103 enum { 104 VFPU_CTRL_SPREFIX, 105 VFPU_CTRL_TPREFIX, 106 VFPU_CTRL_DPREFIX, 107 VFPU_CTRL_CC, 108 VFPU_CTRL_INF4, 109 VFPU_CTRL_RSV5, 110 VFPU_CTRL_RSV6, 111 VFPU_CTRL_REV, 112 VFPU_CTRL_RCX0, 113 VFPU_CTRL_RCX1, 114 VFPU_CTRL_RCX2, 115 VFPU_CTRL_RCX3, 116 VFPU_CTRL_RCX4, 117 VFPU_CTRL_RCX5, 118 VFPU_CTRL_RCX6, 119 VFPU_CTRL_RCX7, 120 121 VFPU_CTRL_MAX, 122 //unknown.... 123 }; 124 125 enum VCondition 126 { 127 VC_FL, 128 VC_EQ, 129 VC_LT, 130 VC_LE, 131 VC_TR, 132 VC_NE, 133 VC_GE, 134 VC_GT, 135 VC_EZ, 136 VC_EN, 137 VC_EI, 138 VC_ES, 139 VC_NZ, 140 VC_NN, 141 VC_NI, 142 VC_NS 143 }; 144 145 // In memory, we order the VFPU registers differently. 146 // Games use columns a whole lot more than rows, and it would thus be good if columns 147 // were contiguous in memory. Also, matrices aren't but should be. 148 extern u8 voffset[128]; 149 extern u8 fromvoffset[128]; 150 151 enum class CPUCore; 152 153 #if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) 154 155 // Note that CTXREG is offset to point at the first floating point register, intentionally. This is so that a byte offset 156 // can reach both GPR and FPR regs. 157 #define MIPSSTATE_VAR(x) MDisp(X64JitConstants::CTXREG, \ 158 (int)(offsetof(MIPSState, x) - offsetof(MIPSState, f[0]))) 159 160 // Workaround for compilers that don't like dynamic indexing in offsetof 161 #define MIPSSTATE_VAR_ELEM32(x, i) MDisp(X64JitConstants::CTXREG, \ 162 (int)(offsetof(MIPSState, x) - offsetof(MIPSState, f[0]) + (i) * 4)) 163 164 // 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): 165 // #define MIPSSTATE_VAR(x) M(&mips_->x) 166 167 #endif 168 169 enum { 170 NUM_X86_FPU_TEMPS = 16, 171 }; 172 173 class MIPSState 174 { 175 public: 176 MIPSState(); 177 ~MIPSState(); 178 179 void Init(); 180 void Shutdown(); 181 void Reset(); 182 void UpdateCore(CPUCore desired); 183 184 void DoState(PointerWrap &p); 185 186 // MUST start with r and be followed by f, v, and t! 187 u32 r[32]; 188 union { 189 float f[32]; 190 u32 fi[32]; 191 int fs[32]; 192 }; 193 union { 194 float v[128]; 195 u32 vi[128]; 196 }; 197 198 // Register-allocated JIT Temps don't get flushed so we don't reserve space for them. 199 // However, the IR interpreter needs some temps that can stick around between ops. 200 // Can be indexed through r[] using indices 192+. 201 u32 t[16]; //192 202 203 // If vfpuCtrl (prefixes) get mysterious values, check the VFPU regcache code. 204 u32 vfpuCtrl[16]; // 208 205 206 float vt[16]; //224 TODO: VFPU temp 207 208 // ARM64 wants lo/hi to be aligned to 64 bits from the base of this struct. 209 u32 padLoHi; // 240 210 211 union { 212 struct { 213 u32 pc; //241 214 215 u32 lo; //242 216 u32 hi; //243 217 218 u32 fcr31; //244 fpu control register 219 u32 fpcond; //245 cache the cond flag of fcr31 (& 1 << 23) 220 }; 221 u32 other[6]; 222 }; 223 224 u32 nextPC; 225 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. 226 227 bool inDelaySlot; 228 int llBit; // ll/sc 229 u32 temp; // can be used to save temporaries during calculations when we need more than R0 and R1 230 u32 mxcsrTemp; 231 // Temporary used around delay slots and similar. 232 u64 saved_flags; 233 234 GMRng rng; // VFPU hardware random number generator. Probably not the right type. 235 236 // Debug stuff 237 u32 debugCount; // can be used to count basic blocks before crashes, etc. 238 239 // Temps needed for JitBranch.cpp experiments 240 u32 intBranchExit; 241 u32 jitBranchExit; 242 243 u32 savedPC; 244 245 alignas(16) u32 vcmpResult[4]; 246 247 float sincostemp[2]; 248 249 static const u32 FCR0_VALUE = 0x00003351; 250 251 #if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) 252 // FPU TEMP0, etc. are swapped in here if necessary (e.g. on x86.) 253 float tempValues[NUM_X86_FPU_TEMPS]; 254 #endif 255 VfpuWriteMask()256 u8 VfpuWriteMask() const { 257 return (vfpuCtrl[VFPU_CTRL_DPREFIX] >> 8) & 0xF; 258 } VfpuWriteMask(int i)259 bool VfpuWriteMask(int i) const { 260 return (vfpuCtrl[VFPU_CTRL_DPREFIX] >> (8 + i)) & 1; 261 } 262 263 bool HasDefaultPrefix() const; 264 265 void SingleStep(); 266 int RunLoopUntil(u64 globalTicks); 267 // To clear jit caches, etc. 268 void InvalidateICache(u32 address, int length = 4); 269 270 void ClearJitCache(); 271 }; 272 273 274 class MIPSDebugInterface; 275 276 //The one we are compiling or running currently 277 extern MIPSState *currentMIPS; 278 extern MIPSDebugInterface *currentDebugMIPS; 279 extern MIPSState mipsr4k; 280 281 extern const float cst_constants[32]; 282