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.cpp
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
#include <cmath>
19
#include <limits>
20
#include <mutex>
21
#include <utility>
22
23
#include "Common/Math/math_util.h"
24
25
#include "Common/CommonTypes.h"
26
#include "Common/Serialize/Serializer.h"
27
#include "Common/Serialize/SerializeFuncs.h"
28
#include "Core/ConfigValues.h"
29
#include "Core/MIPS/MIPS.h"
30
#include "Core/MIPS/MIPSInt.h"
31
#include "Core/MIPS/MIPSTables.h"
32
#include "Core/MIPS/MIPSDebugInterface.h"
33
#include "Core/MIPS/MIPSVFPUUtils.h"
34
#include "Core/MIPS/IR/IRJit.h"
35
#include "Core/Reporting.h"
36
#include "Core/System.h"
37
#include "Core/MIPS/JitCommon/JitCommon.h"
38
#include "Core/CoreTiming.h"
39
40
MIPSState mipsr4k;
41
MIPSState *currentMIPS = &mipsr4k;
42
MIPSDebugInterface debugr4k(&mipsr4k);
43
MIPSDebugInterface *currentDebugMIPS = &debugr4k;
44
45
u8 voffset[128];
46
u8 fromvoffset[128];
47
48
#ifndef M_LOG2E
49
#define M_E 2.71828182845904523536f
50
#define M_LOG2E 1.44269504088896340736f
51
#define M_LOG10E 0.434294481903251827651f
52
#define M_LN2 0.693147180559945309417f
53
#define M_LN10 2.30258509299404568402f
54
#undef M_PI
55
#define M_PI 3.14159265358979323846f
56
57
#ifndef M_PI_2
58
#define M_PI_2 1.57079632679489661923f
59
#endif
60
#define M_PI_4 0.785398163397448309616f
61
#define M_1_PI 0.318309886183790671538f
62
#define M_2_PI 0.636619772367581343076f
63
#define M_2_SQRTPI 1.12837916709551257390f
64
#define M_SQRT2 1.41421356237309504880f
65
#define M_SQRT1_2 0.707106781186547524401f
66
#endif
67
68
const float cst_constants[32] = {
69
0,
70
std::numeric_limits<float>::max(), // all these are verified on real PSP
71
sqrtf(2.0f),
72
sqrtf(0.5f),
73
2.0f/sqrtf((float)M_PI),
74
2.0f/(float)M_PI,
75
1.0f/(float)M_PI,
76
(float)M_PI/4,
77
(float)M_PI/2,
78
(float)M_PI,
79
(float)M_E,
80
(float)M_LOG2E,
81
(float)M_LOG10E,
82
(float)M_LN2,
83
(float)M_LN10,
84
2*(float)M_PI,
85
(float)M_PI/6,
86
log10f(2.0f),
87
logf(10.0f)/logf(2.0f),
88
sqrtf(3.0f)/2.0f,
89
};
90
91
MIPSState::MIPSState() {
92
MIPSComp::jit = nullptr;
93
94
// Initialize vorder
95
96
// This reordering of the VFPU registers in RAM means that instead of being like this:
97
98
// 0x00 0x20 0x40 0x60 -> "columns", the most common direction
99
// 0x01 0x21 0x41 0x61
100
// 0x02 0x22 0x42 0x62
101
// 0x03 0x23 0x43 0x63
102
103
// 0x04 0x24 0x44 0x64
104
// 0x06 0x26 0x45 0x65
105
// ....
106
107
// the VPU registers are effectively organized like this:
108
// 0x00 0x01 0x02 0x03
109
// 0x04 0x05 0x06 0x07
110
// 0x08 0x09 0x0a 0x0b
111
// ....
112
113
// This is because the original indices look like this:
114
// 0XXMMMYY where M is the matrix number.
115
116
// We will now map 0YYMMMXX to 0MMMXXYY.
117
118
// Advantages:
119
// * Columns can be flushed and reloaded faster "at once"
120
// * 4x4 Matrices are contiguous in RAM, making them, too, fast-loadable in NEON
121
122
// Disadvantages:
123
// * Extra indirection, can be confusing and slower (interpreter only, however we can often skip the table by rerranging formulas)
124
// * Flushing and reloading row registers is now slower
125
126
int i = 0;
127
for (int m = 0; m < 8; m++) {
128
for (int y = 0; y < 4; y++) {
129
for (int x = 0; x < 4; x++) {
130
voffset[m * 4 + x * 32 + y] = i++;
131
}
132
}
133
}
134
135
// And the inverse.
136
for (int i = 0; i < 128; i++) {
137
fromvoffset[voffset[i]] = i;
138
}
139
140
// Sanity check that things that should be ordered are ordered.
141
static const u8 firstThirtyTwo[] = {
142
0x0, 0x20, 0x40, 0x60,
143
0x1, 0x21, 0x41, 0x61,
144
0x2, 0x22, 0x42, 0x62,
145
0x3, 0x23, 0x43, 0x63,
146
147
0x4, 0x24, 0x44, 0x64,
148
0x5, 0x25, 0x45, 0x65,
149
0x6, 0x26, 0x46, 0x66,
150
0x7, 0x27, 0x47, 0x67,
151
};
152
153
for (int i = 0; i < (int)ARRAY_SIZE(firstThirtyTwo); i++) {
154
if (voffset[firstThirtyTwo[i]] != i) {
155
ERROR_LOG(Log::CPU, "Wrong voffset order! %i: %i should have been %i", firstThirtyTwo[i], voffset[firstThirtyTwo[i]], i);
156
}
157
}
158
}
159
160
MIPSState::~MIPSState() {
161
}
162
163
void MIPSState::Shutdown() {
164
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);
165
MIPSComp::JitInterface *oldjit = MIPSComp::jit;
166
if (oldjit) {
167
MIPSComp::jit = nullptr;
168
delete oldjit;
169
}
170
}
171
172
void MIPSState::Reset() {
173
Shutdown();
174
Init();
175
}
176
177
void MIPSState::Init() {
178
memset(r, 0, sizeof(r));
179
memset(f, 0, sizeof(f));
180
memset(v, 0, sizeof(v));
181
memset(vfpuCtrl, 0, sizeof(vfpuCtrl));
182
183
vfpuCtrl[VFPU_CTRL_SPREFIX] = 0xe4; //passthru
184
vfpuCtrl[VFPU_CTRL_TPREFIX] = 0xe4; //passthru
185
vfpuCtrl[VFPU_CTRL_DPREFIX] = 0;
186
vfpuCtrl[VFPU_CTRL_CC] = 0x3f;
187
vfpuCtrl[VFPU_CTRL_INF4] = 0;
188
vfpuCtrl[VFPU_CTRL_REV] = 0x7772ceab;
189
vfpuCtrl[VFPU_CTRL_RCX0] = 0x3f800001;
190
vfpuCtrl[VFPU_CTRL_RCX1] = 0x3f800002;
191
vfpuCtrl[VFPU_CTRL_RCX2] = 0x3f800004;
192
vfpuCtrl[VFPU_CTRL_RCX3] = 0x3f800008;
193
vfpuCtrl[VFPU_CTRL_RCX4] = 0x3f800000;
194
vfpuCtrl[VFPU_CTRL_RCX5] = 0x3f800000;
195
vfpuCtrl[VFPU_CTRL_RCX6] = 0x3f800000;
196
vfpuCtrl[VFPU_CTRL_RCX7] = 0x3f800000;
197
198
pc = 0;
199
hi = 0;
200
lo = 0;
201
fpcond = 0;
202
fcr31 = 0;
203
debugCount = 0;
204
currentMIPS = this;
205
inDelaySlot = false;
206
llBit = 0;
207
nextPC = 0;
208
downcount = 0;
209
210
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);
211
if (PSP_CoreParameter().cpuCore == CPUCore::JIT || PSP_CoreParameter().cpuCore == CPUCore::JIT_IR) {
212
MIPSComp::jit = MIPSComp::CreateNativeJit(this, PSP_CoreParameter().cpuCore == CPUCore::JIT_IR);
213
} else if (PSP_CoreParameter().cpuCore == CPUCore::IR_INTERPRETER) {
214
MIPSComp::jit = new MIPSComp::IRJit(this, false);
215
} else {
216
MIPSComp::jit = nullptr;
217
}
218
}
219
220
bool MIPSState::HasDefaultPrefix() const {
221
return vfpuCtrl[VFPU_CTRL_SPREFIX] == 0xe4 && vfpuCtrl[VFPU_CTRL_TPREFIX] == 0xe4 && vfpuCtrl[VFPU_CTRL_DPREFIX] == 0;
222
}
223
224
void MIPSState::UpdateCore(CPUCore desired) {
225
if (PSP_CoreParameter().cpuCore == desired) {
226
return;
227
}
228
229
PSP_CoreParameter().cpuCore = desired;
230
MIPSComp::JitInterface *oldjit = MIPSComp::jit;
231
MIPSComp::JitInterface *newjit = nullptr;
232
233
switch (PSP_CoreParameter().cpuCore) {
234
case CPUCore::JIT:
235
case CPUCore::JIT_IR:
236
INFO_LOG(Log::CPU, "Switching to JIT%s", PSP_CoreParameter().cpuCore == CPUCore::JIT_IR ? " IR" : "");
237
if (oldjit) {
238
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);
239
MIPSComp::jit = nullptr;
240
delete oldjit;
241
}
242
newjit = MIPSComp::CreateNativeJit(this, PSP_CoreParameter().cpuCore == CPUCore::JIT_IR);
243
break;
244
245
case CPUCore::IR_INTERPRETER:
246
INFO_LOG(Log::CPU, "Switching to IR interpreter");
247
if (oldjit) {
248
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);
249
MIPSComp::jit = nullptr;
250
delete oldjit;
251
}
252
newjit = new MIPSComp::IRJit(this, false);
253
break;
254
255
case CPUCore::INTERPRETER:
256
INFO_LOG(Log::CPU, "Switching to interpreter");
257
if (oldjit) {
258
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);
259
MIPSComp::jit = nullptr;
260
delete oldjit;
261
}
262
break;
263
}
264
265
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);
266
MIPSComp::jit = newjit;
267
}
268
269
void MIPSState::DoState(PointerWrap &p) {
270
auto s = p.Section("MIPSState", 1, 4);
271
if (!s)
272
return;
273
274
// Reset the jit if we're loading.
275
if (p.mode == p.MODE_READ)
276
Reset();
277
// Assume we're not saving state during a CPU core reset, so no lock.
278
if (MIPSComp::jit)
279
MIPSComp::jit->DoState(p);
280
else
281
MIPSComp::DoDummyJitState(p);
282
283
DoArray(p, r, sizeof(r) / sizeof(r[0]));
284
DoArray(p, f, sizeof(f) / sizeof(f[0]));
285
if (s <= 2) {
286
float vtemp[128];
287
DoArray(p, vtemp, sizeof(v) / sizeof(v[0]));
288
for (int i = 0; i < 128; i++) {
289
v[voffset[i]] = vtemp[i];
290
}
291
} else {
292
DoArray(p, v, sizeof(v) / sizeof(v[0]));
293
}
294
DoArray(p, vfpuCtrl, sizeof(vfpuCtrl) / sizeof(vfpuCtrl[0]));
295
Do(p, pc);
296
Do(p, nextPC);
297
Do(p, downcount);
298
// Reversed, but we can just leave it that way.
299
Do(p, hi);
300
Do(p, lo);
301
Do(p, fpcond);
302
if (s <= 1) {
303
u32 fcr0_unused = 0;
304
Do(p, fcr0_unused);
305
}
306
Do(p, fcr31);
307
if (s <= 3) {
308
uint32_t dummy;
309
Do(p, dummy); // rng.m_w
310
Do(p, dummy); // rng.m_z
311
}
312
313
Do(p, inDelaySlot);
314
Do(p, llBit);
315
Do(p, debugCount);
316
317
if (p.mode == p.MODE_READ && MIPSComp::jit) {
318
// Now that we've loaded fcr31, update any jit state associated.
319
MIPSComp::jit->UpdateFCR31();
320
}
321
}
322
323
void MIPSState::SingleStep() {
324
int cycles = MIPS_SingleStep();
325
currentMIPS->downcount -= cycles;
326
CoreTiming::Advance();
327
}
328
329
// returns 1 if reached ticks limit
330
int MIPSState::RunLoopUntil(u64 globalTicks) {
331
switch (PSP_CoreParameter().cpuCore) {
332
case CPUCore::JIT:
333
case CPUCore::JIT_IR:
334
case CPUCore::IR_INTERPRETER:
335
while (inDelaySlot) {
336
// We must get out of the delay slot before going into jit.
337
SingleStep();
338
}
339
insideJit = true;
340
if (hasPendingClears)
341
ProcessPendingClears();
342
MIPSComp::jit->RunLoopUntil(globalTicks);
343
insideJit = false;
344
break;
345
346
case CPUCore::INTERPRETER:
347
return MIPSInterpret_RunUntil(globalTicks);
348
}
349
return 1;
350
}
351
352
// Kept outside MIPSState to avoid header pollution (MIPS.h doesn't even have vector, and is used widely.)
353
static std::vector<std::pair<u32, int>> pendingClears;
354
355
void MIPSState::ProcessPendingClears() {
356
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);
357
for (auto &p : pendingClears) {
358
if (p.first == 0 && p.second == 0)
359
MIPSComp::jit->ClearCache();
360
else
361
MIPSComp::jit->InvalidateCacheAt(p.first, p.second);
362
}
363
pendingClears.clear();
364
hasPendingClears = false;
365
}
366
367
void MIPSState::InvalidateICache(u32 address, int length) {
368
// Only really applies to jit.
369
// Note that the backend is responsible for ensuring native code can still be returned to.
370
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);
371
if (MIPSComp::jit && length != 0) {
372
MIPSComp::jit->InvalidateCacheAt(address, length);
373
}
374
}
375
376
void MIPSState::ClearJitCache() {
377
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);
378
if (MIPSComp::jit) {
379
if (coreState == CORE_RUNNING || insideJit) {
380
pendingClears.emplace_back(0, 0);
381
hasPendingClears = true;
382
CoreTiming::ForceCheck();
383
} else {
384
MIPSComp::jit->ClearCache();
385
}
386
}
387
}
388
389