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