CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

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