Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/MIPS/MIPS.cpp
3186 views
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
24
#include "Common/CommonTypes.h"
25
#include "Common/Serialize/Serializer.h"
26
#include "Common/Serialize/SerializeFuncs.h"
27
#include "Core/ConfigValues.h"
28
#include "Core/MIPS/MIPS.h"
29
#include "Core/MIPS/MIPSInt.h"
30
#include "Core/MIPS/MIPSTables.h"
31
#include "Core/MIPS/MIPSDebugInterface.h"
32
#include "Core/MIPS/MIPSVFPUUtils.h"
33
#include "Core/MIPS/IR/IRJit.h"
34
#include "Core/Reporting.h"
35
#include "Core/Core.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
memset(vcmpResult, 0, sizeof(vcmpResult));
211
212
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);
213
if (PSP_CoreParameter().cpuCore == CPUCore::JIT || PSP_CoreParameter().cpuCore == CPUCore::JIT_IR) {
214
MIPSComp::jit = MIPSComp::CreateNativeJit(this, PSP_CoreParameter().cpuCore == CPUCore::JIT_IR);
215
} else if (PSP_CoreParameter().cpuCore == CPUCore::IR_INTERPRETER) {
216
MIPSComp::jit = new MIPSComp::IRJit(this, false);
217
} else {
218
MIPSComp::jit = nullptr;
219
}
220
}
221
222
bool MIPSState::HasDefaultPrefix() const {
223
return vfpuCtrl[VFPU_CTRL_SPREFIX] == 0xe4 && vfpuCtrl[VFPU_CTRL_TPREFIX] == 0xe4 && vfpuCtrl[VFPU_CTRL_DPREFIX] == 0;
224
}
225
226
void MIPSState::UpdateCore(CPUCore desired) {
227
if (PSP_CoreParameter().cpuCore == desired) {
228
return;
229
}
230
231
IncrementDebugCounter(DebugCounter::CPUCORE_SWITCHES);
232
233
// Get rid of the old JIT first, before switching.
234
{
235
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);
236
if (MIPSComp::jit) {
237
delete MIPSComp::jit;
238
MIPSComp::jit = nullptr;
239
}
240
}
241
242
PSP_CoreParameter().cpuCore = desired;
243
244
MIPSComp::JitInterface *newjit = nullptr;
245
switch (PSP_CoreParameter().cpuCore) {
246
case CPUCore::JIT:
247
case CPUCore::JIT_IR:
248
INFO_LOG(Log::CPU, "Switching to JIT%s", PSP_CoreParameter().cpuCore == CPUCore::JIT_IR ? " IR" : "");
249
newjit = MIPSComp::CreateNativeJit(this, PSP_CoreParameter().cpuCore == CPUCore::JIT_IR);
250
break;
251
252
case CPUCore::IR_INTERPRETER:
253
INFO_LOG(Log::CPU, "Switching to IR interpreter");
254
newjit = new MIPSComp::IRJit(this, false);
255
break;
256
257
case CPUCore::INTERPRETER:
258
INFO_LOG(Log::CPU, "Switching to interpreter");
259
// Leaving newjit as null.
260
break;
261
262
default:
263
WARN_LOG(Log::CPU, "Invalid value for cpuCore, falling back to interpreter");
264
break;
265
}
266
267
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);
268
MIPSComp::jit = newjit;
269
}
270
271
void MIPSState::DoState(PointerWrap &p) {
272
auto s = p.Section("MIPSState", 1, 4);
273
if (!s)
274
return;
275
276
// Reset the jit if we're loading.
277
if (p.mode == p.MODE_READ)
278
Reset();
279
// Assume we're not saving state during a CPU core reset, so no lock.
280
if (MIPSComp::jit)
281
MIPSComp::jit->DoState(p);
282
else
283
MIPSComp::DoDummyJitState(p);
284
285
DoArray(p, r, sizeof(r) / sizeof(r[0]));
286
DoArray(p, f, sizeof(f) / sizeof(f[0]));
287
if (s <= 2) {
288
float vtemp[128];
289
DoArray(p, vtemp, sizeof(v) / sizeof(v[0]));
290
for (int i = 0; i < 128; i++) {
291
v[voffset[i]] = vtemp[i];
292
}
293
} else {
294
DoArray(p, v, sizeof(v) / sizeof(v[0]));
295
}
296
DoArray(p, vfpuCtrl, sizeof(vfpuCtrl) / sizeof(vfpuCtrl[0]));
297
Do(p, pc);
298
Do(p, nextPC);
299
Do(p, downcount);
300
// Reversed, but we can just leave it that way.
301
Do(p, hi);
302
Do(p, lo);
303
Do(p, fpcond);
304
if (s <= 1) {
305
u32 fcr0_unused = 0;
306
Do(p, fcr0_unused);
307
}
308
Do(p, fcr31);
309
if (s <= 3) {
310
uint32_t dummy;
311
Do(p, dummy); // rng.m_w
312
Do(p, dummy); // rng.m_z
313
}
314
315
Do(p, inDelaySlot);
316
Do(p, llBit);
317
Do(p, debugCount);
318
319
if (p.mode == p.MODE_READ && MIPSComp::jit) {
320
// Now that we've loaded fcr31, update any jit state associated.
321
MIPSComp::jit->UpdateFCR31();
322
}
323
}
324
325
void MIPSState::SingleStep() {
326
int cycles = MIPS_SingleStep();
327
currentMIPS->downcount -= cycles;
328
CoreTiming::Advance();
329
}
330
331
// returns 1 if reached ticks limit
332
int MIPSState::RunLoopUntil(u64 globalTicks) {
333
switch (PSP_CoreParameter().cpuCore) {
334
case CPUCore::JIT:
335
case CPUCore::JIT_IR:
336
case CPUCore::IR_INTERPRETER:
337
while (inDelaySlot) {
338
// We must get out of the delay slot before going into jit.
339
// This normally should never take more than one step...
340
SingleStep();
341
}
342
insideJit = true;
343
if (hasPendingClears)
344
ProcessPendingClears();
345
MIPSComp::jit->RunLoopUntil(globalTicks);
346
insideJit = false;
347
break;
348
349
case CPUCore::INTERPRETER:
350
return MIPSInterpret_RunUntil(globalTicks);
351
}
352
return 1;
353
}
354
355
// Kept outside MIPSState to avoid header pollution (MIPS.h doesn't even have vector, and is used widely.)
356
static std::vector<std::pair<u32, int>> pendingClears;
357
358
void MIPSState::ProcessPendingClears() {
359
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);
360
for (auto &p : pendingClears) {
361
if (p.first == 0 && p.second == 0)
362
MIPSComp::jit->ClearCache();
363
else
364
MIPSComp::jit->InvalidateCacheAt(p.first, p.second);
365
}
366
pendingClears.clear();
367
hasPendingClears = false;
368
}
369
370
void MIPSState::InvalidateICache(u32 address, int length) {
371
// Only really applies to jit.
372
// Note that the backend is responsible for ensuring native code can still be returned to.
373
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);
374
if (MIPSComp::jit && length != 0) {
375
MIPSComp::jit->InvalidateCacheAt(address, length);
376
}
377
}
378
379
void MIPSState::ClearJitCache() {
380
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);
381
if (MIPSComp::jit) {
382
if (coreState == CORE_RUNNING_CPU || insideJit) {
383
pendingClears.emplace_back(0, 0);
384
hasPendingClears = true;
385
CoreTiming::ForceCheck();
386
} else {
387
MIPSComp::jit->ClearCache();
388
}
389
}
390
}
391
392