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/HLE/HLE.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 <cstdio>
21
#include <cstdarg>
22
#include <type_traits>
23
24
#include "Common/CommonTypes.h"
25
#include "Common/Log.h"
26
#include "Core/MIPS/MIPS.h"
27
28
class PointerWrap;
29
class PSPAction;
30
typedef void (* HLEFunc)();
31
32
enum {
33
// The low 8 bits are a value, indicating special jit handling.
34
// Currently there are none.
35
36
// The remaining 24 bits are flags.
37
// Don't allow the call within an interrupt. Not yet implemented.
38
HLE_NOT_IN_INTERRUPT = 1 << 8,
39
// Don't allow the call if dispatch or interrupts are disabled.
40
HLE_NOT_DISPATCH_SUSPENDED = 1 << 9,
41
// Indicates the call should write zeros to the stack (stackBytesToClear in the table.)
42
HLE_CLEAR_STACK_BYTES = 1 << 10,
43
// Indicates that this call operates in kernel mode.
44
HLE_KERNEL_SYSCALL = 1 << 11,
45
};
46
47
struct HLEFunction
48
{
49
// This is the id, or nid, of the function (which is how it's linked.)
50
// Generally, the truncated least significant 32 bits of a SHA-1 hash.
51
u32 ID;
52
// A pointer to the C++ handler; see FunctionWrappers.h for helpers.
53
HLEFunc func;
54
// Name of the function. Often the same as func, this should match the PSP func's name and hash.
55
const char *name;
56
// The return type, see argmask for the possible values.
57
// An additional value is possible - 'v', which means void (no return type.)
58
char retmask;
59
// The argument types, in order. Use the following characters:
60
// - x: for u32 (shown as hex in log)
61
// - i: for int/s32
62
// - f: for float
63
// - X: uppercase, for u64
64
// - I: uppercase, for s64
65
// - F: uppercase, for double
66
// - s: a string pointer (const char *, utf-8)
67
// - p: a pointer (e.g. u32 *, shown with value in log)
68
const char *argmask;
69
// Flags (see above, e.g. HLE_NOT_IN_INTERRUPT.)
70
u32 flags;
71
// See HLE_CLEAR_STACK_BYTES.
72
u32 stackBytesToClear;
73
};
74
75
struct HLEModule
76
{
77
const char *name;
78
int numFunctions;
79
const HLEFunction *funcTable;
80
};
81
82
typedef char SyscallModuleName[32];
83
84
struct Syscall
85
{
86
SyscallModuleName moduleName;
87
u32 symAddr;
88
u32 nid;
89
};
90
91
#define PARAM(n) currentMIPS->r[MIPS_REG_A0 + n]
92
#define PARAM64(n) (currentMIPS->r[MIPS_REG_A0 + n] | ((u64)currentMIPS->r[MIPS_REG_A0 + n + 1] << 32))
93
#define PARAMF(n) currentMIPS->f[12 + n]
94
#define RETURN(n) currentMIPS->r[MIPS_REG_V0] = n
95
#define RETURN64(n) {u64 RETURN64_tmp = n; currentMIPS->r[MIPS_REG_V0] = RETURN64_tmp & 0xFFFFFFFF; currentMIPS->r[MIPS_REG_V1] = RETURN64_tmp >> 32;}
96
#define RETURNF(fl) currentMIPS->f[0] = fl
97
98
const char *GetFuncName(const char *module, u32 nib);
99
const char *GetFuncName(int module, int func);
100
const HLEFunction *GetFunc(const char *module, u32 nib);
101
int GetFuncIndex(int moduleIndex, u32 nib);
102
int GetModuleIndex(const char *modulename);
103
104
void RegisterModule(const char *name, int numFunctions, const HLEFunction *funcTable);
105
106
// Run the current thread's callbacks after the syscall finishes.
107
void hleCheckCurrentCallbacks();
108
// Reschedule after the syscall finishes.
109
void hleReSchedule(const char *reason);
110
// Reschedule and go into a callback processing state after the syscall finishes.
111
void hleReSchedule(bool callbacks, const char *reason);
112
// Run interrupts after the syscall finishes.
113
void hleRunInterrupts();
114
// Pause emulation after the syscall finishes.
115
void hleDebugBreak();
116
// Don't set temp regs to 0xDEADBEEF.
117
void hleSkipDeadbeef();
118
// Set time spent in debugger (for more useful debug stats while debugging.)
119
void hleSetSteppingTime(double t);
120
// Set time spent in realtime sync.
121
void hleSetFlipTime(double t);
122
// Check if the current syscall context is kernel.
123
bool hleIsKernelMode();
124
// Enqueue a MIPS function to be called after this HLE call finishes.
125
void hleEnqueueCall(u32 func, int argc, const u32 *argv, PSPAction *afterAction = nullptr);
126
127
// Delays the result for usec microseconds, allowing other threads to run during this time.
128
u32 hleDelayResult(u32 result, const char *reason, int usec);
129
u64 hleDelayResult(u64 result, const char *reason, int usec);
130
void hleEatCycles(int cycles);
131
void hleEatMicro(int usec);
132
133
inline int hleDelayResult(int result, const char *reason, int usec) {
134
return hleDelayResult((u32) result, reason, usec);
135
}
136
137
inline s64 hleDelayResult(s64 result, const char *reason, int usec) {
138
return hleDelayResult((u64) result, reason, usec);
139
}
140
141
void HLEInit();
142
void HLEDoState(PointerWrap &p);
143
void HLEShutdown();
144
u32 GetNibByName(const char *module, const char *function);
145
u32 GetSyscallOp(const char *module, u32 nib);
146
bool FuncImportIsSyscall(const char *module, u32 nib);
147
bool WriteSyscall(const char *module, u32 nib, u32 address);
148
void CallSyscall(MIPSOpcode op);
149
void WriteFuncStub(u32 stubAddr, u32 symAddr);
150
void WriteFuncMissingStub(u32 stubAddr, u32 nid);
151
152
void HLEReturnFromMipsCall();
153
154
const HLEFunction *GetSyscallFuncPointer(MIPSOpcode op);
155
// For jit, takes arg: const HLEFunction *
156
void *GetQuickSyscallFunc(MIPSOpcode op);
157
158
void hleDoLogInternal(Log t, LogLevel level, u64 res, const char *file, int line, const char *reportTag, char retmask, const char *reason, const char *formatted_reason);
159
160
template <typename T>
161
T hleDoLog(Log t, LogLevel level, T res, const char *file, int line, const char *reportTag, char retmask, const char *reason, ...) {
162
if ((int)level > MAX_LOGLEVEL || !GenericLogEnabled(level, t)) {
163
return res;
164
}
165
166
char formatted_reason[4096] = {0};
167
if (reason != nullptr) {
168
va_list args;
169
va_start(args, reason);
170
formatted_reason[0] = ':';
171
formatted_reason[1] = ' ';
172
vsnprintf(formatted_reason + 2, sizeof(formatted_reason) - 3, reason, args);
173
formatted_reason[sizeof(formatted_reason) - 1] = '\0';
174
va_end(args);
175
}
176
177
u64 fmtRes = res;
178
if (std::is_floating_point<T>::value) {
179
// We reinterpret as the bits for now, so we can have a common helper.
180
fmtRes = *(const u32 *)&res;
181
} else if (std::is_signed<T>::value) {
182
fmtRes = (s64)res;
183
}
184
hleDoLogInternal(t, level, fmtRes, file, line, reportTag, retmask, reason, formatted_reason);
185
return res;
186
}
187
188
template <typename T>
189
T hleDoLog(Log t, LogLevel level, T res, const char *file, int line, const char *reportTag, char retmask) {
190
if (((int)level > MAX_LOGLEVEL || !GenericLogEnabled(level, t)) && !reportTag) {
191
return res;
192
}
193
194
u64 fmtRes = res;
195
if (std::is_floating_point<T>::value) {
196
// We reinterpret as the bits for now, so we can have a common helper.
197
fmtRes = *(const u32 *)&res;
198
} else if (std::is_signed<T>::value) {
199
fmtRes = (s64)res;
200
}
201
hleDoLogInternal(t, level, fmtRes, file, line, reportTag, retmask, nullptr, "");
202
return res;
203
}
204
205
// This is just a quick way to force logging to be more visible for one file.
206
#ifdef HLE_LOG_FORCE
207
#define HLE_LOG_LDEBUG LNOTICE
208
#define HLE_LOG_LVERBOSE LDEBUG
209
210
#undef DEBUG_LOG
211
#define DEBUG_LOG NOTICE_LOG
212
#undef VERBOSE_LOG
213
#define VERBOSE_LOG DEBUG_LOG
214
#else
215
#define HLE_LOG_LDEBUG LDEBUG
216
#define HLE_LOG_LVERBOSE LVERBOSE
217
#endif
218
219
#define hleLogHelper(t, level, res, retmask, ...) hleDoLog(t, LogLevel::level, res, __FILE__, __LINE__, nullptr, retmask, ##__VA_ARGS__)
220
#define hleLogError(t, res, ...) hleLogHelper(t, LERROR, res, 'x', ##__VA_ARGS__)
221
#define hleLogWarning(t, res, ...) hleLogHelper(t, LWARNING, res, 'x', ##__VA_ARGS__)
222
#define hleLogDebug(t, res, ...) hleLogHelper(t, HLE_LOG_LDEBUG, res, 'x', ##__VA_ARGS__)
223
#define hleLogVerbose(t, res, ...) hleLogHelper(t, HLE_LOG_LVERBOSE, res, 'x', ##__VA_ARGS__)
224
#define hleLogSuccessX(t, res, ...) hleLogHelper(t, HLE_LOG_LDEBUG, res, 'x', ##__VA_ARGS__)
225
#define hleLogSuccessI(t, res, ...) hleLogHelper(t, HLE_LOG_LDEBUG, res, 'i', ##__VA_ARGS__)
226
#define hleLogSuccessInfoX(t, res, ...) hleLogHelper(t, LINFO, res, 'x', ##__VA_ARGS__)
227
#define hleLogSuccessInfoI(t, res, ...) hleLogHelper(t, LINFO, res, 'i', ##__VA_ARGS__)
228
#define hleLogSuccessVerboseX(t, res, ...) hleLogHelper(t, HLE_LOG_LVERBOSE, res, 'x', ##__VA_ARGS__)
229
#define hleLogSuccessVerboseI(t, res, ...) hleLogHelper(t, HLE_LOG_LVERBOSE, res, 'i', ##__VA_ARGS__)
230
231
#define hleReportError(t, res, ...) hleDoLog(t, LogLevel::LERROR, res, __FILE__, __LINE__, "", 'x', ##__VA_ARGS__)
232
#define hleReportWarning(t, res, ...) hleDoLog(t, LogLevel::LWARNING, res, __FILE__, __LINE__, "", 'x', ##__VA_ARGS__)
233
#define hleReportDebug(t, res, ...) hleDoLog(t, LogLevel::HLE_LOG_LDEBUG, res, __FILE__, __LINE__, "", 'x', ##__VA_ARGS__)
234
235