CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Core/HLE/HLE.h
Views: 1401
// Copyright (c) 2012- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#pragma once1819#include <cstdio>20#include <cstdarg>21#include <type_traits>2223#include "Common/CommonTypes.h"24#include "Common/Log.h"25#include "Core/MIPS/MIPS.h"2627class PointerWrap;28class PSPAction;29typedef void (* HLEFunc)();3031enum {32// The low 8 bits are a value, indicating special jit handling.33// Currently there are none.3435// The remaining 24 bits are flags.36// Don't allow the call within an interrupt. Not yet implemented.37HLE_NOT_IN_INTERRUPT = 1 << 8,38// Don't allow the call if dispatch or interrupts are disabled.39HLE_NOT_DISPATCH_SUSPENDED = 1 << 9,40// Indicates the call should write zeros to the stack (stackBytesToClear in the table.)41HLE_CLEAR_STACK_BYTES = 1 << 10,42// Indicates that this call operates in kernel mode.43HLE_KERNEL_SYSCALL = 1 << 11,44};4546struct HLEFunction47{48// This is the id, or nid, of the function (which is how it's linked.)49// Generally, the truncated least significant 32 bits of a SHA-1 hash.50u32 ID;51// A pointer to the C++ handler; see FunctionWrappers.h for helpers.52HLEFunc func;53// Name of the function. Often the same as func, this should match the PSP func's name and hash.54const char *name;55// The return type, see argmask for the possible values.56// An additional value is possible - 'v', which means void (no return type.)57char retmask;58// The argument types, in order. Use the following characters:59// - x: for u32 (shown as hex in log)60// - i: for int/s3261// - f: for float62// - X: uppercase, for u6463// - I: uppercase, for s6464// - F: uppercase, for double65// - s: a string pointer (const char *, utf-8)66// - p: a pointer (e.g. u32 *, shown with value in log)67const char *argmask;68// Flags (see above, e.g. HLE_NOT_IN_INTERRUPT.)69u32 flags;70// See HLE_CLEAR_STACK_BYTES.71u32 stackBytesToClear;72};7374struct HLEModule75{76const char *name;77int numFunctions;78const HLEFunction *funcTable;79};8081typedef char SyscallModuleName[32];8283struct Syscall84{85SyscallModuleName moduleName;86u32 symAddr;87u32 nid;88};8990#define PARAM(n) currentMIPS->r[MIPS_REG_A0 + n]91#define PARAM64(n) (currentMIPS->r[MIPS_REG_A0 + n] | ((u64)currentMIPS->r[MIPS_REG_A0 + n + 1] << 32))92#define PARAMF(n) currentMIPS->f[12 + n]93#define RETURN(n) currentMIPS->r[MIPS_REG_V0] = n94#define RETURN64(n) {u64 RETURN64_tmp = n; currentMIPS->r[MIPS_REG_V0] = RETURN64_tmp & 0xFFFFFFFF; currentMIPS->r[MIPS_REG_V1] = RETURN64_tmp >> 32;}95#define RETURNF(fl) currentMIPS->f[0] = fl9697const char *GetFuncName(const char *module, u32 nib);98const char *GetFuncName(int module, int func);99const HLEFunction *GetFunc(const char *module, u32 nib);100int GetFuncIndex(int moduleIndex, u32 nib);101int GetModuleIndex(const char *modulename);102103void RegisterModule(const char *name, int numFunctions, const HLEFunction *funcTable);104105// Run the current thread's callbacks after the syscall finishes.106void hleCheckCurrentCallbacks();107// Reschedule after the syscall finishes.108void hleReSchedule(const char *reason);109// Reschedule and go into a callback processing state after the syscall finishes.110void hleReSchedule(bool callbacks, const char *reason);111// Run interrupts after the syscall finishes.112void hleRunInterrupts();113// Pause emulation after the syscall finishes.114void hleDebugBreak();115// Don't set temp regs to 0xDEADBEEF.116void hleSkipDeadbeef();117// Set time spent in debugger (for more useful debug stats while debugging.)118void hleSetSteppingTime(double t);119// Set time spent in realtime sync.120void hleSetFlipTime(double t);121// Check if the current syscall context is kernel.122bool hleIsKernelMode();123// Enqueue a MIPS function to be called after this HLE call finishes.124void hleEnqueueCall(u32 func, int argc, const u32 *argv, PSPAction *afterAction = nullptr);125126// Delays the result for usec microseconds, allowing other threads to run during this time.127u32 hleDelayResult(u32 result, const char *reason, int usec);128u64 hleDelayResult(u64 result, const char *reason, int usec);129void hleEatCycles(int cycles);130void hleEatMicro(int usec);131132inline int hleDelayResult(int result, const char *reason, int usec) {133return hleDelayResult((u32) result, reason, usec);134}135136inline s64 hleDelayResult(s64 result, const char *reason, int usec) {137return hleDelayResult((u64) result, reason, usec);138}139140void HLEInit();141void HLEDoState(PointerWrap &p);142void HLEShutdown();143u32 GetNibByName(const char *module, const char *function);144u32 GetSyscallOp(const char *module, u32 nib);145bool FuncImportIsSyscall(const char *module, u32 nib);146bool WriteSyscall(const char *module, u32 nib, u32 address);147void CallSyscall(MIPSOpcode op);148void WriteFuncStub(u32 stubAddr, u32 symAddr);149void WriteFuncMissingStub(u32 stubAddr, u32 nid);150151void HLEReturnFromMipsCall();152153const HLEFunction *GetSyscallFuncPointer(MIPSOpcode op);154// For jit, takes arg: const HLEFunction *155void *GetQuickSyscallFunc(MIPSOpcode op);156157void hleDoLogInternal(Log t, LogLevel level, u64 res, const char *file, int line, const char *reportTag, char retmask, const char *reason, const char *formatted_reason);158159template <typename T>160T hleDoLog(Log t, LogLevel level, T res, const char *file, int line, const char *reportTag, char retmask, const char *reason, ...) {161if ((int)level > MAX_LOGLEVEL || !GenericLogEnabled(level, t)) {162return res;163}164165char formatted_reason[4096] = {0};166if (reason != nullptr) {167va_list args;168va_start(args, reason);169formatted_reason[0] = ':';170formatted_reason[1] = ' ';171vsnprintf(formatted_reason + 2, sizeof(formatted_reason) - 3, reason, args);172formatted_reason[sizeof(formatted_reason) - 1] = '\0';173va_end(args);174}175176u64 fmtRes = res;177if (std::is_floating_point<T>::value) {178// We reinterpret as the bits for now, so we can have a common helper.179fmtRes = *(const u32 *)&res;180} else if (std::is_signed<T>::value) {181fmtRes = (s64)res;182}183hleDoLogInternal(t, level, fmtRes, file, line, reportTag, retmask, reason, formatted_reason);184return res;185}186187template <typename T>188T hleDoLog(Log t, LogLevel level, T res, const char *file, int line, const char *reportTag, char retmask) {189if (((int)level > MAX_LOGLEVEL || !GenericLogEnabled(level, t)) && !reportTag) {190return res;191}192193u64 fmtRes = res;194if (std::is_floating_point<T>::value) {195// We reinterpret as the bits for now, so we can have a common helper.196fmtRes = *(const u32 *)&res;197} else if (std::is_signed<T>::value) {198fmtRes = (s64)res;199}200hleDoLogInternal(t, level, fmtRes, file, line, reportTag, retmask, nullptr, "");201return res;202}203204// This is just a quick way to force logging to be more visible for one file.205#ifdef HLE_LOG_FORCE206#define HLE_LOG_LDEBUG LNOTICE207#define HLE_LOG_LVERBOSE LDEBUG208209#undef DEBUG_LOG210#define DEBUG_LOG NOTICE_LOG211#undef VERBOSE_LOG212#define VERBOSE_LOG DEBUG_LOG213#else214#define HLE_LOG_LDEBUG LDEBUG215#define HLE_LOG_LVERBOSE LVERBOSE216#endif217218#define hleLogHelper(t, level, res, retmask, ...) hleDoLog(t, LogLevel::level, res, __FILE__, __LINE__, nullptr, retmask, ##__VA_ARGS__)219#define hleLogError(t, res, ...) hleLogHelper(t, LERROR, res, 'x', ##__VA_ARGS__)220#define hleLogWarning(t, res, ...) hleLogHelper(t, LWARNING, res, 'x', ##__VA_ARGS__)221#define hleLogDebug(t, res, ...) hleLogHelper(t, HLE_LOG_LDEBUG, res, 'x', ##__VA_ARGS__)222#define hleLogVerbose(t, res, ...) hleLogHelper(t, HLE_LOG_LVERBOSE, res, 'x', ##__VA_ARGS__)223#define hleLogSuccessX(t, res, ...) hleLogHelper(t, HLE_LOG_LDEBUG, res, 'x', ##__VA_ARGS__)224#define hleLogSuccessI(t, res, ...) hleLogHelper(t, HLE_LOG_LDEBUG, res, 'i', ##__VA_ARGS__)225#define hleLogSuccessInfoX(t, res, ...) hleLogHelper(t, LINFO, res, 'x', ##__VA_ARGS__)226#define hleLogSuccessInfoI(t, res, ...) hleLogHelper(t, LINFO, res, 'i', ##__VA_ARGS__)227#define hleLogSuccessVerboseX(t, res, ...) hleLogHelper(t, HLE_LOG_LVERBOSE, res, 'x', ##__VA_ARGS__)228#define hleLogSuccessVerboseI(t, res, ...) hleLogHelper(t, HLE_LOG_LVERBOSE, res, 'i', ##__VA_ARGS__)229230#define hleReportError(t, res, ...) hleDoLog(t, LogLevel::LERROR, res, __FILE__, __LINE__, "", 'x', ##__VA_ARGS__)231#define hleReportWarning(t, res, ...) hleDoLog(t, LogLevel::LWARNING, res, __FILE__, __LINE__, "", 'x', ##__VA_ARGS__)232#define hleReportDebug(t, res, ...) hleDoLog(t, LogLevel::HLE_LOG_LDEBUG, res, __FILE__, __LINE__, "", 'x', ##__VA_ARGS__)233234235